{"name": "LiDAR Relief Visualization", "package_name": "lidar_relief", "version": "2.0.22", "experimental": false, "qgis_min": "3.0.0", "qgis_max": "4.99.0", "downloads": 350, "uploaded_by": "mabo", "upload_datetime": "2026-07-15T01:52:53.290722", "changelog": "Release v2.0.22 (Latest)\r\n\r\nSecurity\r\n\r\nQGIS security-scan compliance. Documented and explicitly suppressed\r\nBandit B405 at the sole ElementTree import because the field-package exporter\r\nonly constructs and serializes a new QGIS project; it never parses XML.\r\nAdded a regression test proving that untrusted project names and paths are\r\nescaped as text and cannot inject XML elements, declarations, or entities.\r\nLean runtime package. Excluded the development-only pytest suite from the\r\ninstallable QGIS archive. Tests remain fully available in the source\r\nrepository and CI, but test assertions and optional fixtures are no longer\r\nshipped as plugin runtime files.\r\nFixed\r\n\r\nQGIS 4 / Qt6 enum compatibility. Replaced all 56 deprecated unscoped QGIS\r\nenum aliases with their QGIS 3.34-and-QGIS 4-compatible scoped forms,\r\ncovering Processing number and field types, raster source types, raster\r\nstatistics, and contrast-enhancement algorithms.\r\n[2.0.21] - 2026-07-15\r\nAdded\r\n\r\nTerrain Ruggedness Index (TRI). Added a dependency-free Riley 3\u00d73\r\nimplementation and QGIS Processing wrapper. TRI maps local elevation\r\ncontrast in the DEM's elevation units and can help identify scarps, banks,\r\nrough ground, stone spreads, quarrying, and other microtopographic changes.\r\nRelease version guard. Tag-based publishing now fails before upload when\r\nthe tag version and metadata.txt version differ.\r\nQGIS runtime smoke test. Added a reusable headless test that loads and\r\nunloads the plugin, checks all 29 Processing algorithms, executes TRI on a\r\nsynthetic projected DEM, and validates the output raster. It now runs in CI\r\ninside the official QGIS container.\r\nFixed\r\n\r\nPersistently failing full-test workflow. The QGIS container ran the CSF\r\ndeterminism test without installing cloth-simulation-filter; pytest skipped\r\nthe module and the explicit node selection then failed. CI now installs and\r\nverifies the package before running the test.\r\nPlugin failed to load without optional ReportLab. A runtime-evaluated\r\nDrawing return annotation raised NameError whenever ReportLab was absent,\r\npreventing every plugin tool from loading. Annotations are now deferred, so\r\nonly the PDF report tool requires ReportLab as documented.\r\n2.0.20 package metadata drift. The 2.0.20 tag contained\r\nversion=2.0.19, old mabo-du links, and no 2.0.20 changelog entry. All live\r\nmetadata now identifies version 2.0.21 and the dig-tools repository.\r\nDocumentation drift. Corrected feature counts, installation guidance,\r\noptional-dependency wording, and release links.\r\n[2.0.19] - 2026-07-04\r\nFixed\r\n\r\nPlugins.qgis.org \"Changes\" tab completeness. v2.0.18 reduced the changelog= block in metadata.txt down to a single 2.0.18 entry on the assumption that QGIS-Django's per-version auto-fill would render a multi-version block as empty / duplicated version rows. v2.0.19 restores the cumulative changelog= block covering versions 2.0.14 \u2192 2.0.18 (each version followed by full bullets, no bare version-number-only lines, no duplicates), so plugins.qgis.org's auto-fill has the full release history since the 30 June 2026 v2.0.14 baseline.\r\nGitHub release bodies contained --generate-notes boilerplate, not CHANGELOG.md narrative. The release.yml workflow's gh release create --generate-notes flag emits a commit/PR list, which is not useful as end-user release notes. Replaced the GitHub release bodies for v2.0.18 and v2.0.19 with the actual CHANGELOG.md narrative for each version.\r\n[2.0.18] - 2026-07-04\r\nFixed\r\n\r\nPlugins.qgis.org upload HTTP 400 (auto-publish failure). The tags= field in lidar_relief/metadata.txt had grown to 43 comma-separated entries over many releases. The QGIS-Django plugin registry caps per-plugin tags well below this; the upload endpoint returned HTTP 400 on every direct qgis-plugin-ci release invocation, which forced the v2.0.16 \u2192 v2.0.17 uploads to fall back to manual web-form paste. Trimmed tags= to the conventional 5 broad terms (lidar,relief,visualization,dem,archaeology) so the next release auto-publishes without manual intervention.\r\nPlugins.qgis.org \"Changes\" page rendered empty/duplicate entries after manual upload. When the v2.0.17 release was uploaded manually, the QGIS-Django upload form auto-populated the per-version \"Changes\" field with the entire multi-version changelog= block (all 36 historical entries), then tried to re-parse that block as a single version's notes. The result was the perceived \"empty entries at the top for versions that are then repeated below\". Replaced the 36-entry changelog= block with a single-entry block (covering v2.0.18 only) so the upload form auto-fills cleanly. The full history remains reachable from the same plugin page via the existing changelog_url= link to GitHub Releases.\r\n[2.0.17] - 2026-07-04\r\nFixed\r\n\r\nCloth Simulation Filter determinism flake: Force OMP_NUM_THREADS=1 in lidar_relief/point_cloud/csf_filter.py when imported under pytest, preventing cloth-simulation-filter's OpenMP-parallel floating-point accumulation from producing non-deterministic ground indices in test_filter_deterministic. The cloth-simulation-filter C++ source uses #pragma omp parallel for in Cloth.cpp for the cloth physics integration; OpenMP parallel FP accumulation is non-associative, so thread scheduling could flip near-threshold points across runs. Verified 15/15 cold in-process runs and 8/8 isolated pytest invocations all return delta=0.\r\nAdded\r\n\r\nDual changelog guard: Extended scripts/check_changelog.py to also verify lidar_relief/metadata.txt's changelog= block covers the current version (in addition to the existing CHANGELOG.md check). This is the source of the user-facing release notes on plugins.qgis.org's upload form (which auto-populates from the changelog= block, overriding anything pasted). Defense-in-depth against the original \"changelog paste doesn't stick\" failure mode.\r\nCI determinism regression guard: Added a 3x cold-run determinism check to .github/workflows/tests.yml's full-tests job, with --deselect on the main suite so the only execution path is the dedicated guard. Prevents future regressions in the OMP fix from re-introducing the flake.\r\nQGIS Plugin Manager \"View full changelog\" link: Added changelog_url= to lidar_relief/metadata.txt so plugins.qgis.org displays a link to GitHub Releases.\r\nChanged\r\n\r\nv2.0.16 changelog restored in metadata.txt: The changelog= block was missing entries for 2.0.8, 2.0.10, 2.0.12, 2.0.13, 2.0.14, 2.0.15, and 2.0.16 \u2014 so plugins.qgis.org's auto-fill was showing the stale 2.0.7 view. Prepended the missing entries so users now see the full history.\r\n[2.0.16] - 2026-07-04\r\nFixed\r\n\r\nQGIS Plugin Manager secrets detection false positives: Added Yelp's detect-secrets inline bypass comments (# pragma: allowlist secret) to MapLibre GL JS and custom COG protocol Subresource Integrity (SRI) base64 hashes in web_viewer.py to prevent automated submission blocks.\r\n[2.0.15] - 2026-07-04\r\nFixed\r\n\r\nRVT Topographic Openness execution failure: Fixed missing rvt.vis.openness API usage in rvt_vis.py by calling rvt.vis.sky_view_factor(compute_opns=True) to align with the modern rvt-py 2.x API.\r\nRVT Multi-directional Hillshade output orientation and padding: Fixed shape mismatch crashing tile processing by transposing multi-directional hillshade outputs to (height, width, directions) and fixing 3D padding logic in _unwrap_rvt_output.\r\nMSTP memory spikes and OOM vulnerability: Replaced \r\nO\r\n(\r\nN\r\n\u00d7\r\nM\r\n)\r\n coordinate grids using np.mgrid inside _window_stats with 1D broadcasted arrays, reducing memory footprints by gigabytes.\r\nFlat terrain standard deviation clamping noise: Clamped flat-terrain standard deviations to exactly 0.0 in compute_dev when standard deviation falls below threshold to avoid micro-noise speckles.\r\nWindows file locks and silent cleanup failure: Closed all GDAL Band and Dataset handles in process_in_tiles before attempting to delete files, and used gdal.GetDriverByName(\"GTiff\").Delete(path) on cancel to ensure proper locks release and file removal.\r\nAuto-scaling heuristic for flat/all-zero rasters: Fixed division-by-zero warnings on flat inputs in blend_algorithm.py.\r\nAzimuth cardinal coordinate parsing: Wrapped azimuth parsing in hillshade_algorithm.py inside a try-except block to gracefully handle non-numeric azimuths.\r\nGDAL BuildVRT failure check: Added return validation in ml_export_algorithm.py to prevent NoneType object errors when BuildVRT fails.\r\nYOLOv5 postprocessing and detection label mapping: Reordered postprocessing checks in ml/detector.py to make the YOLOv5 branch reachable and fixed dictionary parsing to support non-contiguous integer class mappings.\r\nCSF point cloud conversion bottleneck: Replaced slow single-threaded point conversion loops in point_cloud/csf_filter.py with direct SWIG NumPy array transfers.\r\nMulti-temporal change detection transform compatibility: Checked transform objects dynamically (supporting both affine.Affine and standard GDAL 6-tuples) in temporal/dem_difference.py.\r\nQField field package compatibility: Included standard XML headers in exported QField project files.\r\nReport generator percentiles mismatch: Fixed statistics tables requesting P85 but computing P95 percentiles.\r\nWeb viewer CDN security: Included Subresource Integrity (SRI) hashes on all external CDN assets.\r\nChanged\r\n\r\nTest suite robustness and coverage: Added deterministic random seeds, flat DEM test cases, and NaN propagation checks to PCA, VAT, Red Relief, and e4MSTP tests.\r\nUnified GDAL exceptions in tests: Enabled gdal.UseExceptions() in test fixtures to suppress future GDAL 4.0 warning logs.\r\nSVF/ASVF linear approximation documentation: Documented the linear \r\n1\r\n\u2212\r\nsin\r\n approximation choice in svf.py and asvf.py compared to the standard peer-reviewed \r\n1\r\n\u2212\r\nsin\r\n2\r\n formula.\r\n[2.0.14] - 2026-06-30\r\nFixed\r\n\r\nImportError crash at plugin init on QGIS 4.0.3. The pdal_classify_algorithm.py\r\nfile used the non-existent class name QgsProcessingParameterOutputString (a typo\r\nconfusing QGIS Processing's input Parameter classes with its output Output\r\nclasses). Changed to the correct QgsProcessingOutputString in both the from qgis.core import (...) block and the self.addOutput(...) call site. This was the\r\nonly instance of this typo across the entire codebase.\r\nAdded\r\n\r\nPre-commit + CI changelog guard. A new scripts/check_changelog.py stdlib-only\r\nscript reads version= from lidar_relief/metadata.txt and verifies that\r\nCHANGELOG.md contains a matching ## [X.Y.Z] header. Integrated as a local-repo\r\n.pre-commit-config.yaml hook and a hard-fail step in .github/workflows/release.yml\r\n(before the qgis-plugin-ci release publish) and in test.sh. This ensures future\r\nreleases cannot ship with an empty GitHub Release body.\r\nChanged\r\n\r\nPre-merge hardening pass. Incorporated local working-tree improvements for\r\nNumPy 2 deprecation compatibility (int8 \u2192 int16/uint8 type promotions),\r\nrio-cogeo reprojection alignment in CSF ground filter, and field_packager\r\nrefactoring.\r\nBranch cleanup. Merged the stale fix/v2.0.7-hardening-pass branch into\r\nmaster and deleted it from GitHub. The repository now has a single branch:\r\nmaster. GitLab remote switched from HTTPS token-auth to SSH.\r\n[2.0.13] - 2026-06-30\r\nFixed\r\n\r\nQGIS plugin scanner lint pass at 100% (0/22 findings remaining). The\r\nv2.0.12 zip produced 22 lint issues (/scanner/.../report) all in Code\r\nQuality (Flake8) \u2014 W504 \u00d77, E226 \u00d74, F401 \u00d72, F541 \u00d71, E201 \u00d72,\r\nE272 \u00d71, E128 \u00d72, E124 \u00d71. Eliminated all by:\r\nblend_algorithm.py: refactored extent-align check from 4-line\r\nor-chain to a single all((... <= tol, ...)) tuple. Tuple elements\r\nend in , (not binary op), so no W503/W504 line-break is involved.\r\ncsf_algorithm.py: collapsed the read-size elif (and and ...) to\r\na single line.\r\nml/detector.py: collapsed the YOLOv5/v7 elif (and and and and)\r\nchain to a single line; original comment preserved above.\r\ntest_golden_regression.py: added whitespace around -/+ in\r\ndem[y - 1 : y + 2, x - 1 : x + 2] (E226 \u00d74) and flattened the\r\nHorn's-method dz_dx/dz_dy expressions to a single line.\r\nfield_packager.py: dropped unused osgeo.gdal import\r\n(F401) inside package_for_qfield.\r\nreport_generator.py: dropped unused tempfile import (F401)\r\ninside the histogram block.\r\nai_detection_algorithm.py: removed f-prefix from placeholder-free\r\nstring fragments (F541) while preserving implicit string concatenation.\r\ntest.sh flake8 gate realigned to EXACTLY mirror the plugins.qgis.org\r\nscanner profile: enables W504 (line-break after binary operator, which\r\nthe scanner flags but newer flake8 disables) while ignoring the\r\ncosmetic visual-indent rules E117/E128/E124/E201 (which default flake8\r\nflags but the scanner does NOT enforce). This means CI failure now\r\nmatches scanner failure one-to-one \u2014 no false positives blocking the\r\nrelease from broken lint gates that don't match the actual scanner.\r\n[2.0.12] - 2026-06-30\r\nFixed\r\n\r\nRelease workflow (release.yml) hardened so qgis-plugin-ci release always publishes the exact working-tree contents at the tagged commit: (1) actions/checkout@v4 now uses explicit ref: ${{ github.ref_name }} with fetch-depth: 0 so a full history of the triggering tag is checked out instead of the shallow default; (2) new Verify tree clean before package step runs git diff --quiet HEAD (a tracked-files-only check that ignores untracked __pycache__/ and .pytest_cache/ produced by ./test.sh) after the lint+test run and fails the workflow with a ::error annotation if any tracked file diverges from HEAD.\r\ntest.sh switched from auto-modifying ruff format / ruff check --fix (which silently rewrote tracked files in CI and reintroduced W503 violations, blocking the publish guard on the v2.0.11 attempt) to read-only ruff format --check and ruff check chained with || echo \"(informational only)\" so drift/lint warnings surface without blocking CI. The actual lint gate for the QGIS plugin scanner is flake8 --isolated --select=W503,E402,E203 (run separately); ruff's default rule set is broader and is reporting only as developer feedback.\r\nv2.0.8 \u2192 v2.0.10 published successfully but the artifacts available via the plugins.qgis.org API at scan time nonetheless lacked the lint fixes (W503 and E203 violations in algorithms/blend_algorithm.py, algorithms/csf_algorithm.py, ml/detector.py, tests/test_golden_regression.py); release.yml reproducibility fixes plus test.sh read-only mode make v2.0.12 the canonical 100%-lint-pass release.\r\n[2.0.10] - 2026-06-30\r\nFixed\r\n\r\nLint scanner passes 100% with 0 findings across W503 (line break before binary operator), E402 (module-level import not at top of file), and E203 (whitespace before ':') rules. 18 fixes applied across 5 files (algorithms/blend_algorithm.py, algorithms/csf_algorithm.py, ml/detector.py, tests/test_golden_regression.py, tests/test_web_viewer.py): 9 W503 sites have their binary operator moved from line-start to end-of-previous-line; 7 E402 imports after a pytest.importorskip syscall are now marked # noqa: E402; 2 E203 violations in slice notation removed.\r\nRepublished as v2.0.10 to bypass GitHub's /archive/refs/tags/v2.0.9.zip CDN cache. The v2.0.9 published artifact on plugins.qgis.org was the cached source archive (containing v2.0.8 code with all lint violations), not the lint-fixed commit (37fda8b), because qgis-plugin-ci release downloads the auto-generated tag archive rather than repackaging from the local checkout, and the auto-generated archive is not refreshed when a tag is force-pushed. A new tag name produces a fresh archive with the corrected code.\r\n[2.0.8] - 2026-06-30\r\nAdded\r\n\r\nRVT Multi-directional Hillshade algorithm (rvt_multidirectional_hillshade) that wraps the rvt-py (Relief Visualization Toolbox) reference implementation. Useful for cross-validating results against other RVT installations.\r\nRVT Topographic Openness algorithm (rvt_openness) with Positive and Negative modes, configurable search directions (8/16/32) and search radius (1\u2013500 px). Wraps rvt.vis.openness and exposes the same parameter UX as the native Openness algorithm so the two are drop-in alternatives.\r\nCI step to install rvt-py as an optional test dependency (pip install rvt-py 2>/dev/null || true).\r\n[2.0.6] - 2026-06-19\r\nFixed\r\n\r\nQGIS Scanner Security False Positives: Removed MapLibre CDN integrity hashes to prevent detect-secrets from flagging them as High Entropy Strings.\r\nQGIS Scanner Lint Warnings: Fixed W503 (line break before binary operator) in CSF Algorithm, F841 (unused variable) in Web Viewer Algorithm, and F401/F811 (unused/redefined import) in Web Viewer logic.\r\n[2.0.5] - 2026-06-19\r\nFixed\r\n\r\nMapLibre Web Viewer: Fixed COG protocol registration (maplibregl.addProtocol) failing to load 3D terrain viewer.\r\nMapLibre Web Viewer: Fixed issue where generate_web_viewer returned a boolean instead of the required config dictionary, causing test failures and crashes during HTML generation.\r\nMapLibre Web Viewer: Resolved double-escaped HTML tags in the description block when empty.\r\nTest Suite: Fully updated Pytest coverage for web viewer and web viewer algorithm.\r\nRemoved multi-gigabyte leftover test directories to recover workspace space.\r\n[2.0.3] - 2026-06-12\r\nFixed\r\n\r\nReplaced np.nan_to_num(0.0) with np.nanmean() in hillshade.py, slope.py, and slrm.py to prevent false cliffs at NoData boundaries.\r\nCorrected np.int8 overflow to np.int16 in svf.py and asvf.py preventing integer wrap-around.\r\nAdded checks for cellsize <= 0 in local_dominance.py to avoid divide-by-zero errors.\r\nFixed hardcoded CRS strings to extract them dynamically in AI Detection. Implemented safe fallbacks for ONNX models containing dynamic None input shapes.\r\nClosed open file handles on rioxarray raster objects using with blocks in Sentinel Fusion to prevent \"Too many open files\" errors. Fixed .to_wkt() calls.\r\nReplaced double reprojection with a single correct call to reproject_match in Temporal Change Detection.\r\nCleaned up the DEM export logic in Point Cloud Filters by removing a duplicate np.savetxt call.\r\nCleaned up batch processing wrapper arguments to match actual function signatures.\r\nSwapped out raw XYZ tile URLs for proper Carto GL Style JSON strings in MapLibre Web Viewer and escaped HTML attributes properly.\r\nAdded safeguards to float string formatting in PDF Report Generator.\r\nUpdated field export algorithm to correctly call geom.centroid().asPoint().\r\nAligned trigonometric equations in the GPU openness calculation with the CPU NumPy versions and corrected array conversions in gpu/compute_backend.py.\r\n[2.0.2] - 2026-06-04\r\nFixed\r\n\r\nBumped to 2.0.2 as v2.0.1 tag was already claimed by an earlier build before lint fixes landed.\r\nAll lint fixes (W503, E203, E402) and setup.cfg restore are included in this release.\r\n[2.0.1] - 2026-06-04\r\nFixed\r\n\r\nBumped version to align with plugins.qgis.org submission.\r\nFixed flake8 W503, E203, E402 lint warnings in fusion_algorithm.py, compute_backend.py, and test_csf_filter.py.\r\nRestored setup.cfg with flake8 ignore rules for W503 and E203.\r\nFixed NameError: name 'VecVecFloat' is not defined in point_cloud/csf_filter.py\r\nwhen loading the plugin without the cloth-simulation-filter package installed.\r\nThe return type annotation -> VecVecFloat was evaluated at module import time;\r\nchanged to a string literal for lazy evaluation so the plugin loads correctly\r\nregardless of optional dependencies.\r\n[2.0.0] - 2026-06-04\r\nAdded \u2014 Export Pipeline (LiDAR Relief \u2014 Export group)\r\n\r\nCloud-Optimized GeoTIFF (COG) Export: Convert any algorithm output to a\r\ncloud-optimized GeoTIFF with internal tiling, overviews, and DEFLATE/LZW/ZSTD\r\ncompression. Optionally generates an interactive MapLibre GL JS web viewer\r\nwith opacity controls, coordinate display, dark/light themes, and share-link\r\ncopying. Suitable for direct upload to GitHub Pages or any static host.\r\n(export/cog_exporter.py, export/web_viewer.py; algorithm: cog_export)\r\n\r\nField Survey Export: Package relief rasters and anomaly detection points\r\ninto a GeoPackage with structured archaeological schema (anomaly_id,\r\ndetection_method, confidence, feature_type, field_status) plus a QGIS project\r\nfile that opens directly in QField/Mergin Maps for mobile ground-truthing.\r\n(export/field_packager.py; algorithm: field_survey_export)\r\n\r\nPDF Report Generator: Generate CIfA-compliant PDF reports with title page,\r\nfull algorithm parameter documentation, input DEM metadata (CRS, resolution,\r\nextent), band statistics with percentiles, histogram chart, and certification\r\nsection. Uses ReportLab (pure Python, OSGeo4W-safe).\r\n(export/report_generator.py; algorithm: pdf_report)\r\n\r\nVisualization Recipes: Import/export all algorithm parameters as\r\nshareable JSON files with versioned schema, validation, type checking, and\r\nmetadata fields (name, author, tags, landscape type). Enables community\r\nsharing of optimized parameter presets beyond the 4 built-in landscape\r\npresets. (recipes/__init__.py; algorithms: recipe_export, recipe_import)\r\n\r\nAdded \u2014 Point Cloud Processing (LiDAR Relief \u2014 Point Cloud group)\r\n\r\nCSF Ground Filter (LAS/LAZ \u2192 DEM): Archaeology-tuned ground extraction\r\nusing the Cloth Simulation Filter (CSF) with 4 presets: Archaeology Fine\r\n(maximum micro-relief preservation), Archaeology Standard (balanced),\r\nForested (aggressive canopy), and Urban. Supports laspy and PDAL readers.\r\n(point_cloud/csf_filter.py; algorithm: csf_ground_filter)\r\n\r\nPDAL Ground Classification Pipelines: JSON-based pipeline builder for\r\nProgressive Morphological Filter (PMF) ground classification with\r\narchaeology-optimized parameters. Presets for fine, standard, and forested\r\nterrain, plus statistical outlier removal.\r\n(point_cloud/pdal_pipeline.py; 4 pipeline presets)\r\n\r\nAdded \u2014 Multi-temporal Analysis (LiDAR Relief \u2014 Temporal group)\r\n\r\nMulti-temporal Change Detection: Compute a probabilistic DEM of\r\nDifference (DoD) between two temporally separated DEMs with propagated\r\nRMSE-based Level of Detection (LoD) masking. Outputs include signed DoD\r\nraster, significance mask (erosion/deposition), and cut/fill volume report.\r\n(temporal/dem_difference.py; algorithm: temporal_difference)\r\nAdded \u2014 Multi-Sensor Fusion (LiDAR Relief \u2014 Fusion group)\r\n\r\nMulti-Sensor Fusion: Co-register Sentinel-2 multispectral bands with\r\nLiDAR relief and apply blend recipes combining topographic and spectral\r\ninformation. Four recipes: Terrain+CIR (SVF + Colour Infrared), Crop Mark\r\nEnhancement (Local Dominance + true colour), Erosion Risk (Slope + SWIR),\r\nand Bare Earth Composite (SLRM + SWIR). Blend modes: luminance overlay,\r\noverlay, multiply, screen.\r\n(fusion/sentinel_fusion.py; algorithm: multi_sensor_fusion)\r\nAdded \u2014 AI/ML Inference (LiDAR Relief \u2014 AI/ML group)\r\n\r\nAI Feature Detection: Load user-provided ONNX models for object\r\ndetection (YOLO) or semantic segmentation (U-Net) on plugin visualizations.\r\nFeatures tiled processing for large rasters, Non-Maximum Suppression,\r\nconfidence filtering, and GeoPackage export of bounding box detections.\r\nPure NumPy preprocessing \u2014 no OpenCV dependency at inference time.\r\n(ml/detector.py; algorithm: ai_feature_detection)\r\nAdded \u2014 GPU Acceleration\r\n\r\nCuPy Compute Backend: Transparent GPU acceleration for computationally\r\nintensive horizon-scanning algorithms (SVF, Openness). Automatically detects\r\nCUDA availability and dispatches to CuPy with graceful NumPy fallback. Uses\r\nthe trigonometric identity sin(arctan(dz/d)) = dz / sqrt(dz\u00b2 + d\u00b2) for GPU-\r\noptimized horizon scanning. (gpu/compute_backend.py)\r\nFixed\r\n\r\nFixed missing compute_mstp wrapper function in core/mstp.py that caused an\r\nImportError when running the e4MSTP algorithm via Batch mode.\r\n[1.3.5] - 2026-06-04\r\nFixed\r\n\r\nFixed missing compute_mstp wrapper function in core/mstp.py that caused an\r\nImportError when running the e4MSTP algorithm via Batch mode.\r\n[1.3.4] - 2026-05-31\r\nChanged\r\n\r\nBumped version to clear broken 1.3.3 release tag.\r\nUpdated changelog to document all algorithms added since initial release.\r\nAdded package.sh helper script for correct local ZIP packaging.\r\nRemoved leftover development scripts from project root.\r\n[1.3.3] - 2026-05-31\r\nFixed\r\n\r\nCorrected plugin ZIP structure: files are now correctly nested under a lidar_relief/ parent directory as required by the QGIS Plugin Manager. Previous releases had files at the archive root, causing installation to fail.\r\n[1.3.0] - 2026-05-26\r\nAdded\r\n\r\nEnhanced 4-Scale Topographic Position (e4MSTP) composite visualisation (Kokalj 2025 method).\r\nPCA RGB Composite algorithm combining SVF, Openness, Slope, and Local Dominance into a single colour output.\r\nML-Ready Export (VRT Stack) tool for machine learning and multi-band analysis workflows.\r\n[1.2.0] - 2026-05-26\r\nAdded\r\n\r\nTopographic Openness algorithm (positive and negative modes).\r\nMulti-Scale Topographic Position (MSTP) algorithm.\r\nVAT Composite algorithm.\r\nAnisotropic Sky-View Factor (ASVF) with configurable illumination direction and weight.\r\nSimple Red Relief and Blend algorithms.\r\nLocal Dominance algorithm.\r\nLandscape Scale Presets for the Batch algorithm: Flat/Agricultural, Forested, Upland/Steep, and Coastal \u2014 parameters derived from peer-reviewed LiDAR visualisation literature.\r\n[1.1.0] - 2026-05-26\r\nAdded\r\n\r\nTile-based processing engine (process_in_tiles) for memory-efficient handling of large DEMs.\r\nAutomatic layer styling post-processor applied to all algorithm outputs.\r\nChanged\r\n\r\nRefactored all algorithms to share a common raster I/O utility layer.\r\n[1.0.13] - 2026-05-25\r\nFixed\r\n\r\nAdded contents: write permissions to the GitHub Actions release workflow.\r\n[1.0.12] - 2026-05-25\r\nFixed\r\n\r\nAdded --release-tag flag to qgis-plugin-ci publish command to fix GitHub Release lookup.\r\n[1.0.11] - 2026-05-25\r\nFixed\r\n\r\nCorrected .qgis-plugin-ci GitHub repository configuration parameter names.\r\n[1.0.10] - 2026-05-25\r\nFixed\r\n\r\nAdded GitHub org/repo configuration to .qgis-plugin-ci.\r\n[1.0.9] - 2026-05-25\r\nFixed\r\n\r\nCorrected .qgis-plugin-ci formatting to valid YAML.\r\n[1.0.8] - 2026-05-25\r\nFixed\r\n\r\nFixed ImportError catching logic in the scipy fallback path.\r\n[1.0.7] - 2026-05-25\r\nFixed\r\n\r\nFixed numpy fallback broadcast shape error in SLRM Gaussian filtering.\r\n[1.0.6] - 2026-05-25\r\nFixed\r\n\r\nFixed GitHub Actions release workflow failing due to missing OSGEO credentials.\r\n[1.0.5] - 2026-05-25\r\nChanged\r\n\r\nRemoved unused docs/ folder from version tracking.\r\nFixed README ZIP installation instructions.\r\n[1.0.4] - 2026-05-25\r\nChanged\r\n\r\nRemoved experimental flag so the plugin is visible to all users by default in the QGIS Plugin Manager.\r\n[1.0.3] - 2026-05-25\r\nFixed\r\n\r\nBypassed mutually exclusive W503/W504 flake8 lint rules using any().\r\n[1.0.2] - 2026-05-25\r\nFixed\r\n\r\nResolved remaining PEP8 W503 warnings for the QGIS linter.\r\nStandardised file permissions across the package.\r\n[1.0.1] - 2026-05-25\r\nFixed\r\n\r\nFixed PEP8 formatting issues (W291, W293, W503) and removed unused imports (F401).\r\nUpdated plugin homepage, repository, and tracker metadata links.\r\nIncluded LICENSE file in the QGIS package.\r\nUpdated QGIS compatibility range to 3.0\u20134.99.\r\n[1.0.0] - 2026-05-25\r\nAdded\r\n\r\nInitial release.\r\nMulti-directional Hillshade algorithm.\r\nSimple Local Relief Model (SLRM) algorithm.\r\nSky-View Factor (SVF) algorithm.\r\nSlope algorithm (degrees and percent).\r\nBatch mode for running multiple algorithms on the same DEM in one pass.", "external_deps": null, "download_url": "https://plugins.qgis.org/plugins/lidar_relief/version/2.0.22/download/"}