# Model exported as python.
# Name : Update EOL SOL coords
# Group : PXGEO
# With QGIS : 34200
from typing import Any, Optional
from qgis.core import (QgsProject,
QgsProcessing,
QgsVectorLayer,
QgsProcessingAlgorithm,
QgsProcessingContext,
QgsProcessingFeedback,
QgsProcessingMultiStepFeedback,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterBoolean,
QgsProcessingParameterString
)
from qgis.PyQt.QtCore import QCoreApplication
import processing
import os
[docs]
class UpdateEolSolCoords(QgsProcessingAlgorithm):
INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_NAME = 'OUTPUT_NAME'
DELETE_INPUT = 'DELETE_INPUT'
[docs]
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
[docs]
def createInstance(self):
return UpdateEolSolCoords()
[docs]
def name(self) -> str:
return 'updateeolsolcoords'
[docs]
def displayName(self) -> str:
return self.tr('Update EOL SOL coords')
[docs]
def group(self) -> str:
return self.tr('Seismic scripts')
[docs]
def groupId(self) -> str:
return 'seismicscripts'
[docs]
def shortHelpString(self):
return self.tr("""
This tool generates the updated coordinates of the given layer.
It does so by calculating the End-Of-Line and Start-Of-Line coordinates with geometry.
The results are written to a new layer by the default name "Updated_Coordinates", you may change this name in the Parameters panel.
You can also remove the given input layer by checking the box bellow, to avoid excess of layers showing in the panel.
Run this process after changing the geometry of source or receiver lines (e.g.: after rotating or clipping the layer).
It is neccesary because the coordinates generated by '1 Generate Seismic Grids' are static, meaning the values in the attributes table do not change even when manupilating the geometry of the lines.
""")
[docs]
def initAlgorithm(self, config=None):
"""
Here we define the inputs and output of the algorithm, along
with some other properties.
"""
# INPUTS & parameters
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT_LAYER, 'Input lines', types=[QgsProcessing.TypeVectorLine], defaultValue=None))
# self.addParameter(QgsProcessingParameterFeatureSink('WithEolSol', 'With EOL SOL', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, supportsAppend=True, defaultValue=None))
self.addParameter(QgsProcessingParameterString(self.OUTPUT_NAME, 'Output Layer Name', defaultValue='Updated_Coordinates'))
self.addParameter(QgsProcessingParameterBoolean(self.DELETE_INPUT, 'Remove input layer after processing', defaultValue=False))
[docs]
def processAlgorithm(self, parameters: dict[str, Any], context: QgsProcessingContext, model_feedback: QgsProcessingFeedback) -> dict[str, Any]:
# Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
# overall progress through the model
feedback = QgsProcessingMultiStepFeedback(5, model_feedback)
results = {}
outputs = {}
# Drop field(s)
alg_params = {
'COLUMN': ['X_start, Y_start, X_end, Y_end'],
'INPUT': parameters[self.INPUT_LAYER],
'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
}
outputs['DropFields'] = processing.run('native:deletecolumn', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
feedback.setCurrentStep(1)
if feedback.isCanceled():
return {}
# X_start
alg_params = {
'FIELD_LENGTH': 0,
'FIELD_NAME': 'X_start',
'FIELD_PRECISION': 0,
'FIELD_TYPE': 0, # Decimal (double)
'FORMULA': '$x_at(0)',
'INPUT': outputs['DropFields']['OUTPUT'],
'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
}
outputs['X_start'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
feedback.setCurrentStep(2)
if feedback.isCanceled():
return {}
# Y_start
alg_params = {
'FIELD_LENGTH': 0,
'FIELD_NAME': 'Y_start',
'FIELD_PRECISION': 0,
'FIELD_TYPE': 0, # Decimal (double)
'FORMULA': '$y_at(0)',
'INPUT': outputs['X_start']['OUTPUT'],
'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
}
outputs['Y_start'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
feedback.setCurrentStep(3)
if feedback.isCanceled():
return {}
# X_end
alg_params = {
'FIELD_LENGTH': 0,
'FIELD_NAME': 'X_end',
'FIELD_PRECISION': 0,
'FIELD_TYPE': 0, # Decimal (double)
'FORMULA': '$x_at(-1)',
'INPUT': outputs['Y_start']['OUTPUT'],
'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
}
outputs['X_end'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
feedback.setCurrentStep(4)
if feedback.isCanceled():
return {}
# Get project directory
project_dir = os.path.dirname(QgsProject.instance().fileName())
layer_name = parameters[self.OUTPUT_NAME]
# Function to find next available filename
def get_next_available_filename(directory, base_name):
index = 1
base_filename = f"{base_name}.gpkg"
full_path = os.path.join(directory, base_filename)
while os.path.exists(full_path):
base_filename = f"{base_name}_{index}.gpkg"
full_path = os.path.join(directory, base_filename)
index += 1
return full_path
output_path = get_next_available_filename(project_dir, layer_name)
# Y_end
alg_params = {
'FIELD_LENGTH': 0,
'FIELD_NAME': 'Y_end',
'FIELD_PRECISION': 0,
'FIELD_TYPE': 0, # Decimal (double)
'FORMULA': '$y_at(-1)',
'INPUT': outputs['X_end']['OUTPUT'],
'OUTPUT': output_path
}
outputs['Y_end'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
results['WithEolSol'] = output_path
layer = QgsVectorLayer(output_path, layer_name, "ogr")
QgsProject.instance().addMapLayer(layer)
if parameters[self.DELETE_INPUT]:
input_layer = self.parameterAsVectorLayer(parameters, self.INPUT_LAYER, context)
QgsProject.instance().removeMapLayer(input_layer.id())
return results