From 50a9ed629268e5367b7e8880950a5b9cc15f4490 Mon Sep 17 00:00:00 2001 From: dwolfsch <168710278+dwolfsch@users.noreply.github.com> Date: Sun, 14 Dec 2025 10:50:32 +0100 Subject: [PATCH 1/2] refactor(scarp): rename attributes for consistency and update related references - Standardized attribute names in shapefiles and codebase (`dip` -> `dipDir`, `slopeangle` -> `dipAngle`, etc.). - Updated affected modules, tests, and documentation to reflect these changes. --- avaframe/com6RockAvalanche/scarp.py | 59 +++++++++++------- .../Inputs/POINTS/points_coordinates.dbf | Bin 198 -> 483 bytes .../Inputs/POINTS/points_coordinates.shp | Bin 156 -> 128 bytes .../Inputs/POINTS/points_coordinates.shx | Bin 116 -> 108 bytes .../POLYGONS/scarpFluchthorn_perimeter.dbf | Bin 88 -> 77 bytes .../POLYGONS/scarpFluchthorn_perimeter.shp | Bin 372 -> 236 bytes .../POLYGONS/scarpFluchthorn_perimeter.shx | Bin 116 -> 108 bytes avaframe/in2Trans/shpConversion.py | 42 ++++++------- docs/moduleCom6RockAvalanche.rst | 16 ++--- 9 files changed, 64 insertions(+), 53 deletions(-) diff --git a/avaframe/com6RockAvalanche/scarp.py b/avaframe/com6RockAvalanche/scarp.py index 10eb5d0f0..d3ae2f762 100644 --- a/avaframe/com6RockAvalanche/scarp.py +++ b/avaframe/com6RockAvalanche/scarp.py @@ -83,15 +83,16 @@ def scarpAnalysisMain(cfg, baseDir): # Read required attributes directly from the shapefile's attribute table try: planesZseed = list(map(float, SHPdata['zseed'])) - planesDip = list(map(float, SHPdata['dip'])) - planesSlope = list(map(float, SHPdata['slopeangle'])) + planesDipDir = list(map(float, SHPdata['dipdir'])) + planesDipAngle = list(map(float, SHPdata['dipAngle'])) + except KeyError as e: - raise ValueError(f"Required attribute '{e.args[0]}' not found in shapefile. Make sure 'zseed', 'dip', and 'slope' fields exist.") + raise ValueError(f"Required attribute '{e.args[0]}' not found in shapefile. Make sure 'zseed', 'dipdir', and 'dipangle' fields exist.") - if not (len(planesZseed) == len(planesDip) == len(planesSlope) == SHPdata["nFeatures"]): + if not (len(planesZseed) == len(planesDipDir) == len(planesDipAngle) == SHPdata["nFeatures"]): raise ValueError("Mismatch between number of features and extracted plane attributes in the shapefile.") - if not (len(planesZseed) == len(planesDip) == len(planesSlope) == SHPdata["nFeatures"]): + if not (len(planesZseed) == len(planesDipDir) == len(planesDipAngle) == SHPdata["nFeatures"]): raise ValueError( "Mismatch between number of shapefile features and plane parameters in the .ini file." ) @@ -100,8 +101,8 @@ def scarpAnalysisMain(cfg, baseDir): xSeed = SHPdata["x"][int(SHPdata["Start"][i])] ySeed = SHPdata["y"][int(SHPdata["Start"][i])] zSeed = planesZseed[i] - dip = planesDip[i] - slopeAngle = planesSlope[i] + dip = planesDipDir[i] + slopeAngle = planesDipAngle[i] planeFeatures.extend([xSeed, ySeed, zSeed, dip, slopeAngle]) features = ",".join(map(str, planeFeatures)) @@ -112,14 +113,14 @@ def scarpAnalysisMain(cfg, baseDir): ellipsoidsMaxDepth = list(map(float, SHPdata['maxdepth'])) ellipsoidsSemiMajor = list(map(float, SHPdata['semimajor'])) ellipsoidsSemiMinor = list(map(float, SHPdata['semiminor'])) - ellipsoidsTilt = list(map(float, SHPdata['tilt'])) - ellipsoidsDir = list(map(float, SHPdata['direc'])) + ellipsoidsDipAngle = list(map(float, SHPdata['dipAngle'])) + ellipsoidsDipDir = list(map(float, SHPdata['dipdir'])) ellipsoidsOffset = list(map(float, SHPdata['offset'])) - ellipsoidDip = list(map(float, SHPdata['dip'])) + ellipsoidsRotAngle = list(map(float, SHPdata['rotAngle'])) except KeyError as e: - raise ValueError(f"Required attribute '{e.args[0]}' not found in shapefile. Ensure the fields 'maxdepth', 'semimajor', 'semiminor', 'tilt', 'dir', 'dip', and 'offset' exist.") + raise ValueError(f"Required attribute '{e.args[0]}' not found in shapefile. Ensure the fields 'maxdepth', 'semimajor', 'semiminor', 'rotangle', 'dipdir', 'dipangle', and 'offset' exist.") - if not all(len(lst) == SHPdata["nFeatures"] for lst in [ellipsoidsMaxDepth, ellipsoidsSemiMajor, ellipsoidsSemiMinor, ellipsoidsTilt, ellipsoidsDir, ellipsoidsOffset, ellipsoidDip]): + if not all(len(lst) == SHPdata["nFeatures"] for lst in [ellipsoidsMaxDepth, ellipsoidsSemiMajor, ellipsoidsSemiMinor, ellipsoidsDipAngle, ellipsoidsDipDir, ellipsoidsOffset, ellipsoidsRotAngle]): raise ValueError("Mismatch between number of shapefile features and ellipsoid parameters.") for i in range(SHPdata["nFeatures"]): @@ -128,10 +129,10 @@ def scarpAnalysisMain(cfg, baseDir): maxDepth = ellipsoidsMaxDepth[i] semiMajor = ellipsoidsSemiMajor[i] semiMinor = ellipsoidsSemiMinor[i] - tilt = ellipsoidsTilt[i] - direction = ellipsoidsDir[i] + tilt = ellipsoidsDipAngle[i] + direction = ellipsoidsDipDir[i] offset = ellipsoidsOffset[i] - dip = ellipsoidDip[i] + dip = ellipsoidsRotAngle[i] ellipsoidFeatures.extend([xCenter, yCenter, maxDepth, semiMajor, semiMinor, tilt, direction, offset, dip]) features = ",".join(map(str, ellipsoidFeatures)) @@ -150,6 +151,11 @@ def scarpAnalysisMain(cfg, baseDir): raise ValueError("Unsupported method. Choose 'plane' or 'ellipsoid'.") hRelData = dem["rasterData"] - scarpData + + #Compute and log excavated volume + cellArea = abs(dem["header"]["cellsize"] ** 2) + volume = np.sum(hRelData[periData > 0]) * cellArea + log.info(f"Excavated volume (within perimeter): {volume:.2f} m³") # create output directory and files outDir = pathlib.Path(baseDir) @@ -236,8 +242,10 @@ def calculateScarpWithPlanes(elevData, periData, elevTransform, planes): dip = [planes[3]] slope = [planes[4]] - betaX = [math.tan(math.radians(slope[0])) * math.cos(math.radians(dip[0]))] - betaY = [math.tan(math.radians(slope[0])) * math.sin(math.radians(dip[0]))] + slopeRad = math.radians(slope[0]) + dipRad = math.radians(dip[0]) + betaX = [ math.tan(slopeRad) * math.sin(dipRad) ] + betaY = [ math.tan(slopeRad) * math.cos(dipRad) ] for i in range(1, nPlanes): xSeed.append(planes[5 * i]) @@ -245,8 +253,11 @@ def calculateScarpWithPlanes(elevData, periData, elevTransform, planes): zSeed.append(planes[5 * i + 2]) dip.append(planes[5 * i + 3]) slope.append(planes[5 * i + 4]) - betaX.append(math.tan(math.radians(slope[i])) * math.cos(math.radians(dip[i]))) - betaY.append(math.tan(math.radians(slope[i])) * math.sin(math.radians(dip[i]))) + + slopeRad = math.radians(slope[i]) + dipRad = math.radians(dip[i]) + betaX.append( math.tan(slopeRad) * math.sin(dipRad) ) + betaY.append( math.tan(slopeRad) * math.cos(dipRad) ) for row in range(n): for col in range(m): @@ -333,6 +344,8 @@ def calculateScarpWithEllipsoids(elevData, periData, elevTransform, ellipsoids): dxOffset = -offset[k] * normal_dx * math.sin(slopeAngle) dyOffset = -offset[k] * normal_dy * math.sin(slopeAngle) dzOffset = -offset[k] * math.cos(slopeAngle) + #clamp z-offset + dzOffset = max(-maxDepth[k], min(dzOffset, maxDepth[k])) else: dxOffset = dyOffset = dzOffset = 0 else: @@ -344,11 +357,9 @@ def calculateScarpWithEllipsoids(elevData, periData, elevTransform, ellipsoids): dxPos = west - x0 dyPos = north - y0 - - # Rotate the position by dip angle - dxRot = dxPos * np.cos(dip[k]) + dyPos * np.sin(dip[k]) - dyRot = -dxPos * np.sin(dip[k]) + dyPos * np.cos(dip[k]) - + + dxRot = dxPos * np.sin(dip[k]) - dyPos * np.cos(dip[k]) + dyRot = dxPos * np.cos(dip[k]) + dyPos * np.sin(dip[k]) # Normalize to ellipsoid axes xNorm = dxRot / semiMajor[k] yNorm = dyRot / semiMinor[k] diff --git a/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.dbf b/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.dbf index ef0170f0422ae9ff7a8e280556033fd2876a21ac..b0e1d2757eab9334f2a173df848cde4eb9ab0868 100644 GIT binary patch literal 483 zcmZRsV-jLyU|>*WJP0H)L2hD2N@_t#22jQiBrCy>swO3~z%eg9Cl!}`ep*^_Y6(~m zR{h1PxtY0%S@}gc%m>S7=HZkF+MkjM)QrpiqWqFXeD13%PEAb#Ysc0L%D4Hvj+t literal 198 zcmZRsW#wmLU|?uuPy&*epsF}EH3cH<2co!{QPrem7Qh6s$`|M47o;ZUrRStFV3p@p g00JXZ0|Pw+0|O9S!5G0bf-_N6n8Ae=Ou$Sj0FFr&2mk;8 diff --git a/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.shp b/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.shp index 0cc7e001666ab1d47f73d6d321da310614a583c6..a1cb3ab00538d986f34e25b221539ee816a90ae5 100644 GIT binary patch literal 128 ycmZQzQ0HR64jf)EGcYg$<*w&%-DvUt;DNdC68x|4WOqd8W7m!%3NnTZn^^#oupOKL literal 156 zcmZQzQ0HR64*Xs)GcYg$<%B&{)3fFtKEVBZ?J@Jc?2ZTPR`V`nJ#@fUzq`ZiI=drw m?I@xkW4J&BOfSqVpb!&G?&^wT4#7o-4)EB|D*AJp-4OutlOL=A diff --git a/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.shx b/avaframe/data/scarpExample/Inputs/POINTS/points_coordinates.shx index adec32cf50824328aad1a453ac95aea068b0e6bf..9f4f0f8bf475fc27009a420457875354c455e413 100644 GIT binary patch literal 108 xcmZQzQ0HR64$NLKGcYg$<*w&%-DvUt;DNdC68x|4WOqd8W7m!%Y6RqQ0RW{J6kGrR literal 116 zcmZQzQ0HR64y;}Wo54AVP%}i>dq(y01-X{H2?qr delta 24 XcmeZ`U}dgldvE}1qV_9HB|%% diff --git a/avaframe/data/scarpExample/Inputs/POLYGONS/scarpFluchthorn_perimeter.shp b/avaframe/data/scarpExample/Inputs/POLYGONS/scarpFluchthorn_perimeter.shp index ec5f2194b65076b7467cdeaf6799d1b739ab7800..a07334ed12f90b46085244378e5884d8a7a9554c 100644 GIT binary patch literal 236 zcmZQzQ0HR64$59IGcd3MB&;byYzn0zc$sV0Y!deFp)G@7m^5ihPBX;d5 zqKrVE1F~6CILrbm1gQf7n7uH2&Yf1WYjikxK-T%P>>i-KFn7Srl6|xN){I$)4tT0Q LPrV6rC%S$BZ|Y5i literal 372 zcmZQzQ0HR64tBj@W?*0i%I!^%+wazN_`rh1^Y)XMvOA{ye0gWS#(@Lzn{!ne?yx&z z*N!5}2;@0{%nCYL8R-&@X;xCkuI9UE*&RU&LFzyNrq*5cdFsU@?2e&Dabktx2M@s1 z!rW2I<7ecxj@@zF?iq~Sk_fZW^#hG$0%EW`G!II-BvlB&;byYzn0zc$sV0Y!deFp)G@7m^5ihPBX;d5 JqDDZT0{}885}N=3 literal 116 zcmZQzQ0HR64y;} Date: Thu, 19 Feb 2026 13:08:56 +0100 Subject: [PATCH 2/2] test(scarp): update plane parameter mappings and expected feature count --- avaframe/tests/test_scarp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/avaframe/tests/test_scarp.py b/avaframe/tests/test_scarp.py index cb1b89071..1692b34a3 100644 --- a/avaframe/tests/test_scarp.py +++ b/avaframe/tests/test_scarp.py @@ -121,8 +121,8 @@ def test_plane_parameter_extraction(scarp_test_data): # Extract plane parameters (as done in scarpAnalysisMain) planesZseed = list(map(float, SHPdata["zseed"])) - planesDip = list(map(float, SHPdata["dip"])) - planesSlope = list(map(float, SHPdata["slopeangle"])) + planesDip = list(map(float, SHPdata["dipdir"])) + planesSlope = list(map(float, SHPdata["dipAngle"])) # Assertions assert len(planesZseed) == SHPdata["nFeatures"], ( @@ -132,7 +132,7 @@ def test_plane_parameter_extraction(scarp_test_data): assert len(planesSlope) == SHPdata["nFeatures"], ( "Should have slope for each feature" ) - assert SHPdata["nFeatures"] == 2, "Test data should have 2 features" + assert SHPdata["nFeatures"] == 1, "Test data should have 1 feature" # Build feature string planeFeatures = []