geoai-py 0.19.0__tar.gz → 0.20.0__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.
Files changed (79) hide show
  1. {geoai_py-0.19.0 → geoai_py-0.20.0}/PKG-INFO +1 -1
  2. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/__init__.py +1 -1
  3. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/PKG-INFO +1 -1
  4. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/SOURCES.txt +17 -0
  5. {geoai_py-0.19.0 → geoai_py-0.20.0}/pyproject.toml +2 -2
  6. geoai_py-0.20.0/qgis_plugin/README.md +188 -0
  7. geoai_py-0.20.0/qgis_plugin/geoai_plugin/__init__.py +21 -0
  8. geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/__init__.py +13 -0
  9. geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/map_tools.py +172 -0
  10. geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/moondream.py +651 -0
  11. geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/samgeo.py +1438 -0
  12. geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/segmentation.py +1450 -0
  13. geoai_py-0.20.0/qgis_plugin/geoai_plugin/geoai_plugin.py +510 -0
  14. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/about.svg +5 -0
  15. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/gpu.svg +12 -0
  16. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/icon.png +0 -0
  17. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/moondream.svg +6 -0
  18. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/samgeo.png +0 -0
  19. geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/segment.svg +6 -0
  20. geoai_py-0.20.0/qgis_plugin/geoai_plugin/metadata.txt +42 -0
  21. geoai_py-0.20.0/qgis_plugin/install.py +156 -0
  22. geoai_py-0.20.0/qgis_plugin/install.sh +42 -0
  23. {geoai_py-0.19.0 → geoai_py-0.20.0}/.dockerignore +0 -0
  24. {geoai_py-0.19.0 → geoai_py-0.20.0}/.editorconfig +0 -0
  25. {geoai_py-0.19.0 → geoai_py-0.20.0}/.gitignore +0 -0
  26. {geoai_py-0.19.0 → geoai_py-0.20.0}/.pre-commit-config.yaml +0 -0
  27. {geoai_py-0.19.0 → geoai_py-0.20.0}/CITATION.cff +0 -0
  28. {geoai_py-0.19.0 → geoai_py-0.20.0}/Dockerfile +0 -0
  29. {geoai_py-0.19.0 → geoai_py-0.20.0}/LICENSE +0 -0
  30. {geoai_py-0.19.0 → geoai_py-0.20.0}/MANIFEST.in +0 -0
  31. {geoai_py-0.19.0 → geoai_py-0.20.0}/README.md +0 -0
  32. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/__init__.py +0 -0
  33. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/catalog_models.py +0 -0
  34. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/catalog_tools.py +0 -0
  35. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/geo_agents.py +0 -0
  36. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/map_tools.py +0 -0
  37. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/stac_models.py +0 -0
  38. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/stac_tools.py +0 -0
  39. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/change_detection.py +0 -0
  40. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/classify.py +0 -0
  41. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/detectron2.py +0 -0
  42. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/dinov3.py +0 -0
  43. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/download.py +0 -0
  44. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/extract.py +0 -0
  45. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/geoai.py +0 -0
  46. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/hf.py +0 -0
  47. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/landcover_train.py +0 -0
  48. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/landcover_utils.py +0 -0
  49. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/map_widgets.py +0 -0
  50. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/moondream.py +0 -0
  51. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/sam.py +0 -0
  52. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/segment.py +0 -0
  53. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/segmentation.py +0 -0
  54. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/timm_segment.py +0 -0
  55. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/timm_train.py +0 -0
  56. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/__init__.py +0 -0
  57. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/cloudmask.py +0 -0
  58. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/multiclean.py +0 -0
  59. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/sr.py +0 -0
  60. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/train.py +0 -0
  61. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/utils.py +0 -0
  62. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/dependency_links.txt +0 -0
  63. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/entry_points.txt +0 -0
  64. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/requires.txt +0 -0
  65. {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/top_level.txt +0 -0
  66. {geoai_py-0.19.0 → geoai_py-0.20.0}/mkdocs.yml +0 -0
  67. {geoai_py-0.19.0 → geoai_py-0.20.0}/pytest.ini +0 -0
  68. {geoai_py-0.19.0 → geoai_py-0.20.0}/requirements.txt +0 -0
  69. {geoai_py-0.19.0 → geoai_py-0.20.0}/requirements_docs.txt +0 -0
  70. {geoai_py-0.19.0 → geoai_py-0.20.0}/setup.cfg +0 -0
  71. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/__init__.py +0 -0
  72. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/create_test_data.py +0 -0
  73. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_classify.py +0 -0
  74. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_download.py +0 -0
  75. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_extract.py +0 -0
  76. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_fixtures.py +0 -0
  77. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_geoai.py +0 -0
  78. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_segment.py +0 -0
  79. {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoai-py
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: A Python package for using Artificial Intelligence (AI) with geospatial data
5
5
  Author-email: Qiusheng Wu <giswqs@gmail.com>
6
6
  License: MIT License
@@ -2,7 +2,7 @@
2
2
 
3
3
  __author__ = """Qiusheng Wu"""
4
4
  __email__ = "giswqs@gmail.com"
5
- __version__ = "0.19.0"
5
+ __version__ = "0.20.0"
6
6
 
7
7
 
8
8
  import os
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoai-py
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: A Python package for using Artificial Intelligence (AI) with geospatial data
5
5
  Author-email: Qiusheng Wu <giswqs@gmail.com>
6
6
  License: MIT License
@@ -49,6 +49,23 @@ geoai_py.egg-info/dependency_links.txt
49
49
  geoai_py.egg-info/entry_points.txt
50
50
  geoai_py.egg-info/requires.txt
51
51
  geoai_py.egg-info/top_level.txt
52
+ qgis_plugin/README.md
53
+ qgis_plugin/install.py
54
+ qgis_plugin/install.sh
55
+ qgis_plugin/geoai_plugin/__init__.py
56
+ qgis_plugin/geoai_plugin/geoai_plugin.py
57
+ qgis_plugin/geoai_plugin/metadata.txt
58
+ qgis_plugin/geoai_plugin/dialogs/__init__.py
59
+ qgis_plugin/geoai_plugin/dialogs/map_tools.py
60
+ qgis_plugin/geoai_plugin/dialogs/moondream.py
61
+ qgis_plugin/geoai_plugin/dialogs/samgeo.py
62
+ qgis_plugin/geoai_plugin/dialogs/segmentation.py
63
+ qgis_plugin/geoai_plugin/icons/about.svg
64
+ qgis_plugin/geoai_plugin/icons/gpu.svg
65
+ qgis_plugin/geoai_plugin/icons/icon.png
66
+ qgis_plugin/geoai_plugin/icons/moondream.svg
67
+ qgis_plugin/geoai_plugin/icons/samgeo.png
68
+ qgis_plugin/geoai_plugin/icons/segment.svg
52
69
  tests/__init__.py
53
70
  tests/create_test_data.py
54
71
  tests/test_classify.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "geoai-py"
3
- version = "0.19.0"
3
+ version = "0.20.0"
4
4
  dynamic = [
5
5
  "dependencies",
6
6
  ]
@@ -45,7 +45,7 @@ universal = true
45
45
 
46
46
 
47
47
  [tool.bumpversion]
48
- current_version = "0.19.0"
48
+ current_version = "0.20.0"
49
49
  commit = true
50
50
  tag = true
51
51
 
@@ -0,0 +1,188 @@
1
+ # GeoAI Plugin for QGIS
2
+
3
+ A QGIS plugin providing AI-powered geospatial analysis tools from the [geoai](https://github.com/opengeos/geoai) package.
4
+
5
+ ## Features
6
+
7
+ The plugin provides **dockable panels** that can be attached to the left or right side of QGIS.
8
+
9
+ ### Moondream Vision-Language Model Panel
10
+ - **Caption**: Generate descriptions of geospatial imagery (short, normal, or long)
11
+ - **Query**: Ask questions about images using natural language
12
+ - **Detect**: Detect and locate objects with bounding boxes
13
+ - **Point**: Locate specific objects with point markers
14
+
15
+ ### Segmentation Panel (Combined Training & Inference)
16
+ - **Tab 1 - Create Training Data**: Export GeoTIFF tiles from raster and vector data
17
+ - **Tab 2 - Train Models**: Train custom segmentation models (U-Net, DeepLabV3+, FPN, etc.)
18
+ - **Tab 3 - Run Inference**: Apply trained models to new imagery and vectorize results
19
+
20
+ ### SamGeo Panel (Segment Anything Model)
21
+ - **Model Tab**: Load SAM models (SAM1, SAM2, or SAM3) with configurable backend and device settings
22
+ - **Text Tab**: Segment objects using text prompts (e.g., "tree", "building", "road")
23
+ - **Interactive Tab**: Segment using point prompts (foreground/background) or box prompts drawn on the map
24
+ - **Batch Tab**: Process multiple points interactively or from vector files/layers
25
+ - **Output Tab**: Save results as raster (GeoTIFF) or vector (GeoPackage, Shapefile) with optional regularization (orthogonalize polygons, filter by minimum area)
26
+
27
+ ### GPU Memory Management
28
+ - **Clear GPU Memory**: Release GPU memory and clear CUDA cache for all loaded models
29
+
30
+ ## Requirements
31
+
32
+ - QGIS 3.28 or later
33
+ - Python 3.10+
34
+ - PyTorch (with CUDA support for GPU acceleration)
35
+ - geoai-py package
36
+ - samgeo package (for SamGeo panel)
37
+
38
+ ## Installation
39
+
40
+ ### Option 1: Install from Plugin Manager (Recommended)
41
+
42
+ 1. Open QGIS
43
+ 2. Go to `Plugins` → `Manage and Install Plugins...`
44
+ 3. Search for "GeoAI"
45
+ 4. Click "Install Plugin"
46
+
47
+ ### Option 2: Install Using Script (Recommended for Developers)
48
+
49
+ 1. Clone or download this repository
50
+ 2. Run the installation script:
51
+
52
+ **Linux/macOS:**
53
+ ```bash
54
+ python install.py
55
+ ```
56
+
57
+ **Windows:**
58
+ ```cmd
59
+ python install.py
60
+ ```
61
+
62
+ 3. Restart QGIS
63
+ 4. Enable the plugin in `Plugins` → `Manage and Install Plugins...`
64
+
65
+ To remove the plugin:
66
+ ```bash
67
+ python install.py --remove
68
+ ```
69
+
70
+ ### Option 3: Manual Installation
71
+
72
+ 1. Copy the `geoai_plugin` folder to your QGIS plugins directory:
73
+ - **Linux**: `~/.local/share/QGIS/QGIS3/profiles/default/python/plugins/`
74
+ - **Windows**: `C:\Users\<username>\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins\`
75
+ - **macOS**: `~/Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins/`
76
+ 2. Restart QGIS
77
+ 3. Enable the plugin in `Plugins` → `Manage and Install Plugins...`
78
+
79
+ ### Install Dependencies
80
+
81
+ Before using the plugin, install the required Python packages in your QGIS Python environment:
82
+
83
+ ```bash
84
+ conda create -n geo python=3.12
85
+ conda activate geo
86
+ conda install -c conda-forge qgis segment-geospatial geoai
87
+ ```
88
+
89
+ Some SamGeo dependencies are only available on PyPI. Run the following command to install all dependencies:
90
+
91
+ ```bash
92
+ pip install -U "segment-geospatial[samgeo3]"
93
+ ```
94
+
95
+ It is a bit tricky to install SAM 3 on Windows. Run the following commands on Windows to install SamGeo:
96
+
97
+ ```bash
98
+ conda create -n geo python=3.12
99
+ conda activate geo
100
+ conda install pytorch torchvision pytorch-cuda=12.1 -c pytorch -c nvidia
101
+ conda install -c conda-forge qgis segment-geospatial geoai
102
+ pip install "segment-geospatial[samgeo3]" triton-windows
103
+ ```
104
+
105
+ ## Usage
106
+
107
+ ### Moondream Vision-Language Model
108
+
109
+ 1. Click the **Moondream** button in the GeoAI toolbar (or `GeoAI` menu → `Moondream VLM`)
110
+ 2. Load a Moondream model (default: vikhyatk/moondream2)
111
+ 3. Select a raster layer or browse for an image file
112
+ 4. Choose a mode:
113
+ - **Caption**: Generate a description of the image
114
+ - **Query**: Ask a question about the image
115
+ - **Detect**: Detect objects by type (e.g., "building", "car")
116
+ - **Point**: Locate specific objects
117
+ 5. Click "Run Analysis"
118
+ 6. Results are displayed and optionally added to the map
119
+
120
+ ### Segmentation Panel (Create Data, Train, Inference)
121
+
122
+ 1. Click the **Segmentation** button in the GeoAI toolbar (or `GeoAI` menu → `Segmentation`)
123
+ 2. Use the tabs at the top of the panel to switch between:
124
+ - **Create Training Data**: Select input raster and vector labels, configure tile size and stride, and export tiles to a directory.
125
+ - **Train Model**: Select the images and labels directories, choose model architecture (U-Net, DeepLabV3+, etc.), configure training parameters, and start training.
126
+ - **Run Inference**: Select input raster layer or file, specify the trained model path, configure inference parameters, run inference, and optionally vectorize the results.
127
+
128
+ ### SamGeo Panel (Segment Anything Model)
129
+
130
+ 1. Click the **SamGeo** button in the GeoAI toolbar (or `GeoAI` menu → `SamGeo`)
131
+ 2. In the **Model** tab:
132
+ - Select the SAM model version (SamGeo3/SAM3, SamGeo2/SAM2, or SamGeo/SAM1)
133
+ - Configure backend (meta or transformers) and device (auto, cuda, cpu)
134
+ - Click "Load Model" to initialize the model
135
+ - Select a raster layer or browse for an image file and click "Set Image"
136
+ 3. Choose a segmentation method:
137
+ - **Text Tab**: Enter text prompts describing objects to segment (e.g., "tree, building")
138
+ - **Interactive Tab**:
139
+ - Click "Add Foreground Points" or "Add Background Points" and click on the map
140
+ - Or click "Draw Box" and drag a rectangle on the map
141
+ - Click "Segment by Points" or "Segment by Box"
142
+ - **Batch Tab**: Add multiple points interactively or load from a vector file/layer
143
+ 4. In the **Output** tab:
144
+ - Select output format (Raster GeoTIFF, Vector GeoPackage, or Vector Shapefile)
145
+ - For vector output, optionally enable regularization:
146
+ - Check "Regularize polygons (orthogonalize)"
147
+ - Set Epsilon (simplification tolerance) and Min Area (filter small polygons)
148
+ - Click "Save Masks" to export results
149
+
150
+ ### Clear GPU Memory
151
+
152
+ Click the **GPU** button in the GeoAI toolbar to release GPU memory from all loaded models (Moondream, SamGeo, etc.) and clear CUDA cache.
153
+
154
+ ## Supported Model Architectures (Segmentation)
155
+
156
+ - U-Net
157
+ - U-Net++
158
+ - DeepLabV3
159
+ - DeepLabV3+
160
+ - FPN (Feature Pyramid Network)
161
+ - PSPNet
162
+ - LinkNet
163
+ - MANet
164
+ - SegFormer
165
+
166
+ ## Supported Encoders (Segmentation)
167
+
168
+ - ResNet (34, 50, 101, 152)
169
+ - EfficientNet (b0-b4)
170
+ - MobileNetV2
171
+ - VGG (16, 19)
172
+
173
+ ## Supported SAM Models (SamGeo)
174
+
175
+ - **SamGeo3 (SAM3)**: Latest version with text prompts, point prompts, and box prompts
176
+ - **SamGeo2 (SAM2)**: Improved version with better performance
177
+ - **SamGeo (SAM1)**: Original Segment Anything Model
178
+
179
+ ## License
180
+
181
+ MIT License - see [LICENSE](../LICENSE) for details.
182
+
183
+ ## Links
184
+
185
+ - [GeoAI Documentation](https://opengeoai.org)
186
+ - [SamGeo Documentation](https://samgeo.gishub.org)
187
+ - [GitHub Repository](https://github.com/opengeos/geoai)
188
+ - [Report Issues](https://github.com/opengeos/geoai/issues)
@@ -0,0 +1,21 @@
1
+ """
2
+ GeoAI Plugin for QGIS
3
+
4
+ This plugin provides AI-powered geospatial analysis tools including:
5
+ - Moondream vision-language model for image analysis
6
+ - Semantic segmentation model training and inference
7
+ """
8
+
9
+ from .geoai_plugin import GeoAIPlugin
10
+
11
+
12
+ def classFactory(iface):
13
+ """Load GeoAIPlugin class from file geoai_plugin.
14
+
15
+ Args:
16
+ iface: A QGIS interface instance.
17
+
18
+ Returns:
19
+ GeoAIPlugin: The plugin instance.
20
+ """
21
+ return GeoAIPlugin(iface)
@@ -0,0 +1,13 @@
1
+ """
2
+ GeoAI Plugin Dialogs
3
+
4
+ This module contains the dialog and dock widget classes for the GeoAI plugin.
5
+ """
6
+
7
+ from .moondream import MoondreamDockWidget
8
+ from .segmentation import SegmentationDockWidget
9
+
10
+ __all__ = [
11
+ "MoondreamDockWidget",
12
+ "SegmentationDockWidget",
13
+ ]
@@ -0,0 +1,172 @@
1
+ """
2
+ Map tools for interactive segmentation prompts.
3
+ """
4
+
5
+ from qgis.PyQt.QtCore import Qt, pyqtSignal
6
+ from qgis.PyQt.QtGui import QColor
7
+ from qgis.core import QgsPointXY, QgsRectangle, QgsWkbTypes
8
+ from qgis.gui import QgsMapTool, QgsRubberBand, QgsVertexMarker
9
+
10
+
11
+ class PointPromptTool(QgsMapTool):
12
+ """Map tool for adding point prompts."""
13
+
14
+ # Removed unused point_added signal
15
+
16
+ def __init__(self, canvas, plugin, batch_mode=False):
17
+ """Initialize the point prompt tool.
18
+
19
+ Args:
20
+ canvas: The QGIS map canvas.
21
+ plugin: The parent plugin instance.
22
+ batch_mode: If True, adds points to batch list instead of regular list.
23
+ """
24
+ super().__init__(canvas)
25
+ self.canvas = canvas
26
+ self.plugin = plugin
27
+ self.is_foreground = True
28
+ self.batch_mode = batch_mode
29
+ self.markers = []
30
+
31
+ # Set cursor
32
+ self.setCursor(Qt.CrossCursor)
33
+
34
+ def set_foreground(self, foreground):
35
+ """Set whether we're adding foreground or background points."""
36
+ self.is_foreground = foreground
37
+
38
+ def canvasPressEvent(self, event):
39
+ """Handle mouse press event."""
40
+ pass
41
+
42
+ def canvasReleaseEvent(self, event):
43
+ """Handle mouse release event - add a point."""
44
+ if event.button() == Qt.LeftButton:
45
+ point = self.toMapCoordinates(event.pos())
46
+
47
+ # Add visual marker
48
+ marker = QgsVertexMarker(self.canvas)
49
+ marker.setCenter(point)
50
+ # Use blue for batch mode, green/red for regular mode
51
+ if self.batch_mode:
52
+ marker.setColor(QColor(0, 120, 255))
53
+ else:
54
+ marker.setColor(
55
+ QColor(0, 255, 0) if self.is_foreground else QColor(255, 0, 0)
56
+ )
57
+ marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
58
+ marker.setIconSize(10)
59
+ marker.setPenWidth(3)
60
+ self.markers.append(marker)
61
+
62
+ # Add point to plugin
63
+ if self.batch_mode:
64
+ self.plugin.add_batch_point(point)
65
+ else:
66
+ self.plugin.add_point(point, self.is_foreground)
67
+
68
+ elif event.button() == Qt.RightButton:
69
+ # Right-click to finish
70
+ self.deactivate()
71
+ if self.batch_mode:
72
+ self.plugin.batch_add_point_btn.setChecked(False)
73
+ else:
74
+ self.plugin.add_fg_point_btn.setChecked(False)
75
+ self.plugin.add_bg_point_btn.setChecked(False)
76
+
77
+ def clear_markers(self):
78
+ """Clear all markers from the canvas."""
79
+ for marker in self.markers:
80
+ self.canvas.scene().removeItem(marker)
81
+ self.markers = []
82
+
83
+ def deactivate(self):
84
+ """Deactivate the tool."""
85
+ super().deactivate()
86
+
87
+
88
+ class BoxPromptTool(QgsMapTool):
89
+ """Map tool for drawing box prompts."""
90
+
91
+ box_drawn = pyqtSignal(object) # QgsRectangle
92
+
93
+ def __init__(self, canvas, plugin):
94
+ """Initialize the box prompt tool.
95
+
96
+ Args:
97
+ canvas: The QGIS map canvas.
98
+ plugin: The parent plugin instance.
99
+ """
100
+ super().__init__(canvas)
101
+ self.canvas = canvas
102
+ self.plugin = plugin
103
+
104
+ # Rubber band for visual feedback
105
+ self.rubber_band = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)
106
+ self.rubber_band.setColor(QColor(0, 120, 255, 100))
107
+ self.rubber_band.setStrokeColor(QColor(0, 120, 255))
108
+ self.rubber_band.setWidth(2)
109
+
110
+ self.start_point = None
111
+ self.is_drawing = False
112
+
113
+ # Set cursor
114
+ self.setCursor(Qt.CrossCursor)
115
+
116
+ def canvasPressEvent(self, event):
117
+ """Handle mouse press event - start drawing."""
118
+ if event.button() == Qt.LeftButton:
119
+ self.start_point = self.toMapCoordinates(event.pos())
120
+ self.is_drawing = True
121
+ self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
122
+
123
+ def canvasMoveEvent(self, event):
124
+ """Handle mouse move event - update rubber band."""
125
+ if self.is_drawing and self.start_point is not None:
126
+ current_point = self.toMapCoordinates(event.pos())
127
+ self.update_rubber_band(self.start_point, current_point)
128
+
129
+ def canvasReleaseEvent(self, event):
130
+ """Handle mouse release event - finish drawing."""
131
+ if event.button() == Qt.LeftButton and self.is_drawing:
132
+ end_point = self.toMapCoordinates(event.pos())
133
+ self.is_drawing = False
134
+
135
+ # Create rectangle
136
+ rect = QgsRectangle(self.start_point, end_point)
137
+
138
+ # Update rubber band with final position
139
+ self.update_rubber_band(self.start_point, end_point)
140
+
141
+ # Set box in plugin
142
+ self.plugin.set_box(rect)
143
+
144
+ # Deactivate tool
145
+ self.deactivate()
146
+ self.plugin.draw_box_btn.setChecked(False)
147
+
148
+ elif event.button() == Qt.RightButton:
149
+ # Right-click to cancel
150
+ self.is_drawing = False
151
+ self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
152
+ self.deactivate()
153
+ self.plugin.draw_box_btn.setChecked(False)
154
+
155
+ def update_rubber_band(self, start_point, end_point):
156
+ """Update the rubber band rectangle."""
157
+ self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
158
+
159
+ # Create rectangle points
160
+ self.rubber_band.addPoint(QgsPointXY(start_point.x(), start_point.y()), False)
161
+ self.rubber_band.addPoint(QgsPointXY(end_point.x(), start_point.y()), False)
162
+ self.rubber_band.addPoint(QgsPointXY(end_point.x(), end_point.y()), False)
163
+ self.rubber_band.addPoint(QgsPointXY(start_point.x(), end_point.y()), True)
164
+
165
+ def clear_rubber_band(self):
166
+ """Clear the rubber band."""
167
+ self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
168
+
169
+ def deactivate(self):
170
+ """Deactivate the tool."""
171
+ self.is_drawing = False
172
+ super().deactivate()