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.
- {geoai_py-0.19.0 → geoai_py-0.20.0}/PKG-INFO +1 -1
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/__init__.py +1 -1
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/PKG-INFO +1 -1
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/SOURCES.txt +17 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/pyproject.toml +2 -2
- geoai_py-0.20.0/qgis_plugin/README.md +188 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/__init__.py +21 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/__init__.py +13 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/map_tools.py +172 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/moondream.py +651 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/samgeo.py +1438 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/dialogs/segmentation.py +1450 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/geoai_plugin.py +510 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/about.svg +5 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/gpu.svg +12 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/icon.png +0 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/moondream.svg +6 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/samgeo.png +0 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/icons/segment.svg +6 -0
- geoai_py-0.20.0/qgis_plugin/geoai_plugin/metadata.txt +42 -0
- geoai_py-0.20.0/qgis_plugin/install.py +156 -0
- geoai_py-0.20.0/qgis_plugin/install.sh +42 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/.dockerignore +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/.editorconfig +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/.gitignore +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/.pre-commit-config.yaml +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/CITATION.cff +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/Dockerfile +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/LICENSE +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/MANIFEST.in +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/README.md +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/__init__.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/catalog_models.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/catalog_tools.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/geo_agents.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/map_tools.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/stac_models.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/agents/stac_tools.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/change_detection.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/classify.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/detectron2.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/dinov3.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/download.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/extract.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/geoai.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/hf.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/landcover_train.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/landcover_utils.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/map_widgets.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/moondream.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/sam.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/segment.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/segmentation.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/timm_segment.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/timm_train.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/__init__.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/cloudmask.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/multiclean.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/tools/sr.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/train.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai/utils.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/dependency_links.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/entry_points.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/requires.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/geoai_py.egg-info/top_level.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/mkdocs.yml +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/pytest.ini +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/requirements.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/requirements_docs.txt +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/setup.cfg +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/__init__.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/create_test_data.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_classify.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_download.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_extract.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_fixtures.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_geoai.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_segment.py +0 -0
- {geoai_py-0.19.0 → geoai_py-0.20.0}/tests/test_utils.py +0 -0
|
@@ -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.
|
|
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.
|
|
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()
|