Skip to content

Commit 1235856

Browse files
Merge branch 'noelle/sorter' into processing/processing_tools
2 parents 26399b2 + a660002 commit 1235856

8 files changed

Lines changed: 400 additions & 73 deletions

File tree

m2l/main/vectorLayerWrapper.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,35 @@ def dataframeToQgsLayer(
454454
feedback.pushInfo("Done.")
455455
feedback.setProgress(100)
456456
return sink, sink_id
457+
458+
from qgis.core import NULL
459+
from PyQt5.QtCore import QVariant
460+
461+
def qvariantToFloat(f, field_name):
462+
val = f.attribute(field_name) # usually returns a native Python type
463+
# null / empty values
464+
if val in (None, NULL, ''):
465+
return None
466+
# strings with decimal comma (depending on locale)
467+
if isinstance(val, str):
468+
val = val.strip()
469+
if val == '':
470+
return None
471+
val = val.replace(',', '.') # replace comma with dot if present
472+
try:
473+
return float(val)
474+
except ValueError:
475+
pass
476+
# residual QVariant
477+
if isinstance(val, QVariant):
478+
# toDouble() -> (value, ok)
479+
d, ok = val.toDouble()
480+
return float(d) if ok else None
481+
# native int/float
482+
if isinstance(val, (int, float)):
483+
return float(val)
484+
# fallback conversion attempt
485+
try:
486+
return float(val)
487+
except Exception:
488+
return None
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .extract_basal_contacts import BasalContactsAlgorithm
22
from .sorter import StratigraphySorterAlgorithm
33
from .thickness_calculator import ThicknessCalculatorAlgorithm
4-
from .sampler import SamplerAlgorithm
4+
from .sampler import SamplerAlgorithm

m2l/processing/algorithms/extract_basal_contacts.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class BasalContactsAlgorithm(QgsProcessingAlgorithm):
4141
INPUT_STRATI_COLUMN = 'STRATIGRAPHIC_COLUMN'
4242
INPUT_IGNORE_UNITS = 'IGNORE_UNITS'
4343
OUTPUT = "BASAL_CONTACTS"
44+
ALL_CONTACTS = "ALL_CONTACTS"
4445

4546
def name(self) -> str:
4647
"""Return the algorithm name."""
@@ -127,6 +128,13 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
127128
)
128129
)
129130

131+
self.addParameter(
132+
QgsProcessingParameterFeatureSink(
133+
"ALL_CONTACTS",
134+
"All Contacts",
135+
)
136+
)
137+
130138
def processAlgorithm(
131139
self,
132140
parameters: dict[str, Any],
@@ -172,6 +180,7 @@ def processAlgorithm(
172180

173181
feedback.pushInfo("Extracting Basal Contacts...")
174182
contact_extractor = ContactExtractor(geology, faults)
183+
all_contacts = contact_extractor.extract_all_contacts()
175184
basal_contacts = contact_extractor.extract_basal_contacts(strati_column)
176185

177186
feedback.pushInfo("Exporting Basal Contacts Layer...")
@@ -183,7 +192,15 @@ def processAlgorithm(
183192
output_key=self.OUTPUT,
184193
feedback=feedback,
185194
)
186-
return {self.OUTPUT: basal_contacts}
195+
contacts_layer = GeoDataFrameToQgsLayer(
196+
self,
197+
all_contacts,
198+
parameters=parameters,
199+
context=context,
200+
output_key=self.ALL_CONTACTS,
201+
feedback=feedback,
202+
)
203+
return {self.OUTPUT: basal_contacts, self.ALL_CONTACTS: contacts_layer}
187204

188205
def createInstance(self) -> QgsProcessingAlgorithm:
189206
"""Create a new instance of the algorithm."""

m2l/processing/algorithms/sampler.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,21 @@
2626
QgsProcessingParameterFeatureSource,
2727
QgsProcessingParameterRasterLayer,
2828
QgsProcessingParameterEnum,
29+
QgsProcessingParameterRasterLayer,
30+
QgsProcessingParameterEnum,
2931
QgsProcessingParameterNumber,
3032
QgsFields,
33+
QgsFields,
3134
QgsField,
3235
QgsFeature,
3336
QgsGeometry,
3437
QgsPointXY,
3538
QgsVectorLayer,
3639
QgsWkbTypes,
3740
QgsCoordinateReferenceSystem
41+
QgsVectorLayer,
42+
QgsWkbTypes,
43+
QgsCoordinateReferenceSystem
3844
)
3945
# Internal imports
4046
from ...main.vectorLayerWrapper import qgsLayerToGeoDataFrame
@@ -74,20 +80,25 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
7480

7581

7682
self.addParameter(
83+
QgsProcessingParameterEnum(
7784
QgsProcessingParameterEnum(
7885
self.INPUT_SAMPLER_TYPE,
7986
"SAMPLER_TYPE",
8087
["Decimator", "Spacing"],
8188
defaultValue=0
89+
["Decimator", "Spacing"],
90+
defaultValue=0
8291
)
8392
)
8493

8594
self.addParameter(
95+
QgsProcessingParameterRasterLayer(
8696
QgsProcessingParameterRasterLayer(
8797
self.INPUT_DTM,
8898
"DTM",
8999
[QgsProcessing.TypeRaster],
90100
optional=True,
101+
optional=True,
91102
)
92103
)
93104

@@ -115,6 +126,8 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
115126
"DECIMATION",
116127
QgsProcessingParameterNumber.Integer,
117128
defaultValue=1,
129+
QgsProcessingParameterNumber.Integer,
130+
defaultValue=1,
118131
optional=True,
119132
)
120133
)
@@ -125,6 +138,8 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
125138
"SPACING",
126139
QgsProcessingParameterNumber.Double,
127140
defaultValue=200.0,
141+
QgsProcessingParameterNumber.Double,
142+
defaultValue=200.0,
128143
optional=True,
129144
)
130145
)
@@ -133,6 +148,7 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
133148
QgsProcessingParameterFeatureSink(
134149
self.OUTPUT,
135150
"Sampled Points",
151+
"Sampled Points",
136152
)
137153
)
138154

