qgis-tem-loader

qgis plugin for loading TEM geophysical inversion XYZ files as 3D objects
git clone git://src.adamsgaard.dk/qgis-tem-loader # fast
git clone https://src.adamsgaard.dk/qgis-tem-loader.git # slow
Log | Files | Refs | README | LICENSE Back to index

commit 2c8ca16f1c3fc767f81b202e5ba896efa85d6da7
parent 79f24997662133e3aa0bdd2ecbd6541b3fba08c1
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Fri, 15 May 2026 19:08:23 +0200

fix(layers): use midpoint for DOI opacity

Diffstat:
Mtem_loader/core.py | 10++++++----
Mtem_loader/styles/layers.qml | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mtest/test_core.py | 30++++++++++++++++++++++++------
3 files changed, 256 insertions(+), 50 deletions(-)

diff --git a/tem_loader/core.py b/tem_loader/core.py @@ -49,10 +49,10 @@ ABOVE_DOI_OPACITY = 100 BELOW_DOI_OPACITY = 10 -def layer_opacity(depth_bottom, doi): +def layer_opacity(depth_mid, doi): if doi is None: return ABOVE_DOI_OPACITY - return ABOVE_DOI_OPACITY if depth_bottom <= doi else BELOW_DOI_OPACITY + return ABOVE_DOI_OPACITY if depth_mid <= doi else BELOW_DOI_OPACITY # Resistivity ranges mirror the graduated symbology in styles/layers.qml. # Each entry is (upper_exclusive, '#RRGGBB'); the final entry is the catch-all. @@ -306,6 +306,7 @@ def process_xyz(path): depth_top = cum_depth depth_bottom = cum_depth + thick + depth_mid = (depth_top + depth_bottom) / 2 z_top = z - depth_top z_bot = z - depth_bottom z_mid = (z_top + z_bot) / 2 @@ -323,7 +324,7 @@ def process_xyz(path): 'DepthBottom': depth_bottom, 'Resistivity': res, 'Color': resistivity_color(res), - 'Opacity': layer_opacity(depth_bottom, doi), + 'Opacity': layer_opacity(depth_mid, doi), 'Layer': i + 1, 'Geometry': layer_wkt, }) @@ -366,6 +367,7 @@ def _append_atem_sci_row(row, res_cols, elev_cols, points, doi_points, layers): z_mid = (z_top + z_bot) / 2 depth_top = z - z_top depth_bottom = z - z_bot + depth_mid = (depth_top + depth_bottom) / 2 layer_rows.append({ 'X': x, 'Y': y, @@ -377,7 +379,7 @@ def _append_atem_sci_row(row, res_cols, elev_cols, points, doi_points, layers): 'DepthBottom': depth_bottom, 'Resistivity': res, 'Color': resistivity_color(res), - 'Opacity': layer_opacity(depth_bottom, doi), + 'Opacity': layer_opacity(depth_mid, doi), 'Layer': i + 1, 'Geometry': f'LINESTRING Z ({x} {y} {z_top}, {x} {y} {z_bot})', }) diff --git a/tem_loader/styles/layers.qml b/tem_loader/styles/layers.qml @@ -1,6 +1,6 @@ <!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'> -<qgis autoRefreshMode="Disabled" autoRefreshTime="0" hasScaleBasedVisibilityFlag="0" labelsEnabled="0" layerType="Vector" maxScale="0" minScale="100000000" readOnly="0" simplifyAlgorithm="0" simplifyDrawingHints="1" simplifyDrawingTol="1" simplifyLocal="1" simplifyMaxScale="1" styleCategories="AllStyleCategories" symbologyReferenceScale="-1" version="4.0.1-Norrköping"> - <renderer-3d layer="layers_219f0a67_bfa6_4c9e_97ae_f671f176d748" type="vector"> +<qgis autoRefreshMode="Disabled" autoRefreshTime="0" hasScaleBasedVisibilityFlag="0" labelsEnabled="0" layerType="Vector" maxScale="0" minScale="100000000" readOnly="0" simplifyAlgorithm="0" simplifyDrawingHints="1" simplifyDrawingTol="1" simplifyLocal="1" simplifyMaxScale="1" styleCategories="AllStyleCategories" symbologyReferenceScale="-1" version="4.0.2-Norrköping"> + <renderer-3d layer="layers_12b54bb4_518f_47ff_a696_ce88ee7fec58" type="vector"> <vector-layer-3d-tiling max-chunk-features="1000" show-bounding-boxes="0" zoom-levels-count="3"/> <symbol material_type="simpleline" type="line"> <data alt-binding="centroid" alt-clamping="absolute" extrusion-height="0" offset="0" simple-lines="1" width="6"/> @@ -27,7 +27,7 @@ <Searchable>1</Searchable> <Private>0</Private> </flags> - <temporal accumulate="0" durationField="X" durationUnit="min" enabled="0" endExpression="" endField="" fixedDuration="0" limitMode="0" mode="0" startExpression="" startField=""> + <temporal accumulate="0" durationField="fid" durationUnit="min" enabled="0" endExpression="" endField="" fixedDuration="0" limitMode="0" mode="0" startExpression="" startField=""> <fixedRange> <start></start> <end></end> @@ -198,7 +198,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -245,7 +251,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -292,7 +304,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -339,7 +357,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -386,7 +410,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -433,7 +463,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -480,7 +516,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -527,7 +569,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -574,7 +622,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -621,7 +675,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -668,7 +728,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -715,7 +781,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -762,7 +834,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -809,7 +887,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -856,7 +940,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -903,7 +993,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -950,7 +1046,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -997,7 +1099,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1044,7 +1152,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1091,7 +1205,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1138,7 +1258,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1185,7 +1311,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1232,7 +1364,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1279,7 +1417,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1326,7 +1470,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1375,7 +1525,13 @@ <data_defined_properties> <Option type="Map"> <Option name="name" type="QString" value=""/> - <Option name="properties"/> + <Option name="properties" type="Map"> + <Option name="alpha" type="Map"> + <Option name="active" type="bool" value="true"/> + <Option name="field" type="QString" value="Opacity"/> + <Option name="type" type="int" value="2"/> + </Option> + </Option> <Option name="type" type="QString" value="collection"/> </Option> </data_defined_properties> @@ -1518,6 +1674,13 @@ <referencedLayers/> <referencingLayers/> <fieldConfiguration> + <field configurationFlags="NoFlag" name="fid"> + <editWidget type="TextEdit"> + <config> + <Option/> + </config> + </editWidget> + </field> <field configurationFlags="NoFlag" name="X"> <editWidget type="TextEdit"> <config> @@ -1588,6 +1751,13 @@ </config> </editWidget> </field> + <field configurationFlags="NoFlag" name="Opacity"> + <editWidget type="Range"> + <config> + <Option/> + </config> + </editWidget> + </field> <field configurationFlags="NoFlag" name="Layer"> <editWidget type="Range"> <config> @@ -1597,19 +1767,22 @@ </field> </fieldConfiguration> <aliases> - <alias field="X" index="0" name=""/> - <alias field="Y" index="1" name=""/> - <alias field="Z" index="2" name=""/> - <alias field="ZTop" index="3" name=""/> - <alias field="ZMid" index="4" name=""/> - <alias field="ZBottom" index="5" name=""/> - <alias field="DepthTop" index="6" name=""/> - <alias field="DepthBottom" index="7" name=""/> - <alias field="Resistivity" index="8" name=""/> - <alias field="Color" index="9" name=""/> - <alias field="Layer" index="10" name=""/> + <alias field="fid" index="0" name=""/> + <alias field="X" index="1" name=""/> + <alias field="Y" index="2" name=""/> + <alias field="Z" index="3" name=""/> + <alias field="ZTop" index="4" name=""/> + <alias field="ZMid" index="5" name=""/> + <alias field="ZBottom" index="6" name=""/> + <alias field="DepthTop" index="7" name=""/> + <alias field="DepthBottom" index="8" name=""/> + <alias field="Resistivity" index="9" name=""/> + <alias field="Color" index="10" name=""/> + <alias field="Opacity" index="11" name=""/> + <alias field="Layer" index="12" name=""/> </aliases> <defaults> + <default applyOnUpdate="0" expression="" field="fid"/> <default applyOnUpdate="0" expression="" field="X"/> <default applyOnUpdate="0" expression="" field="Y"/> <default applyOnUpdate="0" expression="" field="Z"/> @@ -1620,9 +1793,11 @@ <default applyOnUpdate="0" expression="" field="DepthBottom"/> <default applyOnUpdate="0" expression="" field="Resistivity"/> <default applyOnUpdate="0" expression="" field="Color"/> + <default applyOnUpdate="0" expression="" field="Opacity"/> <default applyOnUpdate="0" expression="" field="Layer"/> </defaults> <constraints> + <constraint constraints="3" exp_strength="0" field="fid" notnull_strength="1" unique_strength="1"/> <constraint constraints="0" exp_strength="0" field="X" notnull_strength="0" unique_strength="0"/> <constraint constraints="0" exp_strength="0" field="Y" notnull_strength="0" unique_strength="0"/> <constraint constraints="0" exp_strength="0" field="Z" notnull_strength="0" unique_strength="0"/> @@ -1633,9 +1808,11 @@ <constraint constraints="0" exp_strength="0" field="DepthBottom" notnull_strength="0" unique_strength="0"/> <constraint constraints="0" exp_strength="0" field="Resistivity" notnull_strength="0" unique_strength="0"/> <constraint constraints="0" exp_strength="0" field="Color" notnull_strength="0" unique_strength="0"/> + <constraint constraints="0" exp_strength="0" field="Opacity" notnull_strength="0" unique_strength="0"/> <constraint constraints="0" exp_strength="0" field="Layer" notnull_strength="0" unique_strength="0"/> </constraints> <constraintExpressions> + <constraint desc="" exp="" field="fid"/> <constraint desc="" exp="" field="X"/> <constraint desc="" exp="" field="Y"/> <constraint desc="" exp="" field="Z"/> @@ -1646,6 +1823,7 @@ <constraint desc="" exp="" field="DepthBottom"/> <constraint desc="" exp="" field="Resistivity"/> <constraint desc="" exp="" field="Color"/> + <constraint desc="" exp="" field="Opacity"/> <constraint desc="" exp="" field="Layer"/> </constraintExpressions> <expressionfields/> @@ -1665,6 +1843,8 @@ <column hidden="0" name="Resistivity" type="field" width="-1"/> <column hidden="0" name="Layer" type="field" width="-1"/> <column hidden="0" name="Color" type="field" width="-1"/> + <column hidden="0" name="fid" type="field" width="-1"/> + <column hidden="0" name="Opacity" type="field" width="-1"/> <column hidden="1" type="actions" width="-1"/> </columns> </attributetableconfig> @@ -1701,6 +1881,7 @@ def my_form_open(dialog, layer, feature): <field editable="1" name="DepthBottom"/> <field editable="1" name="DepthTop"/> <field editable="1" name="Layer"/> + <field editable="1" name="Opacity"/> <field editable="1" name="Resistivity"/> <field editable="1" name="X"/> <field editable="1" name="Y"/> @@ -1708,12 +1889,14 @@ def my_form_open(dialog, layer, feature): <field editable="1" name="ZBottom"/> <field editable="1" name="ZMid"/> <field editable="1" name="ZTop"/> + <field editable="1" name="fid"/> </editable> <labelOnTop> <field labelOnTop="0" name="Color"/> <field labelOnTop="0" name="DepthBottom"/> <field labelOnTop="0" name="DepthTop"/> <field labelOnTop="0" name="Layer"/> + <field labelOnTop="0" name="Opacity"/> <field labelOnTop="0" name="Resistivity"/> <field labelOnTop="0" name="X"/> <field labelOnTop="0" name="Y"/> @@ -1721,12 +1904,14 @@ def my_form_open(dialog, layer, feature): <field labelOnTop="0" name="ZBottom"/> <field labelOnTop="0" name="ZMid"/> <field labelOnTop="0" name="ZTop"/> + <field labelOnTop="0" name="fid"/> </labelOnTop> <reuseLastValuePolicy> <field name="Color" reuseLastValuePolicy="NotAllowed"/> <field name="DepthBottom" reuseLastValuePolicy="NotAllowed"/> <field name="DepthTop" reuseLastValuePolicy="NotAllowed"/> <field name="Layer" reuseLastValuePolicy="NotAllowed"/> + <field name="Opacity" reuseLastValuePolicy="NotAllowed"/> <field name="Resistivity" reuseLastValuePolicy="NotAllowed"/> <field name="X" reuseLastValuePolicy="NotAllowed"/> <field name="Y" reuseLastValuePolicy="NotAllowed"/> @@ -1734,6 +1919,7 @@ def my_form_open(dialog, layer, feature): <field name="ZBottom" reuseLastValuePolicy="NotAllowed"/> <field name="ZMid" reuseLastValuePolicy="NotAllowed"/> <field name="ZTop" reuseLastValuePolicy="NotAllowed"/> + <field name="fid" reuseLastValuePolicy="NotAllowed"/> </reuseLastValuePolicy> <dataDefinedFieldProperties/> <widgets/> diff --git a/test/test_core.py b/test/test_core.py @@ -179,16 +179,33 @@ class ProcessXYZTests(unittest.TestCase): self.assertEqual(layer_opacity(0.0, None), ABOVE_DOI_OPACITY) self.assertEqual(layer_opacity(999.0, None), ABOVE_DOI_OPACITY) - def test_layer_opacity_returns_above_when_depth_at_doi(self): + def test_layer_opacity_returns_above_when_midpoint_depth_at_doi(self): self.assertEqual(layer_opacity(10.0, 10.0), ABOVE_DOI_OPACITY) self.assertEqual(layer_opacity(0.0, 50.0), ABOVE_DOI_OPACITY) - def test_layer_opacity_returns_below_when_depth_exceeds_doi(self): - self.assertEqual(layer_opacity(11.0, 10.0), BELOW_DOI_OPACITY) + def test_layer_opacity_returns_below_when_midpoint_depth_exceeds_doi(self): + self.assertEqual(layer_opacity(10.1, 10.0), BELOW_DOI_OPACITY) self.assertEqual(layer_opacity(200.0, 50.0), BELOW_DOI_OPACITY) + def test_crossing_layer_is_above_when_midpoint_is_at_doi(self): + with TemporaryDirectory() as tmp: + path = Path(tmp) / "midpoint.xyz" + path.write_text( + "/ Line StationNo X Y Z DOI DataResidual NumLayers " + "Res_001 Res_002 Res_003 Thick_001 Thick_002 Thick_003\n" + "1 1 0 0 100 15 0 3 10 20 30 10 10 10\n" + ) + + _, _, layers = process_xyz(path) + + self.assertEqual(layers[0]["Opacity"], ABOVE_DOI_OPACITY) + self.assertEqual(layers[1]["DepthTop"], 10.0) + self.assertEqual(layers[1]["DepthBottom"], 20.0) + self.assertEqual(layers[1]["Opacity"], ABOVE_DOI_OPACITY) + self.assertEqual(layers[2]["Opacity"], BELOW_DOI_OPACITY) + def test_fixture_layers_have_correct_opacity(self): - # TEMImage fixture has DOI, so opacity depends on depth vs DOI. + # TEMImage fixture has DOI, so opacity depends on midpoint depth vs DOI. # Each sounding has its own DOI; we verify the first sounding's layers. path = FIXTURE_DIR / "profiler_temimager_4_0_4_6.xyz" points, doi_points, layers = process_xyz(path) @@ -202,11 +219,12 @@ class ProcessXYZTests(unittest.TestCase): first_n = points[0]["NumLayers"] first_layers = layers[:first_n] for layer in first_layers: - expected = ABOVE_DOI_OPACITY if layer["DepthBottom"] <= first_doi else BELOW_DOI_OPACITY + depth_mid = (layer["DepthTop"] + layer["DepthBottom"]) / 2 + expected = ABOVE_DOI_OPACITY if depth_mid <= first_doi else BELOW_DOI_OPACITY self.assertEqual( layer["Opacity"], expected, - f"Layer {layer['Layer']} depth {layer['DepthBottom']} vs DOI {first_doi}", + f"Layer {layer['Layer']} midpoint depth {depth_mid} vs DOI {first_doi}", ) def test_sci_fixture_layers_all_above_opacity(self):