tem_loader.py (3840B)
1 from pathlib import Path 2 3 from qgis.PyQt.QtWidgets import QAction, QFileDialog, QMessageBox 4 from qgis.core import ( 5 QgsProject, 6 QgsVectorLayer, 7 QgsCoordinateReferenceSystem, 8 ) 9 10 from . import core 11 12 13 STYLES_DIR = Path(__file__).parent / 'styles' 14 15 16 def _build_delimited_text_uri(csv_path, geom_type, crs_str): 17 base_uri = csv_path.resolve().as_uri() 18 return ( 19 f'{base_uri}?type={geom_type}' 20 f'&crs={crs_str}' 21 f'&wktField=Geometry' 22 f'&delimiter=,' 23 f'&xField=X&yField=Y' 24 ) 25 26 27 class TEMLoaderPlugin: 28 def __init__(self, iface): 29 self.iface = iface 30 self._action = None 31 32 def initGui(self): 33 self._action = QAction('Load TEM XYZ files\u2026', self.iface.mainWindow()) 34 self._action.triggered.connect(self.run) 35 self.iface.addPluginToMenu('TEM Loader', self._action) 36 37 def unload(self): 38 self.iface.removePluginMenu('TEM Loader', self._action) 39 self._action = None 40 41 def run(self): 42 paths, _ = QFileDialog.getOpenFileNames( 43 self.iface.mainWindow(), 44 'Select TEM XYZ files', 45 '', 46 'XYZ files (*.xyz);;All files (*)', 47 ) 48 failed = [] 49 for path in paths: 50 filepath = Path(path) 51 try: 52 self._load_xyz(filepath) 53 except Exception as exc: 54 failed.append(f'{filepath.name}: {exc}') 55 if failed: 56 QMessageBox.warning( 57 self.iface.mainWindow(), 58 'TEM Loader', 59 '\n'.join(failed), 60 ) 61 62 def _load_xyz(self, filepath): 63 points, doi_points, layers = core.process_xyz(filepath) 64 pts_csv = core.write_csv(points, filepath, '.points.csv') 65 doi_csv = core.write_csv(doi_points, filepath, '.doi.csv') 66 lyr_csv = core.write_csv(layers, filepath, '.layers.csv') 67 68 project = QgsProject.instance() 69 crs = None 70 source_epsg = core.detect_source_epsg(filepath) 71 if source_epsg: 72 candidate = QgsCoordinateReferenceSystem() 73 if candidate.createFromString(source_epsg) and candidate.isValid(): 74 crs = candidate 75 76 if crs is None: 77 crs = project.crs() 78 if not crs.isValid(): 79 crs = QgsCoordinateReferenceSystem() 80 crs.createFromString('EPSG:4326') 81 crs_str = crs.authid() 82 83 loaded_layers = {} 84 source_layers = [ 85 ('layers', lyr_csv, 'LineString'), 86 ('doi', doi_csv, 'Point'), 87 ('points', pts_csv, 'Point'), 88 ] 89 for name, csv_path, geom_type in source_layers: 90 uri = _build_delimited_text_uri(csv_path, geom_type, crs_str) 91 layer = QgsVectorLayer(uri, name, 'delimitedtext') 92 if not layer.isValid(): 93 continue 94 95 qml = STYLES_DIR / f'{name}.qml' 96 if qml.exists(): 97 layer.loadNamedStyle(str(qml)) 98 99 project.addMapLayer(layer, False) 100 loaded_layers[name] = layer 101 102 if not loaded_layers: 103 raise ValueError('failed to load any layers') 104 105 group_name = filepath.stem 106 root = project.layerTreeRoot() 107 group = root.insertGroup(0, group_name) 108 insert_index = 0 109 for name in ('points', 'doi', 'layers'): 110 layer = loaded_layers.get(name) 111 if layer is None: 112 continue 113 group.insertLayer(insert_index, layer) 114 insert_index += 1 115 116 failed = [name for name, _, _ in source_layers if name not in loaded_layers] 117 if failed: 118 QMessageBox.warning( 119 self.iface.mainWindow(), 120 'TEM Loader', 121 f'{filepath.name}: failed to load layers: {", ".join(failed)}', 122 )