@@ -161,12 +177,18 @@ def processAlgorithm(
161177
geology = qgsLayerToGeoDataFrame(geology)
162178
spatial_data_gdf = qgsLayerToGeoDataFrame(spatial_data)
163179
dtm_gdal = gdal.Open(dtm.source()) if dtm is not None and dtm.isValid() else None
180+
spatial_data_gdf = qgsLayerToGeoDataFrame(spatial_data)
181+
dtm_gdal = gdal.Open(dtm.source()) if dtm is not None and dtm.isValid() else None
164182

183+
if sampler_type == "Decimator":
165184
if sampler_type == "Decimator":
166185
feedback.pushInfo("Sampling...")
167186
sampler = SamplerDecimator(decimation=decimation, dtm_data=dtm_gdal, geology_data=geology)
168187
samples = sampler.sample(spatial_data_gdf)
188+
sampler = SamplerDecimator(decimation=decimation, dtm_data=dtm_gdal, geology_data=geology)
189+
samples = sampler.sample(spatial_data_gdf)
169190

191+
if sampler_type == "Spacing":
170192
if sampler_type == "Spacing":
171193
feedback.pushInfo("Sampling...")
172194
sampler = SamplerSpacing(spacing=spacing, dtm_data=dtm_gdal, geology_data=geology)
@@ -192,6 +214,33 @@ def processAlgorithm(
192214
crs
193215
)
194216

217+
if samples is not None and not samples.empty:
218+
for _index, row in samples.iterrows():
219+
feature = QgsFeature(fields)
220+
221+
# decimator has z values
222+
if 'Z' in samples.columns and pd.notna(row.get('Z')):
223+
wkt = f"POINT Z ({row['X']} {row['Y']} {row['Z']})"
224+
feature.setGeometry(QgsGeometry.fromWkt(wkt))
225+
else:
226+
#spacing has no z values
227+
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(row['X'], row['Y'])))
228+
229+
feature.setAttributes([
230+
str(row.get('ID', '')),
231+
float(row.get('X', 0)),
232+
float(row.get('Y', 0)),
233+
float(row.get('Z', 0)) if pd.notna(row.get('Z')) else 0.0,
234+
str(row.get('featureId', ''))
235+
])
236+
237+
sink.addFeature(feature)
238+
239+
fields,
240+
QgsWkbTypes.PointZ if 'Z' in (samples.columns if samples is not None else []) else QgsWkbTypes.Point,
241+
crs
242+
)
243+
195244
if samples is not None and not samples.empty:
196245
for _index, row in samples.iterrows():
197246
feature = QgsFeature(fields)

0 commit comments

Comments
 (0)