diff --git a/Data/Z510/.xtherion.dat b/Data/Z510/.xtherion.dat index bb02502..d411946 100644 --- a/Data/Z510/.xtherion.dat +++ b/Data/Z510/.xtherion.dat @@ -11,5 +11,5 @@ xth_cp_map_tree_insert map 1 948X1 p2 1 MC-Z510-coupe-tot MC-Z510-coupe-tot@Z510 xth_cp_map_tree_create xth_cp_comp_stat 742 14 set xth(th_exit_state) 1 -set xth(th_exit_number) 1746719589 +set xth(th_exit_number) 1750235501 diff --git a/Data/Z510/Outputs/Z510.3d b/Data/Z510/Outputs/Z510.3d index 899ba0a..0c3e4ae 100644 Binary files a/Data/Z510/Outputs/Z510.3d and b/Data/Z510/Outputs/Z510.3d differ diff --git a/Data/Z510/therion.log b/Data/Z510/therion.log index 6c7ff99..990cce8 100644 --- a/Data/Z510/therion.log +++ b/Data/Z510/therion.log @@ -20,8 +20,8 @@ searching for centerline loops ... done calculating station coordinates ... done processing survey data ... ####################### cavern log file ######################## - 1> Survex 1.4.15 - 2> Copyright ¸ 1990-2024 Olly Betts + 1> Survex 1.4.17 + 2> Copyright ¸ 1990-2025 Olly Betts 3> 4> La topographie contient 574 stations, connect‚es par 573 vis‚es. 5> Il y a 0 bouclages. @@ -31,48 +31,12 @@ processing survey data ... 9> Intervalle vertical = 238.38m (de 34 … 1644.00m jusqu'… 223 … 1405.62m) 10> Intervalle Nord-Sud = 70.50m (de 34 … 4758093.00m jusqu'… 293 … 4758022.50m) 11> Intervalle Est-Ouest = 60.84m (de 40 … 679299.28m jusqu'… 293 … 679238.44m) -12> 425 1-noeuds. -13> 79 2-noeuds. -14> 9 3-noeuds. -15> 1 4-noeud. -16> 5 5-noeuds. -17> 29 6-noeuds. -18> 1 7-noeud. -19> 1 9-noeud. -20> 3 10-noeuds. -21> 4 11-noeuds. -22> 3 12-noeuds. -23> 5 13-noeuds. -24> 3 14-noeuds. -25> 2 15-noeuds. -26> 1 16-noeud. -27> 1 17-noeud. -28> 1 18-noeud. -29> 1 19-noeud. -30> +12> ######################### transcription ######################## 4> 574 : .@Z510.Z510 -- 573 : 2024.23@Z510.Z510 9> 34 : Z_510@Z510.Z510 -- 223 : .@Z510.Z510 10> 34 : Z_510@Z510.Z510 -- 293 : .@Z510.Z510 11> 40 : 8.2@Z510.Z510 -- 293 : .@Z510.Z510 -12> 425 : .@Z510.Z510 -13> 79 : 10.3@Z510.Z510 -14> 9 : 4.2@Z510.Z510 -15> 1 : 0@Z510.Z510 -16> 5 : 3.0@Z510.Z510 -17> 29 : 1.9@Z510.Z510 -18> 1 : 0@Z510.Z510 -19> 1 : 0@Z510.Z510 -20> 3 : 2.0@Z510.Z510 -21> 4 : 2.1@Z510.Z510 -22> 3 : 2.0@Z510.Z510 -23> 5 : 3.0@Z510.Z510 -24> 3 : 2.0@Z510.Z510 -25> 2 : 0d@Z510.Z510 -26> 1 : 0@Z510.Z510 -27> 1 : 0@Z510.Z510 -28> 1 : 0@Z510.Z510 -29> 1 : 0@Z510.Z510 #################### end of cavern log file #################### done calculating basic statistics ... done @@ -91,7 +55,7 @@ processing projection extended ... done average distortion: 0.02% done ####################### metapost log file ######################## -This is MetaPost, version 2.01 (TeX Live 2021/W32TeX) (kpathsea version 6.3.3) 8 MAY 2025 17:53 +This is MetaPost, version 2.01 (TeX Live 2021/W32TeX) (kpathsea version 6.3.3) 18 JUN 2025 10:31 **data.mp (c:/Program Files/Therion/texmf/mpost/mpost.mp (c:/Program Files/Therion/texmf/mpost/plain.mp @@ -113,7 +77,7 @@ writing Outputs/Z510-Surveys.kml ... C:\Program Files\Therion\therion.exe: warning -- geographical reference is not associated with table done writing xtherion file ... done -compilation time: 1 sec +compilation time: 0 sec ###################### scrap distortions ####################### diff --git a/Scripts/pyCreateTh.log b/Scripts/pyCreateTh.log index d5c0a46..a3f2d68 100644 --- a/Scripts/pyCreateTh.log +++ b/Scripts/pyCreateTh.log @@ -63,3 +63,29 @@ 2025-06-16 21:47:56,152 - INFO - ******************************************************************************************************************************************** 2025-06-16 21:47:56,153 - ERROR - !!! file not yet supported 2025-06-16 21:47:56,154 - ERROR - !!! There were 1 errors during 3.19 secondes, check the log file ~\..\pyCreateTh.log +2025-06-17 18:45:15,108 - INFO - ******************************************************************************************************************************************** +2025-06-17 18:45:15,108 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders +2025-06-17 18:45:15,109 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr +2025-06-17 18:45:15,109 - INFO - * Version : 2025.06.17 +2025-06-17 18:45:15,109 - INFO - * Input file : +2025-06-17 18:45:15,109 - INFO - * Output file : ~\. +2025-06-17 18:45:15,110 - INFO - * Log file : ~\..\pyCreateTh.log +2025-06-17 18:45:15,110 - INFO - * +2025-06-17 18:45:15,110 - INFO - * +2025-06-17 18:45:15,110 - INFO - * +2025-06-17 18:45:15,111 - INFO - ******************************************************************************************************************************************** +2025-06-17 18:45:15,112 - ERROR - !!! file not yet supported +2025-06-17 18:45:15,112 - ERROR - !!! There were 1 errors during 3.06 secondes, check the log file ~\..\pyCreateTh.log +2025-06-18 21:39:26,689 - INFO - ******************************************************************************************************************************************** +2025-06-18 21:39:26,689 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders +2025-06-18 21:39:26,690 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr +2025-06-18 21:39:26,690 - INFO - * Version : 2025.06.18 +2025-06-18 21:39:26,690 - INFO - * Input file : +2025-06-18 21:39:26,690 - INFO - * Output file : ~\. +2025-06-18 21:39:26,690 - INFO - * Log file : ~\..\pyCreateTh.log +2025-06-18 21:39:26,690 - INFO - * +2025-06-18 21:39:26,691 - INFO - * +2025-06-18 21:39:26,691 - INFO - * +2025-06-18 21:39:26,691 - INFO - ******************************************************************************************************************************************** +2025-06-18 21:39:26,692 - ERROR - !!! file not yet supported +2025-06-18 21:39:26,692 - ERROR - !!! There were 1 errors during 32.63 secondes, check the log file ~\..\pyCreateTh.log diff --git a/Scripts/pyCreateTh/.vscode/settings.json b/Scripts/pyCreateTh/.vscode/settings.json index 4bd4435..e8b38ab 100644 --- a/Scripts/pyCreateTh/.vscode/settings.json +++ b/Scripts/pyCreateTh/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "annee", "ansi", + "ARSIP", "australiangeodetic", "australiangeodeticdatum", "backclino", @@ -14,6 +15,7 @@ "cumcount", "datat", "depmatch", + "depthchange", "depthre", "downcasting", "drawnexemptextendedre", @@ -36,6 +38,7 @@ "Geophysicaya", "isin", "Koef", + "Larra", "lengthre", "lenmatch", "levelname", diff --git a/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc index 16cbff4..c80dd62 100644 Binary files a/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc and b/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/__pycache__/logger_config.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/logger_config.cpython-313.pyc index 2a97b99..4ff4cde 100644 Binary files a/Scripts/pyCreateTh/Lib/__pycache__/logger_config.cpython-313.pyc and b/Scripts/pyCreateTh/Lib/__pycache__/logger_config.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc index 3fabb02..3cc6dff 100644 Binary files a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc and b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/global_data.py b/Scripts/pyCreateTh/Lib/global_data.py index 70a8168..fa9e4d1 100644 --- a/Scripts/pyCreateTh/Lib/global_data.py +++ b/Scripts/pyCreateTh/Lib/global_data.py @@ -1,25 +1,142 @@ -## Global data for pyCreateTh.py +""" +############################################################################################# +global_data.py for pyCreateTh.py +############################################################################################# +""" -# # [Survey_Data] default values -# Author = "Created by pyCreateTh.py" -# Copyright = "# Copyright (C) pyCreateTh.py" -# Copyright_Short = "Licence (C) pyCreateTh.py" -# map_comment = "Created by pyCreateTh.py" -# cs = "UTM30" -# club = "Therion" -# thanksto = "Therion" -# datat = "https://therion.speleo.sk/" -# wpage = "https://therion.speleo.sk/" +################################################################################################# -# ## [Application_data] default values -# template_path = "./Template" -# station_by_scrap = 20 -# final_therion_exe = True -# therion_path = "C:/Therion/therion.exe" -# LINES = -1 -# NAMES = -1 -# configIni = "config.ini" # Default config file name -# debug_log = False # Mode debug des messages -error_count = 0 # Compteur d'erreurs \ No newline at end of file +error_count = 0 # Compteur d'erreurs + +################################################################################################# +thFileDat = """ +encoding utf-8 +# File generated by pyCreateTh.py version {VERSION} date: {DATE} + +survey {SURVEY_NAME} -title "{COMMENT}" +\tcenterline +\t\tdate {SURVEY_DATE} +\t\t# team "{SURVEY_TEAM}" +{FIX_POINTS} + +\t\t# explo-date "{EXPLO_DATE}" +\t\t# explo-team "{EXPLO_TEAM}" + +\t\tunits {LENGTH} +\t\tunits {COMPASS} +\t\tunits {CLINO} +\t\t{DATA_FORMAT} + +\t#{DATA} + +\tendcenterline +endsurvey + +{SOURCE} +""" + +################################################################################################# +thconfigTemplate = """ +source "{th_file}" +layout minimal +scale 1 {scale} +endlayout + +select {selector} + +#export model -o "{th_name}.lox" +export map -projection plan -o "{th_name}-Plan.xvi" -layout minimal -layout-debug station-names +export map -projection extended -o "{th_name}-Extended.xvi" -layout minimal -layout-debug station-names +""" + +################################################################################################# +th2FileHeader = """encoding utf-8""" + +th2File = """ +##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max} +##XTHERION## xth_me_area_zoom_to 100 +##XTHERION## xth_me_image_insert {insert_XVI} + +{Copyright} +# File generated by pyCreateTh.py version {version} date: {date} + +# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min} +# y_min: {Y_Min}, y_max: {Y_Max} ecart : {Y_Max_Y_Min} + +scrap S{projection_short}-{name}_01 -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" + +{points} + +{names} + +{lines} + +endscrap +""" + +th2Point = """ point {x} {y} station -name {station}""" +th2Name = """ point {x} {y} station-name -align tr -scale xs -text {station}""" + +th2Line = """ +line u:Shot_Survey + {x1} {y1} + {x2} {y2} +endline +""" + +th2Scrap = """ + +scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" + +endscrap +""" + +################################################################################################# +datumToEPSG = { + # Datums globaux + "wgs84": "326", # UTM Nord (WGS84) - EPSG:326XX + "etrs89": "258", # UTM Nord (ETRS89) - Europe + + # Datums europĂ©ens + "european1950": "230", # ED50 / UTM Nord - Europe + "ed50": "230", + + # Datums nord-amĂ©ricains + "nad27": "267", # UTM Nord (NAD27) - AmĂ©rique du Nord + "northamericandatum1927": "267", + "northamerican1927": "267", + "nad83": "269", # UTM Nord (NAD83) - AmĂ©rique du Nord + "northamericandatum1983": "269", + "northamerican1983" : "269", + + # Datums français + "ntf": "275", # UTM Nord (NTF) - France (Paris) + "nouvelletriangulationfrançaise": "275", + + # Datums africains + "clarke1880": "297", # UTM Nord (Clarke 1880) - Afrique + + # Datums australiens + "agd66": "202", # UTM Nord (AGD66) - Australie + "australiangeodeticdatum1966": "202", + "australiangeodetic1966": "202", + "agd84": "203", # UTM Nord (AGD84) - Australie + "australiangeodeticdatum1984": "203", + "australiangeodetic1984": "203", + "gda94": "283", # UTM Nord (GDA94) - Australie + "geocentricdatumofaustralia1994": "283", + "geocentricofaustralia1994": "283", + + # Datums asiatiques + "pulkovo1942": "284", # UTM Nord (Pulkovo 1942) - Russie/CEI + "beijing1954": "214", # UTM Nord (Beijing 1954) - Chine + + # Datums sud-amĂ©ricains + "sad69": "291", # UTM Nord (SAD69) - AmĂ©rique du Sud + "southamericandatum1969": "291", + "southamerican1969": "291", + "sirgas2000": "319", # UTM Nord (SIRGAS 2000) - AmĂ©rique Latine +} + \ No newline at end of file diff --git a/Scripts/pyCreateTh/Lib/logger_config.py b/Scripts/pyCreateTh/Lib/logger_config.py index 6889f51..606325d 100644 --- a/Scripts/pyCreateTh/Lib/logger_config.py +++ b/Scripts/pyCreateTh/Lib/logger_config.py @@ -1,8 +1,15 @@ +""" +############################################################################################# +logger_config.py for pyCreateTh.py +############################################################################################# +""" import logging import sys import re +################################################################################################# # Couleurs ANSI par niveau de log +################################################################################################# COLOR_CODES = { logging.DEBUG: "\033[94m", # Bleu logging.INFO: "\033[92m", # Vert @@ -12,19 +19,25 @@ COLOR_CODES = { } RESET = "\033[0m" +################################################################################################# # Supprime les codes ANSI (pour l'Ă©criture dans les fichiers) +################################################################################################# def strip_ansi_codes(text): ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') return ansi_escape.sub('', text) +################################################################################################# # Formatter pour la console avec couleurs +################################################################################################# class ConsoleFormatter(logging.Formatter): def format(self, record): color = COLOR_CODES.get(record.levelno, "") message = super().format(record) return f"{color}{message}{RESET}" +################################################################################################# # Formatter pour le fichier avec "!!!" sur les erreurs +################################################################################################# class FileFormatter(logging.Formatter): def format(self, record): clean_msg = strip_ansi_codes(record.getMessage()) @@ -41,8 +54,11 @@ class FileFormatter(logging.Formatter): sinfo=record.stack_info ) return super().format(record_copy) - + + +################################################################################################# # Fonction de configuration du logger +################################################################################################# def setup_logger(logfile="app.log", debug_log=False): logger = logging.getLogger("Logger") logger.setLevel(logging.DEBUG) diff --git a/Scripts/pyCreateTh/Lib/therion.py b/Scripts/pyCreateTh/Lib/therion.py index 25a5c18..16688d1 100644 --- a/Scripts/pyCreateTh/Lib/therion.py +++ b/Scripts/pyCreateTh/Lib/therion.py @@ -1,3 +1,9 @@ +""" +############################################################################################# +therion.py for pyCreateTh.py +############################################################################################# +""" + import tempfile import shutil import os @@ -48,7 +54,7 @@ def safe_relpath(path): return valeur except ValueError: - max_depth = 6 # Profondeur maximale pour tronquer le chemin + max_depth = 4 # Profondeur maximale pour tronquer le chemin # Disques diffĂ©rents, afficher le chemin relatif partiel depuis la racine commune path_parts = abs_path.split(os.sep) @@ -103,7 +109,6 @@ def compile_templateOld(template, template_args, **kwargs): # Compiler une configuration gĂ©nĂ©rĂ©e dynamiquement Ă  partir d'un template texte. # ################################################################################################# def compile_template(template, template_args, **kwargs): - logfile = "" tmpdir = None try: @@ -117,7 +122,6 @@ def compile_template(template, template_args, **kwargs): therion_path = kwargs.get("therion_path", "therion") - # Écriture des fichiers config + log with open(config_file, "w", encoding="utf-8") as tmp: tmp.write(config) tmp.flush() @@ -125,14 +129,15 @@ def compile_template(template, template_args, **kwargs): # ExĂ©cution de Therion result = subprocess.run( [therion_path, config_file, "-l", log_file], + stdin=subprocess.DEVNULL, # Évite toute attente d'entrĂ©e clavier stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, # DĂ©code automatiquement en UTF-8 (avec fallback ci-dessous) + text=True, timeout=kwargs.get("timeout", 30), - errors="replace" # Remplace caractères invalides (Ă©vite UnicodeDecodeError) + errors="replace" ) - # Lecture du log (en mode tolĂ©rant) + # Lecture du fichier log try: with open(log_file, "r", encoding="cp1252", errors="replace") as f: logfile = f.read() @@ -140,23 +145,24 @@ def compile_template(template, template_args, **kwargs): log.warning(f"Could not read Therion log: {Colors.ENDC}{log_err}") # Analyse du code retour - if result.returncode != 0: - log.error(f"Therion compilation failed with return code: {Colors.ENDC}{result.returncode} {Colors.ERROR}{result.stdout}") + if result.returncode != 0 or "press any key" in result.stdout.lower(): + log.error(f"Therion compilation failed with return code: {Colors.ENDC}{result.returncode}\n{Colors.WHITE}{result.stdout}") global_data.error_count += 1 - - else: - log.info(f"Therion compilation successful") + return "Therion error", tmpdir + stat = get_stats_from_log(logfile) + + log.info(f"Therion compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m") return logfile, tmpdir except subprocess.TimeoutExpired: - log.error(f"Therion process timed out and was terminated {Colors.ENDC}{logfile}") + log.error(f"Therion process timed out and was terminated : {Colors.ENDC}{logfile}") global_data.error_count += 1 return "Therion error", tmpdir except Exception as e: log.error(f"Therion template compilation error: {Colors.ENDC}{e}") - global_data.error_count += 1 + global_data.error_count += 1 return "Therion error", tmpdir finally: @@ -166,54 +172,7 @@ def compile_template(template, template_args, **kwargs): except Exception as cleanup_err: log.warning(f"Could not delete temp directory: {Colors.ENDC}{cleanup_err}") - -################################################################################################# -# Compilation Therion (version avec blocage) # -# Compiler directement un fichier .th dĂ©jĂ  existant avec Therion. -################################################################################################# -def compile_fileOld(filename, **kwargs): - - try: - tmpdir = os.path.dirname(filename) - log_file = join(tmpdir, "therion.log").replace("\\", "/") - therion_path = kwargs["therion_path"] if "therion_path" in kwargs else "therion" - - process = subprocess.Popen( - [therion_path, filename, "-l", log_file], - cwd=tmpdir, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, # fusion stdout + stderr - universal_newlines=True, # dĂ©codage automatique en texte - bufsize=1 # ligne par ligne - ) - - log.info(f"Start therion compilation file : {Colors.ENDC}{safe_relpath(filename)}") - # Lecture en temps rĂ©el - for line in process.stdout: - line = line.rstrip() - lower_line = line.lower() - if "error" in lower_line: - log.error(f" [Therion_Compile] {Colors.ENDC}{line}") - elif "warning" in lower_line: - log.warning(f" [Therion_Compile] {Colors.ENDC}{line}") - else: - log.debug(f" [Therion_Compile] {Colors.ENDC}{line}") - - process.wait() - - # Si la commande Ă©choue, result.returncode sera non nul - if process.returncode != 0: - # Affichage des erreurs et de la sortie standard - log.error(f"Error during Therion compilation, stderr : \n{Colors.ENDC}{process.stderr.decode()}") - global_data.error_count += 1 - - log.info(f"Therion file : {Colors.ENDC}{safe_relpath(filename)}{Colors.GREEN} succeeded") - - except Exception as e: - log.error(f"Therion file {Colors.ENDC}{safe_relpath(filename, os.path.expanduser('~'))}{Colors.ERROR} compilation error: {Colors.ENDC}{e}") - global_data.error_count += 1 - - + ################################################################################################# # Compilation Therion (version sans blocage) # ################################################################################################# @@ -243,12 +202,14 @@ def compile_file(filename, **kwargs): for line in proc.stdout: line = line.rstrip() lower_line = line.lower() - if "error" in lower_line: - log.error(f"[Therion_Compile] {Colors.ENDC}{line}") + if "average loop error" in lower_line: + log.warning(f"[Therion_Compile] {Colors.ENDC}{line}") + elif "error" in lower_line: + log.error(f"[Therion_Compile] {Colors.ENDC}{line}") elif "warning" in lower_line: - log.warning(f" [Therion_Compile] {Colors.ENDC}{line}") + log.warning(f"[Therion_Compile] {Colors.ENDC}{line}") else: - log.debug(f" [Therion_Compile] {Colors.ENDC}{line}") + log.debug(f"[Therion_Compile] {Colors.ENDC}{line}") except Exception as e: log.warning(f"Reading Therion output: {Colors.ENDC}{e}") @@ -283,7 +244,7 @@ def compile_file(filename, **kwargs): def compile_file_th(filepath, **kwargs): template = """source {filepath} layout test - scale 1 500 + scale 1 100 endlayout """ template_args = {"filepath": filepath} @@ -295,8 +256,6 @@ def compile_file_th(filepath, **kwargs): lengthre = re.compile(r".*Longueur totale de la topographie = \s*(\S+)m") depthre = re.compile(r".*Longueur totale verticale =\s*(\S+)m") - -################################################################################################# def get_stats_from_log(log): lenmatch = lengthre.findall(log) depmatch = depthre.findall(log) @@ -309,7 +268,6 @@ def get_stats_from_log(log): syscoord = re.compile(r".*output coordinate system: \s*(\S+)") -################################################################################################# def get_syscoord_from_log(log): lenmatch = syscoord.findall(log) diff --git a/Scripts/pyCreateTh/Template/config.thc b/Scripts/pyCreateTh/Template/config.thc index 6281e94..c4f504f 100644 --- a/Scripts/pyCreateTh/Template/config.thc +++ b/Scripts/pyCreateTh/Template/config.thc @@ -1,10 +1,9 @@ encoding utf-8 ###################################################################################################################################### -# Version pyCreate_th2.py By Alex 2025 01 02 +# Version pyCreateTh.py By Alex MĂ J 2025 01 02 ###################################################################################################################################### - ###################################################################################################################################### # Licence ###################################################################################################################################### diff --git a/Scripts/pyCreateTh/Template/template-maps.th b/Scripts/pyCreateTh/Template/template-maps.th index 09edaa1..13f8579 100644 --- a/Scripts/pyCreateTh/Template/template-maps.th +++ b/Scripts/pyCreateTh/Template/template-maps.th @@ -3,11 +3,11 @@ encoding utf-8 {Copyright} -map MP-{fileName}-Plan-tot -title "{fileName}" +map MP-{fileName}-Plan-tot -title "{caveName}" {other_scraps_plan} endmap -map MC-{fileName}-Extended-tot -title "{fileName}" +map MC-{fileName}-Extended-tot -title "{caveName}" {other_scraps_extended} endmap diff --git a/Scripts/pyCreateTh/Template/template-readme.md b/Scripts/pyCreateTh/Template/template-readme.md index ce3859e..ec4bf00 100644 --- a/Scripts/pyCreateTh/Template/template-readme.md +++ b/Scripts/pyCreateTh/Template/template-readme.md @@ -1,9 +1,14 @@ -encoding utf-8 {file_info} {Copyright} -to add this survey in a main survey add in your -tot.th file: -input Data/{fileName}/{fileName}-tot.th -equate +# Fix point list +{fixPointList} + +# Survey list : +{readMeList} + + +# Error list : +{errorList} \ No newline at end of file diff --git a/Scripts/pyCreateTh/Template/template-tot.th b/Scripts/pyCreateTh/Template/template-tot.th index e8ed83a..8a7dc63 100644 --- a/Scripts/pyCreateTh/Template/template-tot.th +++ b/Scripts/pyCreateTh/Template/template-tot.th @@ -3,6 +3,6 @@ encoding utf-8 {Copyright} -survey {fileName} -title "{fileName}" +survey {fileName} -title "{caveName}" {totData} endsurvey diff --git a/Scripts/pyCreateTh/Template/template.thconfig b/Scripts/pyCreateTh/Template/template.thconfig index 7c2a7ef..c25c798 100644 --- a/Scripts/pyCreateTh/Template/template.thconfig +++ b/Scripts/pyCreateTh/Template/template.thconfig @@ -44,19 +44,6 @@ input {configPath}config.thc ## Ici, on peut specifier des choses comme les symboles Ă  utiliser (UIS, etc) ## ou imprimer des explications des symboles -## DĂ©but de la dĂ©finition du Layout "xviexport" -layout xviexport - #cs UTM32 - ## echelle Ă  laquelle on veut dessiner la topo - scale 1 {Scale} - #scale 1 1000 - ## taille de la grille - grid-size 2 2 2 m - ## mettre la grille en arrière plan - grid bottom -endlayout -## fin de la dĂ©finition du layout "xviexport" - ## DĂ©but de la dĂ©finition du layout "Layout-Plan" layout layout-Plan ## Call the config settings (Layout config inside the config.thc file) @@ -103,7 +90,7 @@ layout layout-Plan ## Couleurs de la topographie #colour map-bg [70 90 70] - #colour map-fg [100 100 80] + #colour map-fg [100 100 80] #colour map-fg altitude #colour map-fg explo-date #colour map-fg topo-date @@ -120,9 +107,9 @@ layout layout-Plan ## Auteur doc-author "{Author}" ## Titre - doc-title "{cavename} Plan - 1:{Scale}" - doc-subject "{cavename}, topographie en plan" - doc-keywords "Cave, Survey, {cavename}, Pierre saint Martin - Larra, {map_comment}" + doc-title "{caveName} Plan - 1:{Scale}" + doc-subject "{caveName}, topographie en plan" + doc-keywords "Cave, Survey, {caveName}, {mapComment}" ## Maintenant on spĂ©cifie la position de la manchette, dont l'intĂ©rieur est occupĂ© par le titre, auteurs, etc. ## Nous pouvons indiquer les cordonnĂ©es du point de la topo ou l'on veut la manchette : @@ -144,8 +131,8 @@ layout layout-Plan legend-columns 2 ## Un commentaire Ă  ajouter au titre, on pourrait indiquer ici la mairie oĂą est placĂ©e la cavitĂ© ## dont le nom est probablement le titre de la topo. - map-comment "{map_comment}" - #map-comment "{map_comment}
Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m" + map-comment "{mapComment}" + #map-comment "{mapComment}
Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m" ## Afficher les statistiques d'explo/topo par équipe/nom. C'est lourd ## si la cavité est importante et qu'il y a beaucoup d'explorateurs/topographes. @@ -159,7 +146,7 @@ layout layout-Plan # symbol-hide point station # symbol-hide line survey # symbol-hide group - # symbol-show line wall + # symbol-show line wall # symbol-hide point station-name # symbol-hide point u:symbol_plan # symbol-hide point u:symbol_extend @@ -176,19 +163,19 @@ layout layout-Plan \legendtextheadersize={\size[28]} %%% Taille du titre \legendtextsectionsize={\size[14]} %%% Taille du titre %\legendtextcolor={\color[0 0 110]} %# RGB values 0--100 - % Output map title as determined by Therion is stored in cavename, défini par la une Map. + % Output map title as determined by Therion is stored in caveName, défini par la une Map. % It will be empty if there are multiple maps selected for any one projection % AND there are multiple source surveys identified in the thconfig file % ie Therion can not infer a unique title from the input data given. - % This code allows you to define an output map title {cavename} if it happens to be empty - \edef\temp{\the\cavename} % cavename from Therion + % This code allows you to define an output map title {caveName} if it happens to be empty + \edef\temp{\the\caveName} % caveName from Therion \edef\nostring{} % empty string - \ifx\temp\nostring % test if cavename is empty + \ifx\temp\nostring % test if caveName is empty % if empty - reassign cavename to describe selected maps as a group - \else % if not empty keep the value set by therion, or assign an override cavename here + reassign caveName to describe selected maps as a group + \else % if not empty keep the value set by therion, or assign an override caveName here \fi - \cavename={{cavename}, Plan 1:{Scale}} % Note Alex : Bug avec certains fichiers ? + \caveName={{caveName}, Plan 1:{Scale}} % Note Alex : Bug avec certains fichiers ? \newtoks\club \club={{club}} %\newtoks\thanksto \thanksto={{thanksto}} \newtoks\wpage \wpage={{wpage}} @@ -198,6 +185,7 @@ layout layout-Plan endcode endlayout +## fin de la définition du layout ##debut de la definition du layout "layout-Extended" layout layout-Extended @@ -244,7 +232,7 @@ layout layout-Extended ## Couleurs de la topographie #colour map-bg [70 90 70] - #colour map-fg [100 100 80] + #colour map-fg [100 100 80] #colour map-fg altitude #colour map-fg explo-date #colour map-fg topo-date @@ -261,10 +249,10 @@ layout layout-Extended ## Auteur doc-author "{Author}" ## Titre - doc-title "{cavename} Coupe développée - 1:{Scale}" + doc-title "{caveName} Coupe développée - 1:{Scale}" - doc-subject "{cavename}, topographie en coupe développée" - doc-keywords "Cave, Survey, {cavename}, Pierre saint Martin - Larra, Coupe développée, {map_comment}" + doc-subject "{caveName}, topographie en coupe développée" + doc-keywords "Cave, Survey, {caveName}, {mapComment}" ## Maintenant on spécifie la position de la manchette, dont l'intérieur est occupé par le titre, auteurs, etc. ## Nous pouvons indiquer les cordonnées du point de la topo ou l'on veut la manchette : @@ -285,8 +273,8 @@ layout layout-Extended legend-columns 2 ## Un commentaire à ajouter au titre, on pourrait indiquer ici la mairie où est placée la cavité ## dont le nom est probablement le titre de la topo. - map-comment "{map_comment}" - #map-comment "{map_comment}
Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m" + map-comment "{mapComment}" + #map-comment "{mapComment}
Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m" ## Afficher les statistiques d'explo/topo par équipe/nom. C'est lourd ## si la cavité est importante et qu'il y a beaucoup d'explorateurs/topographes. @@ -300,7 +288,7 @@ layout layout-Extended # symbol-hide point station # symbol-hide line survey # symbol-hide group - # symbol-show line wall + # symbol-show line wall # symbol-hide point u:symbol_plan # symbol-hide point u:symbol_extend # debug scrap-names @@ -317,19 +305,19 @@ layout layout-Extended \legendtextheadersize={\size[28]} %%% Taille du titre \legendtextsectionsize={\size[14]} %%% Taille du titre %\legendtextcolor={\color[0 0 110]} %# RGB values 0--100 - % Output map title as determined by Therion is stored in cavename, défini par la une Map. + % Output map title as determined by Therion is stored in caveName, défini par la une Map. % It will be empty if there are multiple maps selected for any one projection % AND there are multiple source surveys identified in the thconfig file % ie Therion can not infer a unique title from the input data given. - % This code allows you to define an output map title {cavename} if it happens to be empty - \edef\temp{\the\cavename} % cavename from Therion + % This code allows you to define an output map title {caveName} if it happens to be empty + \edef\temp{\the\caveName} % caveName from Therion \edef\nostring{} % empty string - \ifx\temp\nostring % test if cavename is empty + \ifx\temp\nostring % test if caveName is empty % if empty - reassign cavename to describe selected maps as a group - \else % if not empty keep the value set by therion, or assign an override cavename here + reassign caveName to describe selected maps as a group + \else % if not empty keep the value set by therion, or assign an override caveName here \fi - \cavename={{cavename}, Coupe développée 1:{Scale}} % Note Alex : Bug avec certains fichiers ? + \caveName={{caveName}, Coupe développée 1:{Scale}} % Note Alex : Bug avec certains fichiers ? \newtoks\club \club={{club}} %\newtoks\thanksto \thanksto={{thanksto}} \newtoks\wpage \wpage={{wpage}} @@ -339,8 +327,9 @@ layout layout-Extended endcode endlayout -## Fin de la definition du Layout "normal" +## Fin de la definition du Layout +## Début de la définition du Layout "layout-kml" layout layout-kml ## Définition du système de projection du plan cs EPSG:2154 @@ -352,39 +341,56 @@ layout layout-kml color map-fg [0 0 100] endlayout +## Début de la définition du Layout "xviexport" +layout xviexport + # cs UTM32 + ## echelle à laquelle on veut dessiner la topo + scale 1 {Scale} + # scale 1 1000 + ## taille de la grille + grid-size 2 2 2 m + ## mettre la grille en arrière plan + grid bottom +endlayout +## fin de la définition du layout + ############################################################################################### # 3-EXPORT ############################################################################################### - ## Export des xvi pour le dessin si besoin - # export map -proj plan -layout xviexport -fmt xvi -o Data/{fileName}-Plan.xvi - # export map -proj extended -layout xviexport -fmt xvi -o Data/{fileName}-Extended.xvi + ## Export des xvi pour le dessin si besoin + # export map -proj plan -layout xviexport -fmt xvi -o Data/{fileName}-Plan.xvi + # export map -proj extended -layout xviexport -fmt xvi -o Data/{fileName}-Extended.xvi - ## Selection des Maps à exporter - # select MP-{fileName}-Plan-tot@{fileName} - # select MC-{fileName}-Extended-tot@{fileName} + ## Selection des Maps à exporter + # select MP-{fileName}-Plan-tot@{fileName} + # select MC-{fileName}-Extended-tot@{fileName} - ## Export des fichiers pdf, plan et coupe. - ## ATTENTION, la topo étant énorme, il faut mettre l'option ne traçant pas la centerline ! + ## Export des fichiers pdf, plan et coupe. + ## ATTENTION, la topo étant énorme, il faut mettre l'option ne traçant pas la centerline ! + # export map -projection plan -fmt pdf -layout layout-Plan -o Outputs/{fileName}-Plan.pdf + # export map -projection extended -fmt pdf -layout layout-Extended -o Outputs/{fileName}-Extended.pdf - # export map -projection plan -fmt pdf -layout layout-Plan -o Outputs/{fileName}-Plan.pdf - # export map -projection extended -fmt pdf -layout layout-Extended -o Outputs/{fileName}-Extended.pdf + ## Export du fichier 3d pour Loch + export model -enable all -o Outputs/{fileName}.lox + # export model -enable all -o Outputs/{fileName}.kml + # export model -enable all -o Outputs/{fileName}.plt - ## Export du fichier 3d pour Loch - export model -enable all -o Outputs/{fileName}.lox - export model -enable all -o Outputs/{fileName}.kml + ## Export des fichiers ESRI + # export map -proj plan -fmt esri -o Outputs/{fileName} + # export model -fmt esri -o Outputs/SHP/therion -enc UTF-8 - ## Export des fichiers ESRI - # export map -proj plan -fmt esri -o Outputs/{fileName} + ## Autres exports + # export map -proj plan -fmt kml -o Outputs/{fileName}.kml -layout layout-kml + # export model -fmt kml -o Outputs/{fileName}-model.kml -enable all + # export model -enable all -o Outputs/{fileName}-3D.kml + # export cave-list -location on -o Outputs/{fileName}-Cave-list.html + # export survey-list -location on -o Outputs/{fileName}-Surveys.html + # export database -fmt sql -o Outputs/{fileName}-database.sql + # export continuation-list -o Outputs/{fileName}-Continuations.html - ## Export des fichiers kml - # export map -proj plan -fmt kml -o Outputs/{fileName}.kml -layout layout-kml - # export model -fmt kml -o Outputs/{fileName}-model.kml -enable all - # export model -enable all -o Outputs/{fileName}-3D.kml - # export cave-list -location on -o Outputs/{fileName}-Cave-list.html - # export survey-list -location on -o Outputs/{fileName}-Surveys.html ############################################################################################### -## END +## END FILE ############################################################################################### \ No newline at end of file diff --git a/Scripts/pyCreateTh/config.ini b/Scripts/pyCreateTh/config.ini index 15c927f..b1f53d2 100644 --- a/Scripts/pyCreateTh/config.ini +++ b/Scripts/pyCreateTh/config.ini @@ -1,4 +1,4 @@ -# Configuration values for pyCreate_th2.ph +# Configuration values for pyCreateTh.ph [Survey_Data] Author = Alexandre Pont Copyright1 = # Copyright (C) ARSIP 2025 @@ -7,7 +7,7 @@ Copyright3 = # Copyright_Short = Licence CC by-nc-nd : http://creativecommons.org/licenses/by-nc-nd/4.0/ map_comment = Massif de la Pierre Saint Martin - Larra club = ARSIP -thanksto = Merçi à tout le monde +thanksto = Merci à tout le monde datat = https://github.com/Alex38Lyon/Synthese-PSM_LARRA wpage = https://www.arsip.fr/ cs = UTM30 @@ -18,5 +18,5 @@ template_path = ./template station_by_scrap = 30 final_therion_exe = True therion_path = C:\Program Files\Therion\therion.exe -shot_lines_in_th2_files = True +shot_lines_in_th2_files = False station_name_in_th2_files = True diff --git a/Scripts/pyCreateTh/pyCreateTh.py b/Scripts/pyCreateTh/pyCreateTh.py index 7348909..5bf410d 100644 --- a/Scripts/pyCreateTh/pyCreateTh.py +++ b/Scripts/pyCreateTh/pyCreateTh.py @@ -17,34 +17,39 @@ Création Alex le 2025 06 09 : Version 2025 06 16 : Création fonction createThFolders Ajout des fonctions pour mettre en log - Création de la fonction readMakFile + Création de la fonction makToThFile A venir : - gérer les visées orphelines dans une même survey - gérer les updates des th2 files (th, dat, mak) - - raccourcir nom des surveys compilés (ajouter total en commentaire) + - changer le nom des surveys en un numéro de survey classé par date - habillage des th2 files + - reprendre l'option shot lines dans les th2 files pour supprimer les splays - tester les différentes options args. - reprendre les options de la ligne de commande - - mettre au format les minutes en feet - ajouter les commentaires et les déclinaisons dans les th files - organiser la fonction datToTh - - organiser la fonction readMakAtToTh - - organiser la fonction main + - organiser la fonction makToTh + - organiser la fonction createThFolders - mettre en place barres de progression - completer readme avec détail pour retrouver les fichiers - liste et chemin des points fixes - - instructions d'utilisation + - bilan des métrés + - bilan des erreurs + - - trouver une solution pour les team et les clubs manquants - - mettre en template les fichier th et th2 - + - gérer le cas ou il y a 2 SurveyTitle identiques + - alléger les equates --> 1 fois dans le projet + - changer format des noms des fichiers dat (pas le nom de fichier !) + + """ -Version ="2025.06.17" +Version ="2025.06.18" ################################################################################################# ################################################################################################# @@ -66,7 +71,7 @@ from charset_normalizer import from_path from copy import deepcopy from Lib.survey import SurveyLoader, NoSurveysFoundException -from Lib.therion import compile_template, Colors, compile_file, safe_relpath +from Lib.therion import compile_template, Colors, compile_file, safe_relpath, get_stats_from_log from Lib.logger_config import setup_logger import Lib.global_data as global_data @@ -93,9 +98,9 @@ NAMES = -1 configIni = "config.ini" # Default config file name debug_log = False # Mode debug des messages -# global_data.error_count = 0 # Compteur d'erreurs - +################################################################################################# +# Renommage des tableau pdFrame de station # ################################################################################################# @pd.api.extensions.register_series_accessor("stationName") class StationNameAccessor: @@ -105,11 +110,15 @@ class StationNameAccessor: def __call__(self): return ( self._obj - .str.replace('[', '___', regex=False) - .str.replace(']', '_%_', regex=False) - .str.replace('@', '_._', regex=False) + .str.replace('[', '_d_', regex=False) + .str.replace(']', '_f_', regex=False) + .str.replace('@', '_a_', regex=False) + .str.replace(' ', '_e_', regex=False) + .str.replace('p', '_p_', regex=False) ) +################################################################################################# +# Mise au format des noms # ################################################################################################# def sanitize_filename(th_name): """ @@ -122,6 +131,7 @@ def sanitize_filename(th_name): Returns: str: The cleaned and compatible string. + """ # Unicode normalization to replace accented characters with their non-accented equivalents th_name = unicodedata.normalize('NFKD', th_name).encode('ASCII', 'ignore').decode('ASCII') @@ -135,15 +145,27 @@ def sanitize_filename(th_name): th_name = re.sub(r'[^a-zA-Z0-9._-]', '_', th_name) # Keep only allowed chars # Convert to lowercase, then capitalize the first letter - th_name = th_name.lower().capitalize() - - # Avoid empty result - return th_name or "default_filename" - + # th_name = th_name.lower().capitalize() + th_name = th_name.capitalize() + + # Suppression des underscores en début et fin + th_name = th_name.strip('_') + return th_name or "default_filename" # Avoid empty result +################################################################################################# +# Coloration des messages d'aide d'arg # ################################################################################################# def colored_help(parser): + """ + Affiche l'aide colorée pour les arguments de la ligne de commande. + + Args: + parser (argparse.ArgumentParser): Le parseur d'arguments. + Returns: + None + + """ # Captures the help output help_text = parser.format_help() @@ -167,9 +189,18 @@ def colored_help(parser): print(colored_help_text) sys.exit(1) - ################################################################################################# def read_config(config_file): + """ + Lit le fichier de configuration et initialise les variables globales. + + Args: + config_file (str): Le chemin vers le fichier de configuration. + + Returns: + None + + """ global Author global Copyright global Copyright_Short @@ -246,7 +277,7 @@ def copy_template_if_not_exists(template_path, destination_path): if not os.path.exists(destination_path): # If the destination folder does not exist, copy the template shutil.copytree(template_path, destination_path) - log.info(f"The folder '{Colors.ENDC}{template_path}{Colors.GREEN}' has been copied to '{Colors.ENDC}{safe_relpath(destination_path)}") + log.info(f"The folder '{Colors.ENDC}{template_path}{Colors.GREEN}' has been copied to '{Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN}'") else: log.warning(f"The folder '{Colors.ENDC}{safe_relpath(destination_path)}{Colors.WARNING}' already exists. No files were copied.") except Exception as e: @@ -290,7 +321,8 @@ def copy_file_with_copyright(th_file, destination_path, copyright_text): log.error(f"The file .th does not exist {Colors.ENDC}{safe_relpath(th_file)}") global_data.error_count += 1 - +################################################################################################# +# Remplir les template avec les variables vers output_path # # ################################################################################################# def process_template(template_path, variables, output_path): """ @@ -300,6 +332,10 @@ def process_template(template_path, variables, output_path): template_path (str): Path to the original template file variables (dict): Dictionary of variables to replace output_path (str): Path for the new configuration file + + Returns: + None + """ try: @@ -334,7 +370,6 @@ def process_template(template_path, variables, output_path): log.error(f"An error occurred (process_template): {Colors.ENDC}{e}") global_data.error_count += 1 - ################################################################################################# def parse_therion_surveys(file_path): """ @@ -345,6 +380,7 @@ def parse_therion_surveys(file_path): Returns: list: List of survey names + """ survey_names = [] @@ -360,8 +396,7 @@ def parse_therion_surveys(file_path): if line.startswith('survey ') and ' -title ' in line: # Split the line and extract the survey name start_index = line.find('survey ') + len('survey ') - end_index = line.find(' -title ') - + end_index = line.find(' -title ') survey_name = line[start_index:end_index].strip() survey_names.append(survey_name) @@ -380,7 +415,6 @@ def parse_therion_surveys(file_path): return survey_names - ################################################################################################# def str_to_bool(value): """ @@ -395,41 +429,50 @@ def str_to_bool(value): else: raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}") - ################################################################################################# def select_file(): + """ + Ouvre une boite de dialogue tkinter pour sélectionner un fichier. + + Returns: + str: Le chemin complet du fichier sélectionné. + """ # Créer une instance de la fenêtre tkinter root = tk.Tk() + # Cacher la fenêtre principale root.withdraw() + # Afficher la boite de dialogue de sélection de fichier file_path = filedialog.askopenfilename( title="Select your file", filetypes=[("Compatibles files", "*.th *.mak *.dat"), ("TH files", "*.th"), ("DAT files", "*.dat"), ("MAK files", "*.mak"),("All files", "*.*")] ) - # Retourner le chemin complet du fichier sélectionné - return file_path + + + return file_path # Retourner le chemin complet du fichier sélectionné ################################################################################################# # Création des dossiers à partir d'un th file # ################################################################################################# -def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = "th2", SCALE = "500", UPDATE = "", CONFIG_PATH = "") : -#""" -# Entrées : -# ENTRY_FILE : input th file -# PROJECTION : Plan ou Extended (Extended, not yet implanted) -# TARGET : Scrap name if different from 'ENTRY_FILE' name -# FORMAT : Output format, either th2 for producing skeleton for drawing or plt for visualizing in aven/loch", default="th2" -# SCALE : Scale for the th2 exports, default="500" -# UPDATE : Mode update, option th2" update only th2 files, default="" update all data -# -# Sorties : -# Création des dossiers nécessaires d'après dossier 'template' -# Création des fichiers nécessaires : th, th2, -tot.th -# Création des scrap avec stations topo -# -#""" +def createThFolders(ENTRY_FILE, PROJECTION = "All", TARGET = "None", FORMAT = "th2", SCALE = "500", UPDATE = "", CONFIG_PATH = "") : + """ + Création des dossiers et fichiers à partir d'un fichier .th + + Args: + ENTRY_FILE (str): Le chemin vers le fichier .th d'entrée. + PROJECTION (str): Le type de projection (Plan, Extended, All). + TARGET (str): Le nom de la cible (scrap) si différent du nom du fichier d'entrée. + FORMAT (str): Le format de sortie (th2 ou plt). + SCALE (str): L'échelle pour les exports th2. + UPDATE (str): Le mode de mise à jour. + CONFIG_PATH (str): Le chemin vers le fichier de configuration. + + Returns: + True or False + + """ global Author global Copyright global Copyright_Short @@ -447,7 +490,6 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " global NAMES TH_NAME = sanitize_filename(os.path.splitext(os.path.basename(ENTRY_FILE))[0]) - # DEST_PATH = os.path.dirname(args.survey_file) + "/" + TH_NAME DEST_PATH = os.path.dirname(ENTRY_FILE) + "/" + TH_NAME ABS_PATH = os.path.dirname(ENTRY_FILE) @@ -460,7 +502,7 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " log.debug(f"DEST_PATH: {DEST_PATH}") log.debug(f"ABS_PATH: {ABS_PATH}") - if PROJECTION.lower() != "plan" : + if PROJECTION.lower() != "plan" and PROJECTION.lower() != "extended" and PROJECTION.lower() != "all": log.critical(f"Sorry, projection '{Colors.ENDC}{PROJECTION}{Colors.ERROR}' not yet implemented{Colors.ENDC}") exit(1) @@ -473,7 +515,7 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " exit(1) # Normalise name, namespace, key, file path - log.info(f"Parsing survey entry file:\t{Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.info(f"Parsing survey entry file: {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") survey_list = parse_therion_surveys(ENTRY_FILE) # print(survey_list) @@ -483,9 +525,9 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " log.critical(f"Multiple surveys were found, not yet implemented{Colors.ENDC}") exit(1) - TARGET = sanitize_filename(survey_list[0]) + TARGET = survey_list[0] - log.info(f"Parsing survey target:\t{Colors.ENDC}{TARGET}") + log.info(f"Parsing survey target: {Colors.ENDC}{TARGET}") loader = SurveyLoader(ENTRY_FILE) survey = loader.get_survey_by_id(survey_list[0]) @@ -507,8 +549,8 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " DEST_PATH = os.path.dirname(args.survey_file) log.info(f"\t{Colors.BLUE}DEST_PATH: {Colors.ENDC} {DEST_PATH}") log.info(f"\t{Colors.BLUE}ABS_PATH: {Colors.ENDC} {ABS_PATH}") - - + + ################################################################################################# # Copy template folders # ################################################################################################# @@ -516,61 +558,13 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " log.debug(f"Copy template folder and adapte it") copy_template_if_not_exists(template_path, DEST_PATH) copy_file_with_copyright(ENTRY_FILE, DEST_PATH + "/Data", Copyright) + - totdata = f"""\tinput Data/{TH_NAME}.th - -\t## Pour le plan -\tinput Data/{TH_NAME}-Plan.th2 - -\t## Pour la coupe développée -\tinput Data/{TH_NAME}-Extended.th2 - -\t## Appel des maps -\tinput {TH_NAME}-maps.th -""" - - # Adapte templates - config_vars = { - 'fileName': TH_NAME, - 'cavename': TH_NAME.replace("_", " "), - 'Author': Author, - 'Copyright': Copyright, - 'Scale' : SCALE, - 'Target' : TARGET, - 'map_comment' : map_comment, - 'club' : club, - 'thanksto' : thanksto.replace("_", r"\_"), - 'datat' : datat.replace("_", r"\_"), - 'wpage' : wpage.replace("_", r"\_"), - 'cs' : cs, - 'configPath' : CONFIG_PATH, - 'totData' : totdata, - 'other_scraps_plan' : "", - 'file_info' : f'# File generated by pyCreateTh.py (version {Version}) date: {datetime.now().strftime("%Y.%m.%d %H:%M:%S")}', - } - - process_template(DEST_PATH + '/template.thconfig', config_vars, DEST_PATH + '/' + TH_NAME + '.thconfig') - process_template(DEST_PATH + '/template-tot.th', config_vars, DEST_PATH + '/' + TH_NAME + '-tot.th') - process_template(DEST_PATH + '/template-readme.md', config_vars, DEST_PATH + '/readme.md') - - ################################################################################################# # Produce the parsable XVI file # ################################################################################################# - log.info(f"Compiling 2D XVI file: \t{Colors.ENDC}{TH_NAME}") + log.info(f"Compiling 2D XVI file: {Colors.ENDC}{TH_NAME}") - template = """source "{th_file}" - layout minimal - scale 1 {scale} - endlayout - - select {selector} - - #export model -o "{th_name}.lox" - export map -projection plan -o "{th_name}-Plan.xvi" -layout minimal -layout-debug station-names - export map -projection extended -o "{th_name}-Extended.xvi" -layout minimal -layout-debug station-names - """ - if UPDATE == "th2": template_args = { "th_file": DEST_PATH + "/" + TH_NAME + ".th", @@ -587,393 +581,354 @@ def createThFolders(ENTRY_FILE, PROJECTION = "Plan", TARGET = "None", FORMAT = " "scale": SCALE, } - logfile, tmpdir = compile_template(template, template_args, cleanup=False, therion_path=therion_path) + logfile, tmpdir = compile_template(global_data.thconfigTemplate, template_args, cleanup=False, therion_path=therion_path) + + shutil.rmtree(tmpdir) if logfile == "Therion error": - # log.error(f"Therion error in: {Colors.ENDC}{TH_NAME}") - return logfile + # log.error(f"Therion error in: {Colors.ENDC}{TH_NAME}") + flagErrorCompile = True + stat = {"length": 0, "depth": 0} + else : + flagErrorCompile = False + stat = get_stats_from_log(logfile) + + + ################################################################################################# + # Update files # + ################################################################################################# + if UPDATE == "": + ERR = "# " if flagErrorCompile else "" + + totdata = f"""\tinput Data/{TH_NAME}.th + +\t## Pour le plan +\t{ERR}input Data/{TH_NAME}-Plan.th2 + +\t## Pour la coupe développée +\t{ERR}input Data/{TH_NAME}-Extended.th2 + +\t## Appel des maps +\t{ERR}input {TH_NAME}-maps.th +""" + + # Adapte templates + config_vars = { + 'fileName': TH_NAME, + 'caveName': TH_NAME.replace("_", " "), + 'Author': Author, + 'Copyright': Copyright, + 'Scale' : SCALE, + 'Target' : TARGET, + 'mapComment' : map_comment, + 'club' : club, + 'thanksto' : thanksto.replace("_", r"\_"), + 'datat' : datat.replace("_", r"\_"), + 'wpage' : wpage.replace("_", r"\_"), + 'cs' : cs, + 'configPath' : CONFIG_PATH, + 'totData' : totdata, + 'other_scraps_plan' : "", + 'file_info' : f'# File generated by pyCreateTh.py (version {Version}) date: {datetime.now().strftime("%Y.%m.%d %H:%M:%S")}', + } + + process_template(DEST_PATH + '/template.thconfig', config_vars, DEST_PATH + '/' + TH_NAME + '.thconfig') + process_template(DEST_PATH + '/template-tot.th', config_vars, DEST_PATH + '/' + TH_NAME + '-tot.th') + process_template(DEST_PATH + '/template-readme.md', config_vars, DEST_PATH + '/readme.md') ################################################################################################# # Parse the Plan XVI file # ################################################################################################# - - if UPDATE == "th2": - th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Plan.xvi" - else : - th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Plan.xvi" + other_scraps_plan = "" + if PROJECTION.lower() == "plan" or PROJECTION.lower() == "all" and not flagErrorCompile : + if UPDATE == "th2": + th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Plan.xvi" + else : + th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Plan.xvi" - log.info(f"Parsing plan XVI file:\t{Colors.ENDC}{safe_relpath(th_name_xvi)}") + log.info(f"Parsing Plan XVI file: {Colors.ENDC}{safe_relpath(th_name_xvi)}") - stations = {} - lines = [] - - with open(join(th_name_xvi), "r", encoding="utf-8") as f: - xvi_content = f.read() - xvi_stations, xvi_shots = xvi_content.split("XVIshots") - - # Extract all the stations - for line in xvi_stations.split("\n"): - match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line) - if match: - x = match.groups()[0] - y = match.groups()[1] - station_number = match.groups()[2] - namespace = match.groups()[3] - namespace_array = namespace.split(".") if namespace else [] - station = station_number - if len(namespace_array) > 1: - station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1])) - stations["{}.{}".format(x, y)] = [x, y, station] - - # Extraire les valeurs x et y à partir des listes dans stations - x_values = [float(value[0]) for value in stations.values()] - y_values = [float(value[1]) for value in stations.values()] - - # Trouver les min et max de x - x_min = float(min(x_values)) - x_max = float(max(x_values)) - - # Trouver les min et max de y - y_min = float(min(y_values)) - y_max = float(max(y_values)) - - x_ecart = x_max - x_min - y_ecart = y_max - y_min - - # Afficher les résultats - # log.debug("x_min:", x_min, "x_max:", x_max) - # log.debug("y_min:", y_min, "y_max:", y_max) - # log.debug("Écart max-min pour x:", x_ecart) - # log.debug("Écart max-min pour y:", y_ecart) + stations = {} + lines = [] - # Extract all the lines - for line in xvi_shots.split("\n"): - match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line ) - if match: - x1 = match.groups()[0] - y1 = match.groups()[1] - x2 = match.groups()[2] - y2 = match.groups()[3] - key1 = "{}.{}".format(x1, y1) - key2 = "{}.{}".format(x2, y2) - # Splays won't have stations - station1 = stations[key1][2] if key1 in stations else None - station2 = stations[key2][2] if key2 in stations else None - lines.append([x1, y1, x2, y2, station1, station2]) + with open(join(th_name_xvi), "r", encoding="utf-8") as f: + xvi_content = f.read() + xvi_stations, xvi_shots = xvi_content.split("XVIshots") + + # Extract all the stations + for line in xvi_stations.split("\n"): + match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line) + if match: + x = match.groups()[0] + y = match.groups()[1] + station_number = match.groups()[2] + namespace = match.groups()[3] + namespace_array = namespace.split(".") if namespace else [] + station = station_number + if len(namespace_array) > 1: + station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1])) + stations["{}.{}".format(x, y)] = [x, y, station] + + # Extraire les valeurs x et y à partir des listes dans stations + x_values = [float(value[0]) for value in stations.values()] + y_values = [float(value[1]) for value in stations.values()] + + # Trouver les min et max de x + x_min = float(min(x_values)) + x_max = float(max(x_values)) + + # Trouver les min et max de y + y_min = float(min(y_values)) + y_max = float(max(y_values)) + + x_ecart = x_max - x_min + y_ecart = y_max - y_min + + # Extract all the lines + for line in xvi_shots.split("\n"): + match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line ) + if match: + x1 = match.groups()[0] + y1 = match.groups()[1] + x2 = match.groups()[2] + y2 = match.groups()[3] + key1 = "{}.{}".format(x1, y1) + key2 = "{}.{}".format(x2, y2) + # Splays won't have stations + station1 = stations[key1][2] if key1 in stations else None + station2 = stations[key2][2] if key2 in stations else None + lines.append([x1, y1, x2, y2, station1, station2]) + + if UPDATE == "th2": + th2_name = DEST_PATH + "/" + TH_NAME + else : + th2_name = DEST_PATH + "/Data/" + TH_NAME + output_path = f'{th2_name}-Plan.{FORMAT}' + + scrap_to_add = int(len(stations)/station_by_scrap)-1 + + # log.debug(stations) + + log.info(f"Writing output to: {Colors.ENDC}{safe_relpath(output_path)}") + + # Write TH2 + if FORMAT == "th2": + seen = set() + th2_lines = [] + th2_points = [] + th2_names = [] + other_scraps_plan = f"\tSP-{TARGET}_01\n\tbreak\n" + + for line in lines: + th2_lines.append(global_data.th2Line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3])) + coords1 = "{}.{}".format(line[0], line[1]) - shutil.rmtree(tmpdir) - - if UPDATE == "th2": - th2_name = DEST_PATH + "/" + TH_NAME - else : - th2_name = DEST_PATH + "/Data/" + TH_NAME - output_path = f'{th2_name}-{PROJECTION}.{FORMAT}' - - scrap_to_add = int(len(stations)/station_by_scrap)-1 - - # log.debug(stations) - - log.info(f"Writing output to:\t{Colors.ENDC}{safe_relpath(output_path)}") - - # Write TH2 - if FORMAT == "th2": - th2_file_header = """encoding utf-8""" - - th2_file = """ -##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max} -##XTHERION## xth_me_area_zoom_to 100 -##XTHERION## xth_me_image_insert {insert_XVI} - -{Copyright} -# File generated by pyCreateTh.py version {version} date: {date} - -# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min} -# y_min: {Y_Min}, y_max: {Y_Max} ecart : {Y_Max_Y_Min} - -scrap S{projection_short}-{name}_01 -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" - -{points} - -{names} - -{lines} - -endscrap""" - - th2_point = """ point {x} {y} station -name {station}""" - th2_name = """ point {x} {y} station-name -align tr -scale xs -text {station}""" - - th2_line = """ line u:Shot_Survey - {x1} {y1} - {x2} {y2} - - endline""" - - seen = set() - th2_lines = [] - th2_points = [] - th2_names = [] - other_scraps_plan = f"\tS{PROJECTION[0].upper()}-{TARGET}_01\n\tbreak\n" - - for line in lines: - th2_lines.append(th2_line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3])) - coords1 = "{}.{}".format(line[0], line[1]) - - if coords1 not in seen: - seen.add(coords1) - th2_points.append(th2_point.format(x=line[0], y=line[1], station=line[4])) - th2_names.append(th2_name.format(x=line[0], y=line[1], station=line[4])) - coords2 = "{}.{}".format(line[2], line[3]) - - if "{}.{}".format(line[2], line[3]) not in seen: - seen.add(coords2) - if line[5] != None: - th2_points.append(th2_point.format(x=line[2], y=line[3], station=line[5])) - th2_names.append(th2_name.format(x=line[2], y=line[3], station=line[5])) + if coords1 not in seen: + seen.add(coords1) + th2_points.append(global_data.th2Point.format(x=line[0], y=line[1], station=line[4])) + th2_names.append(global_data.th2Name.format(x=line[0], y=line[1], station=line[4])) + coords2 = "{}.{}".format(line[2], line[3]) + + if "{}.{}".format(line[2], line[3]) not in seen: + seen.add(coords2) + if line[5] != None: + th2_points.append(global_data.th2Point.format(x=line[2], y=line[3], station=line[5])) + th2_names.append(global_data.th2Name.format(x=line[2], y=line[3], station=line[5])) - if isfile(output_path): - log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done") + if isfile(output_path): + log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done") - else : - name = TARGET, - log.debug(f"Therion output path :\t{Colors.ENDC}{safe_relpath(output_path)}") + else : + # name = TARGET, + log.debug(f"Therion output path: {Colors.ENDC}{safe_relpath(output_path)}") - with open(str(output_path), "w+") as f: - f.write(th2_file_header) - f.write(th2_file.format( - name = sanitize_filename(name[0]), - Copyright = Copyright, - Copyright_Short = Copyright_Short, - points="\n".join(th2_points), - lines="\n".join(th2_lines) if LINES else "", - names="\n".join(th2_names) if NAMES else "", - projection=PROJECTION.lower(), - projection_short=PROJECTION[0].upper(), - author=Author, - year=datetime.now().year, - version = Version, - date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), - X_Min=x_min*1.2, - X_Max=x_max*1.2, - Y_Min=y_min*1.2, - Y_Max=y_max*1.2, - X_Max_X_Min =x_ecart, - Y_Max_Y_Min =y_ecart, - insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {" - + stations[next(iter(stations))][1] + " " - + stations[next(iter(stations))][2] +"} " - + os.path.basename(th_name_xvi) + " 0 {}", - ) - ) - if scrap_to_add >= 1 : - for i in range(scrap_to_add): - other_scraps_plan = other_scraps_plan + f"\tS{PROJECTION[0].upper()}-{name[0]}_{i+2:02}\n\tbreak\n" - th2_scrap = """ - -scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" - -endscrap - -""" - f.write(th2_scrap.format( - name=name[0], - projection=PROJECTION.lower(), - projection_short=PROJECTION[0].upper(), + with open(str(output_path), "w+") as f: + f.write(global_data.th2FileHeader) + f.write(global_data.th2File.format( + name = TARGET, + Copyright = Copyright, + Copyright_Short = Copyright_Short, + points="\n".join(th2_points), + lines="\n".join(th2_lines) if LINES else "", + names="\n".join(th2_names) if NAMES else "", + projection="plan", + projection_short="P", author=Author, year=datetime.now().year, - Copyright_Short = Copyright_Short, - num=f"{i+2:02}", + version = Version, + date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), + X_Min=x_min*1.2, + X_Max=x_max*1.2, + Y_Min=y_min*1.2, + Y_Max=y_max*1.2, + X_Max_X_Min =x_ecart, + Y_Max_Y_Min =y_ecart, + insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {" + + stations[next(iter(stations))][1] + " " + + stations[next(iter(stations))][2] +"} " + + os.path.basename(th_name_xvi) + " 0 {}", + ) + ) + if scrap_to_add >= 1 : + for i in range(scrap_to_add): + f.write(global_data.th2Scrap.format( + name=TARGET, + projection="plan", + projection_short="P", + author=Author, + year=datetime.now().year, + Copyright_Short = Copyright_Short, + num=f"{i+2:02}", + ) ) - ) ################################################################################################# # Parse the Extended XVI file # ################################################################################################# - if UPDATE == "th2": - th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Extended.xvi" - else : - th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi" - - log.info(f"Parsing extended XVI file:\t{Colors.ENDC}{safe_relpath(th_name_xvi)}") - - # Parse the Extended XVI file - stations = {} - lines = [] - - with open(join(th_name_xvi), "r", encoding="utf-8") as f: - xvi_content = f.read() - xvi_stations, xvi_shots = xvi_content.split("XVIshots") - - # Extract all the stations - for line in xvi_stations.split("\n"): - match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line) - if match: - x = match.groups()[0] - y = match.groups()[1] - station_number = match.groups()[2] - namespace = match.groups()[3] - namespace_array = namespace.split(".") if namespace else [] - station = station_number - if len(namespace_array) > 1: - station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1])) - stations["{}.{}".format(x, y)] = [x, y, station] - - # Extraire les valeurs x et y à partir des listes dans stations - x_values = [float(value[0]) for value in stations.values()] - y_values = [float(value[1]) for value in stations.values()] - - # Trouver les min et max de x - x_min = float(min(x_values)) - x_max = float(max(x_values)) - - # Trouver les min et max de y - y_min = float(min(y_values)) - y_max = float(max(y_values)) - - x_ecart = x_max - x_min - y_ecart = y_max - y_min - - # Afficher les résultats - # log.debug("x_min:", x_min, "x_max:", x_max) - # log.debug("y_min:", y_min, "y_max:", y_max) - # log.debug("Écart max-min pour x:", x_ecart) - # log.debug("Écart max-min pour y:", y_ecart) - - # Extract all the lines - for line in xvi_shots.split("\n"): - match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line ) - if match: - x1 = match.groups()[0] - y1 = match.groups()[1] - x2 = match.groups()[2] - y2 = match.groups()[3] - key1 = "{}.{}".format(x1, y1) - key2 = "{}.{}".format(x2, y2) - # Splays won't have stations - station1 = stations[key1][2] if key1 in stations else None - station2 = stations[key2][2] if key2 in stations else None - lines.append([x1, y1, x2, y2, station1, station2]) - shutil.rmtree(tmpdir) - - if UPDATE == "th2": - th2_name = DEST_PATH + "/" + TH_NAME - else : - th2_name = DEST_PATH + "/Data/" + TH_NAME - output_path = f'{th2_name}-Extended.{FORMAT}' - - log.info(f"Writing output to:\t\t{Colors.ENDC}{safe_relpath(output_path)}") - - # Write TH2 - if FORMAT == "th2": - th2_file_header = """encoding utf-8""" - - th2_file = """ -##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max} -##XTHERION## xth_me_area_zoom_to 100 -##XTHERION## xth_me_image_insert {insert_XVI} - -{Copyright} -# File generated by pyCreateTh.py version {version} date: {date} - -# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min} -# y_min: {Y_Min}, y_max: {Y_Max} ecart : {Y_Max_Y_Min} - -scrap SC-{name}_01 -station-names "" "@{name}" -projection extended -author {year} "{author}" -copyright {year} "{Copyright_Short}" - -{points} - -{names} - -{lines} - -endscrap""" - - th2_point = """ point {x} {y} station -name {station}""" - th2_name = """ point {x} {y} station-name -align tr -scale xs -text {station}""" - - th2_line = """ line u:Shot_Survey - {x1} {y1} - {x2} {y2} - endline - """ - - seen = set() - th2_lines = [] - th2_points = [] - th2_names = [] - other_scraps_extended = f"\tSC-{TARGET}_01\n\tbreak\n" - - for line in lines: - th2_lines.append(th2_line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3])) - coords1 = "{}.{}".format(line[0], line[1]) - - if coords1 not in seen: - seen.add(coords1) - th2_points.append(th2_point.format(x=line[0], y=line[1], station=line[4])) - th2_names.append(th2_name.format(x=line[0], y=line[1], station=line[4])) - coords2 = "{}.{}".format(line[2], line[3]) - - if "{}.{}".format(line[2], line[3]) not in seen: - seen.add(coords2) - if line[5] != None: - th2_points.append(th2_point.format(x=line[2], y=line[3], station=line[5])) - th2_names.append(th2_name.format(x=line[2], y=line[3], station=line[5])) - - - if isfile(output_path): - log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done{Colors.ENDC}") + other_scraps_extended = "" + if PROJECTION.lower() == "extended" or PROJECTION.lower() == "all" and not flagErrorCompile : + if UPDATE == "th2": + th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Extended.xvi" else : - name = TARGET, - log.debug(f"Therion output path :\t{Colors.ENDC}{output_path}") - - with open(str(output_path), "w+") as f: - f.write(th2_file_header) - f.write(th2_file.format( - name = sanitize_filename(name[0]), - Copyright = Copyright, - Copyright_Short = Copyright_Short, - points="\n".join(th2_points), - lines="\n".join(th2_lines) if LINES else "", - names="\n".join(th2_names) if NAMES else "", - projection="extended", - projection_short="C", - author=Author, - year=datetime.now().year, - version = Version, - date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), - X_Min=x_min*1.2, - X_Max=x_max*1.2, - Y_Min=y_min*1.2, - Y_Max=y_max*1.2, - X_Max_X_Min =x_ecart, - Y_Max_Y_Min =y_ecart, - insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {" - + stations[next(iter(stations))][1] + " " - + stations[next(iter(stations))][2] +"} " - + os.path.basename(th_name_xvi) + " 0 {}", - ) - ) - if scrap_to_add >= 1 : - for i in range(scrap_to_add): - other_scraps_extended = other_scraps_extended + f"\tSC-{name[0]}_{i+2:02}\n\tbreak\n" - th2_scrap = """ - -scrap SC-{name}_{num:02} -station-names "" "@{name}" -projection extended -author {year} "{author}" -copyright {year} "{Copyright_Short}" - -endscrap + th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi" -""" - f.write(th2_scrap.format( - name=name[0], - author=Author, + log.info(f"Parsing extended XVI file:\t{Colors.ENDC}{safe_relpath(th_name_xvi)}") + + # Parse the Extended XVI file + stations = {} + lines = [] + + with open(join(th_name_xvi), "r", encoding="utf-8") as f: + xvi_content = f.read() + xvi_stations, xvi_shots = xvi_content.split("XVIshots") + + # Extract all the stations + for line in xvi_stations.split("\n"): + match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line) + if match: + x = match.groups()[0] + y = match.groups()[1] + station_number = match.groups()[2] + namespace = match.groups()[3] + namespace_array = namespace.split(".") if namespace else [] + station = station_number + if len(namespace_array) > 1: + station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1])) + stations["{}.{}".format(x, y)] = [x, y, station] + + # Extraire les valeurs x et y à partir des listes dans stations + x_values = [float(value[0]) for value in stations.values()] + y_values = [float(value[1]) for value in stations.values()] + + # Trouver les min et max de x + x_min = float(min(x_values)) + x_max = float(max(x_values)) + + # Trouver les min et max de y + y_min = float(min(y_values)) + y_max = float(max(y_values)) + + x_ecart = x_max - x_min + y_ecart = y_max - y_min + + # Extract all the lines + for line in xvi_shots.split("\n"): + match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line ) + if match: + x1 = match.groups()[0] + y1 = match.groups()[1] + x2 = match.groups()[2] + y2 = match.groups()[3] + key1 = "{}.{}".format(x1, y1) + key2 = "{}.{}".format(x2, y2) + # Splays won't have stations + station1 = stations[key1][2] if key1 in stations else None + station2 = stations[key2][2] if key2 in stations else None + lines.append([x1, y1, x2, y2, station1, station2]) + # shutil.rmtree(tmpdir) + + if UPDATE == "th2": + th2_name = DEST_PATH + "/" + TH_NAME + else : + th2_name = DEST_PATH + "/Data/" + TH_NAME + output_path = f'{th2_name}-Extended.{FORMAT}' + + log.info(f"Writing output to: {Colors.ENDC}{safe_relpath(output_path)}") + + # Write TH2 + if FORMAT == "th2": + + seen = set() + th2_lines = [] + th2_points = [] + th2_names = [] + other_scraps_extended = f"\tSC-{TARGET}_01\n\tbreak\n" + + for line in lines: + th2_lines.append(global_data.th2Line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3])) + coords1 = "{}.{}".format(line[0], line[1]) + + if coords1 not in seen: + seen.add(coords1) + th2_points.append(global_data.th2Point.format(x=line[0], y=line[1], station=line[4])) + th2_names.append(global_data.th2Name.format(x=line[0], y=line[1], station=line[4])) + coords2 = "{}.{}".format(line[2], line[3]) + + if "{}.{}".format(line[2], line[3]) not in seen: + seen.add(coords2) + if line[5] != None: + th2_points.append(global_data.th2Point.format(x=line[2], y=line[3], station=line[5])) + th2_names.append(global_data.th2Name.format(x=line[2], y=line[3], station=line[5])) + + + if isfile(output_path): + log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done{Colors.ENDC}") + else : + log.debug(f"Therion output path :\t{Colors.ENDC}{output_path}") + + with open(str(output_path), "w+") as f: + f.write(global_data.th2FileHeader) + f.write(global_data.th2File.format( + name = TARGET, + Copyright = Copyright, Copyright_Short = Copyright_Short, + points="\n".join(th2_points), + lines="\n".join(th2_lines) if LINES else "", + names="\n".join(th2_names) if NAMES else "", + projection="extended", + projection_short="C", + author=Author, year=datetime.now().year, - num=f"{i+2:02}", - ) + version = Version, + date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), + X_Min=x_min*1.2, + X_Max=x_max*1.2, + Y_Min=y_min*1.2, + Y_Max=y_max*1.2, + X_Max_X_Min =x_ecart, + Y_Max_Y_Min =y_ecart, + insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {" + + stations[next(iter(stations))][1] + " " + + stations[next(iter(stations))][2] +"} " + + os.path.basename(th_name_xvi) + " 0 {}", ) + ) + if scrap_to_add >= 1 : + for i in range(scrap_to_add): + # other_scraps_extended = other_scraps_extended + f"\tSC-{TARGET[0]}_{i+2:02}\n\tbreak\n" + f.write(global_data.th2Scrap.format( + name=TARGET, + projection="extended", + projection_short="C", + author=Author, + Copyright_Short=Copyright_Short, + year=datetime.now().year, + num=f"{i+2:02}", + ) + ) ################################################################################################# @@ -982,11 +937,12 @@ endscrap if UPDATE == "": config_vars = { 'fileName': TH_NAME, + 'caveName': TH_NAME.replace("_", " "), 'Author': Author, 'Copyright': Copyright, 'Scale' : SCALE, 'Target' : TARGET, - 'map_comment' : map_comment, + 'mapComment' : map_comment, 'club' : club, 'thanksto' : thanksto, 'datat' : datat, @@ -1005,17 +961,28 @@ endscrap ################################################################################################# # Final therion compilation # ################################################################################################# - if UPDATE == "": if final_therion_exe == True: FILE = os.path.dirname(ENTRY_FILE) + "/" + TH_NAME + "/" + TH_NAME + ".thconfig" # log.info(f"Final therion compilation: {Colors.ENDC}{safe_relpath(FILE)}") - compile_file(FILE, therion_path=therion_path) + if not flagErrorCompile : + compile_file(FILE, therion_path=therion_path) + + return flagErrorCompile, stat ################################################################################################# -# lecture d'un .file # +# lecture d'un fichier .mak # ################################################################################################# def makToThFile(ENTRY_FILE) : + """ + Convertit un fichier .mak en fichier .th. + + Args: + ENTRY_FILE (str): Le chemin vers le fichier .mak d'entrée. + + Returns: + + """ _ConfigPath = "./../../" @@ -1023,8 +990,8 @@ def makToThFile(ENTRY_FILE) : patternDat = re.compile(r'^#.*?\.dat[,;]$', re.IGNORECASE) # Motif insensible à la casse fixPoints = [] - patternFixPoints = re.compile(r'^([\w-]+)\[(m|f),\s*(-?\d+\.?\d*),\s*(-?\d+\.?\d*),\s*(-?\d+\.?\d*)\][,;]$', re.IGNORECASE) - + patternFixPoints = re.compile(r'^([\w-]+)\[(m|f)\s*[, ]\s*(-?\d+\.?\d*)\s*[, ]\s*(-?\d+\.?\d*)\s*[, ]\s*(-?\d+\.?\d*)\]\s*[,;]?\s*(?:/.*)?$',re.IGNORECASE) + UTM = [] Datums = set() # Pour stocker les valeurs uniques trouvées @@ -1076,56 +1043,9 @@ def makToThFile(ENTRY_FILE) : elif not fixPoints : log.critical(f"No fix points found in mak file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") exit(0) - - datum_to_epsg = { - # Datums globaux - "wgs84": "326", # UTM Nord (WGS84) - EPSG:326XX - "etrs89": "258", # UTM Nord (ETRS89) - Europe - - # Datums européens - "european1950": "230", # ED50 / UTM Nord - Europe - "ed50": "230", - - # Datums nord-américains - "nad27": "267", # UTM Nord (NAD27) - Amérique du Nord - "northamericandatum1927": "267", - "northamerican1927": "267", - "nad83": "269", # UTM Nord (NAD83) - Amérique du Nord - "northamericandatum1983": "269", - "northamerican1983" : "269", - - # Datums français - "ntf": "275", # UTM Nord (NTF) - France (Paris) - "nouvelletriangulationfrançaise": "275", - - # Datums africains - "clarke1880": "297", # UTM Nord (Clarke 1880) - Afrique - - # Datums australiens - "agd66": "202", # UTM Nord (AGD66) - Australie - "australiangeodeticdatum1966": "202", - "australiangeodetic1966": "202", - "agd84": "203", # UTM Nord (AGD84) - Australie - "australiangeodeticdatum1984": "203", - "australiangeodetic1984": "203", - "gda94": "283", # UTM Nord (GDA94) - Australie - "geocentricdatumofaustralia1994": "283", - "geocentricofaustralia1994": "283", - - # Datums asiatiques - "pulkovo1942": "284", # UTM Nord (Pulkovo 1942) - Russie/CEI - "beijing1954": "214", # UTM Nord (Beijing 1954) - Chine - - # Datums sud-américains - "sad69": "291", # UTM Nord (SAD69) - Amérique du Sud - "southamericandatum1969": "291", - "southamerican1969": "291", - "sirgas2000": "319", # UTM Nord (SIRGAS 2000) - Amérique Latine - } - datum_lower = next(iter(Datums)).strip().lower().replace(" ","") - if datum_lower not in datum_to_epsg: + if datum_lower not in global_data.datumToEPSG: log.critical(f"Unknown Datum : {datum_lower}") exit(0) @@ -1145,7 +1065,7 @@ def makToThFile(ENTRY_FILE) : exit(0) # Construction du code EPSG - epsg_prefix = datum_to_epsg[datum_lower] + epsg_prefix = global_data.datumToEPSG[datum_lower] epsg_code = f"{epsg_prefix}{zone_num}" if hemisphere == "N" else f"{epsg_prefix}{zone_num + 100}" # Génération du CRS QGIS (format WKT) @@ -1154,9 +1074,7 @@ def makToThFile(ENTRY_FILE) : log.info(f"Reading mak file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.GREEN}, fixed station : {Colors.ENDC}{len(fixPoints)}{Colors.GREEN}, files {Colors.ENDC}{len(datFiles)}{Colors.GREEN}, UTM Zone : {Colors.ENDC}{UTM[0]}{Colors.GREEN}, Datum : {Colors.ENDC}{next(iter(Datums))}{Colors.GREEN}, SCR : {Colors.ENDC}{crs_wkt}") # log.debug(datFiles) # log.debug(fixPoints) - - fixPoints - + SurveyTitleMak = sanitize_filename(os.path.basename(abspath(args.survey_file))[:-4]) folderDest = os.path.dirname(abspath(args.survey_file)) + "/" + SurveyTitleMak @@ -1241,12 +1159,12 @@ def makToThFile(ENTRY_FILE) : config_vars = { 'fileName': SurveyTitleMak, - 'cavename': SurveyTitleMak.replace("_", " "), + 'caveName': SurveyTitleMak.replace("_", " "), 'Author': Author, 'Copyright': Copyright, 'Scale' : args.scale, 'Target' : "TARGET", - 'map_comment' : map_comment, + 'mapComment' : map_comment, 'club' : club, 'thanksto' : thanksto, 'datat' : datat, @@ -1270,6 +1188,18 @@ def makToThFile(ENTRY_FILE) : ################################################################################################# def station_List(data, list, fixPoints) : + """ + Crée une liste de stations à partir des données fournies. + + Args: + data (DataFrame): Les données d'entrée contenant les informations sur les stations. + list (DataFrame): La liste des stations existantes. + fixPoints (list): Les points de fixation à considérer. + + Returns: + DataFrame: La liste mise à jour des stations. + """ + # Création d'un DataFrame à partir des données rows1 = [line.split() for line in data['DATA']] dfDATA = pd.DataFrame(rows1) @@ -1291,241 +1221,260 @@ def station_List(data, list, fixPoints) : return list, dfDATA ################################################################################################# -def formated_Station_List(df, dataFormat ,unit = "meter", ENTRY_FILE = None) : - - # Remplacer les None/NaN par des espaces - df = df.fillna(" ") +def formated_Station_List(df, dataFormat, unit = "meter", ENTRY_FILE = None) : + """ + Formate la liste des stations selon le format spécifié. - # Conserver la première ligne (en-têtes) séparément - header_row = df.iloc[0] + Args: + df (DataFrame): Le DataFrame contenant les données des stations. + dataFormat (str): Le format de données souhaité. + unit (str, optional): L'unité de mesure (par défaut "meter"). + ENTRY_FILE (str, optional): Le chemin du fichier d'entrée (par défaut None). - # Traiter uniquement les lignes à partir de la deuxième (index 1) - df_data = df.iloc[1:].copy() - - columns = dataFormat.split() + Returns: + DataFrame: Le DataFrame formaté. + """ + + # Remplacer les None/NaN par des espaces + df = df.fillna(" ") - Koef = 0.3048 if unit == "meter" else 1.0 - - if "length" in columns: - col_name = df_data.columns[columns.index("length") - 2] - df_data.iloc[:, col_name] = (df_data.iloc[:, col_name].astype(float) * Koef).apply(lambda x: f"{x:.2f}") + # Conserver la première ligne (en-têtes) séparément + header_row = df.iloc[0] - if "up" in columns: - col_name = df_data.columns[columns.index("up") - 2] - df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef - df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - - if "down" in columns: - col_name = df_data.columns[columns.index("down") - 2] - df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef - df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - - if "right" in columns: - col_name = df_data.columns[columns.index("right") - 2] - df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef - df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - - if "left" in columns: - col_name = df_data.columns[columns.index("left") - 2] - df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef - df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - - if "compass" in columns: - df_data.iloc[:, columns.index("compass")-2] = (df_data.iloc[:, columns.index("compass")-2].astype(float)).apply(lambda x: f"{x:.1f}") - - if "clino" in columns: - df_data.iloc[:, columns.index("clino")-2] = (df_data.iloc[:, columns.index("clino")-2].astype(float)).apply(lambda x: f"{x:.1f}") - - if "from" in columns: - df_data.iloc[:, columns.index("from")-2] = (df_data.iloc[:, columns.index("from")-2].astype(str).stationName()) - - if "to" in columns: - df_data.iloc[:, columns.index("to")-2] = (df_data.iloc[:, columns.index("to")-2].astype(str).stationName()) - - # Remplacer les NaN par des espaces après transformation - df_data = df_data.fillna(" ") - - # Ajouter un '# ' au début de la colonne 9 (si non vide) - df_data.iloc[:, 9] = df_data.iloc[:, 9].apply(lambda x: f"# {x}" if str(x).strip() and str(x) != " " else x) - - # Ajouter "_hab" à la colonne 2 si FROM == TO - df_data.iloc[:, 1] = df_data.apply( - lambda row: f"{row.iloc[1]}_hab" if str(row.iloc[0]).strip() == str(row.iloc[1]).strip() else row.iloc[1], - axis=1 - ) - - # Gestion des flags surface et not surface - new_rows = [] - - for idx, row in df_data.iterrows(): - col10 = str(row.iloc[9]) - - # Si la colonne 10 contient #|L# Exclude from Length - if "#|L#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags surface" - new_rows.append(surface_row) - - new_rows.append(row.tolist()) - - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not surface" - new_rows.append(not_surface_row) - - # Si la colonne 10 contient #|S# type Spay (habillages) - elif "#|S#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags splay" - new_rows.append(surface_row) - - new_rows.append(row.tolist()) - - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not splay" - new_rows.append(not_surface_row) + # Traiter uniquement les lignes à partir de la deuxième (index 1) + df_data = df.iloc[1:].copy() - # Si la colonne 10 contient #|X# total exclusion - elif "#|X#" in col10 or "#|XL#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags duplicate" - new_rows.append(surface_row) + columns = dataFormat.split() - new_rows.append(row.tolist()) + Koef = 0.3048 if unit == "length meter" else 1.0 + + if "length" in columns: + col_name = df_data.columns[columns.index("length") - 2] + df_data.iloc[:, col_name] = (df_data.iloc[:, col_name].astype(float) * Koef).apply(lambda x: f"{x:.2f}") - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not duplicate" - new_rows.append(not_surface_row) - log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + if "up" in columns: + col_name = df_data.columns[columns.index("up") - 2] + df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef + df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - # Si la colonne 10 contient #|P# exclude from plotting - elif "#|P#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "# flags exclude from plot no implemented" - new_rows.append(surface_row) + if "down" in columns: + col_name = df_data.columns[columns.index("down") - 2] + df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef + df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - new_rows.append(row.tolist()) + if "right" in columns: + col_name = df_data.columns[columns.index("right") - 2] + df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef + df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") + + if "left" in columns: + col_name = df_data.columns[columns.index("left") - 2] + df_data[col_name] = pd.to_numeric(df_data[col_name], errors='coerce') * Koef + df_data[col_name] = df_data[col_name].apply(lambda x: "-" if pd.notna(x) and x < 0 else f"{x:.2f}" if pd.notna(x) else "") - not_surface_row = [" "] * len(row) - not_surface_row[0] = "# flags not exclude from plot no implemented" - new_rows.append(not_surface_row) - log.warning(f"Flags exclude from plot #|P# not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + if "compass" in columns: + df_data.iloc[:, columns.index("compass")-2] = (df_data.iloc[:, columns.index("compass")-2].astype(float)).apply(lambda x: f"{x:.1f}") + + if "clino" in columns: + df_data.iloc[:, columns.index("clino")-2] = (df_data.iloc[:, columns.index("clino")-2].astype(float)).apply(lambda x: f"{x:.1f}") + + if "from" in columns: + df_data.iloc[:, columns.index("from")-2] = (df_data.iloc[:, columns.index("from")-2].astype(str).stationName()) + + if "to" in columns: + df_data.iloc[:, columns.index("to")-2] = (df_data.iloc[:, columns.index("to")-2].astype(str).stationName()) + + # Remplacer les NaN par des espaces après transformation + df_data = df_data.fillna(" ") + + # Ajouter un '# ' au début de la colonne 9 (si non vide) + df_data.iloc[:, 9] = df_data.iloc[:, 9].apply(lambda x: f"# {x}" if str(x).strip() and str(x) != " " else x) - # Si la colonne 10 contient #|C# exclude from closure - elif "#|C#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "# flags exclude from closure no implemented" - new_rows.append(surface_row) + # Ajouter "_hab" à la colonne 2 si FROM == TO + df_data.iloc[:, 1] = df_data.apply( + lambda row: f"{row.iloc[1]}_hab" if str(row.iloc[0]).strip() == str(row.iloc[1]).strip() else row.iloc[1], + axis=1 + ) + + # Gestion des flags surface et not surface + new_rows = [] - new_rows.append(row.tolist()) + for idx, row in df_data.iterrows(): + col10 = str(row.iloc[9]) - not_surface_row = [" "] * len(row) - not_surface_row[0] = "# flags not exclude from closure no implemented" - new_rows.append(not_surface_row) - log.warning(f"Flags #|C# exclude from closure not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + # Si la colonne 10 contient #|L# Exclude from Length + if "#|L#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags surface" + new_rows.append(surface_row) - # Si la colonne 10 contient #|PL# exclude from plotting and Length - elif "#|PL#" in col10 or "#|LP#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags duplicate" - new_rows.append(surface_row) + new_rows.append(row.tolist()) - new_rows.append(row.tolist()) + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not surface" + new_rows.append(not_surface_row) + + # Si la colonne 10 contient #|S# type Spay (habillages) + elif "#|S#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags splay" + new_rows.append(surface_row) - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not duplicate" - new_rows.append(not_surface_row) - log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + new_rows.append(row.tolist()) - # Si la colonne 10 contient #|LC# exclude from Length and Closure - elif "#|LC#" in col10 or "#|CL#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags duplicate" - new_rows.append(surface_row) - - new_rows.append(row.tolist()) - - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not duplicate" - new_rows.append(not_surface_row) - log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") - - # Si la colonne 10 contient #|PLC# exclude from plotting, closure and length - elif "#|PLC#" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "flags duplicate" - new_rows.append(surface_row) - - new_rows.append(row.tolist()) - - not_surface_row = [" "] * len(row) - not_surface_row[0] = "flags not duplicate" - new_rows.append(not_surface_row) + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not splay" + new_rows.append(not_surface_row) - elif "#|" in col10: - surface_row = [" "] * len(row) - surface_row[0] = "# flags unknown no implemented" - new_rows.append(surface_row) + # Si la colonne 10 contient #|X# total exclusion + elif "#|X#" in col10 or "#|XL#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags duplicate" + new_rows.append(surface_row) - new_rows.append(row.tolist()) + new_rows.append(row.tolist()) - not_surface_row = [" "] * len(row) - not_surface_row[0] = "# flags not unknown no implemented" - new_rows.append(not_surface_row) - log.error(f"Flags unknown '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") - global_data.error_count += 1 - + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not duplicate" + new_rows.append(not_surface_row) + log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + + # Si la colonne 10 contient #|P# exclude from plotting + elif "#|P#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "# flags exclude from plot no implemented" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "# flags not exclude from plot no implemented" + new_rows.append(not_surface_row) + log.warning(f"Flags exclude from plot #|P# not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + + # Si la colonne 10 contient #|C# exclude from closure + elif "#|C#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "# flags exclude from closure no implemented" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "# flags not exclude from closure no implemented" + new_rows.append(not_surface_row) + log.warning(f"Flags #|C# exclude from closure not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + + # Si la colonne 10 contient #|PL# exclude from plotting and Length + elif "#|PL#" in col10 or "#|LP#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags duplicate" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not duplicate" + new_rows.append(not_surface_row) + log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + + # Si la colonne 10 contient #|LC# exclude from Length and Closure + elif "#|LC#" in col10 or "#|CL#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags duplicate" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not duplicate" + new_rows.append(not_surface_row) + log.warning(f"Flags '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented in therion, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + + # Si la colonne 10 contient #|PLC# exclude from plotting, closure and length + elif "#|PLC#" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "flags duplicate" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "flags not duplicate" + new_rows.append(not_surface_row) + + elif "#|" in col10: + surface_row = [" "] * len(row) + surface_row[0] = "# flags unknown no implemented" + new_rows.append(surface_row) + + new_rows.append(row.tolist()) + + not_surface_row = [" "] * len(row) + not_surface_row[0] = "# flags not unknown no implemented" + new_rows.append(not_surface_row) + log.error(f"Flags unknown '{Colors.ENDC}{col10}{Colors.WARNING}' not implemented, line {Colors.ENDC}{idx+1}{Colors.WARNING} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + global_data.error_count += 1 + + else: + new_rows.append(row.tolist()) + + prev_row = row # Garder trace de la ligne précédente + + cleaned_rows = [] + i = 0 + while i < len(new_rows): + current = new_rows[i] + if (i + 1 < len(new_rows) and + str(current[0]).strip() == "flags not surface" and + str(new_rows[i + 1][0]).strip() == "flags surface"): + i += 2 + elif (i + 1 < len(new_rows) and + str(current[0]).strip() == "flags not splay" and + str(new_rows[i + 1][0]).strip() == "flags splay"): + i += 2 + elif (i + 1 < len(new_rows) and + str(current[0]).strip() == "flags not duplicate" and + str(new_rows[i + 1][0]).strip() == "flags duplicate"): + i += 2 + elif (i + 1 < len(new_rows) and + str(current[0]).strip() == "# flags not exclude from closure no implemented" and + str(new_rows[i + 1][0]).strip() == "# flags exclude from closure no implemented"): + i += 2 + elif (i + 1 < len(new_rows) and + str(current[0]).strip() == "# flags not exclude from plot no implemented" and + str(new_rows[i + 1][0]).strip() == "# flags exclude from plot no implemented"): + i += 2 + elif (i + 1 < len(new_rows) and + str(current[0]).strip() == "# flags not unknown no implemented" and + str(new_rows[i + 1][0]).strip() == "# flags unknown no implemented"): + i += 2 else: - new_rows.append(row.tolist()) + cleaned_rows.append(current) + i += 1 - prev_row = row # Garder trace de la ligne précédente + # Convertir les lignes en chaines formatées + output = [] - cleaned_rows = [] - i = 0 - while i < len(new_rows): - current = new_rows[i] - if (i + 1 < len(new_rows) and - str(current[0]).strip() == "flags not surface" and - str(new_rows[i + 1][0]).strip() == "flags surface"): - i += 2 - elif (i + 1 < len(new_rows) and - str(current[0]).strip() == "flags not splay" and - str(new_rows[i + 1][0]).strip() == "flags splay"): - i += 2 - elif (i + 1 < len(new_rows) and - str(current[0]).strip() == "flags not duplicate" and - str(new_rows[i + 1][0]).strip() == "flags duplicate"): - i += 2 - elif (i + 1 < len(new_rows) and - str(current[0]).strip() == "# flags not exclude from closure no implemented" and - str(new_rows[i + 1][0]).strip() == "# flags exclude from closure no implemented"): - i += 2 - elif (i + 1 < len(new_rows) and - str(current[0]).strip() == "# flags not exclude from plot no implemented" and - str(new_rows[i + 1][0]).strip() == "# flags exclude from plot no implemented"): - i += 2 - elif (i + 1 < len(new_rows) and - str(current[0]).strip() == "# flags not unknown no implemented" and - str(new_rows[i + 1][0]).strip() == "# flags unknown no implemented"): - i += 2 - else: - cleaned_rows.append(current) - i += 1 + # Ajouter la première ligne (en-têtes) telle quelle + header_str = "\t\t" + "\t".join(map(str, header_row)) + output.append(header_str) - # Convertir les lignes en chaines formatées - output = [] - - # Ajouter la première ligne (en-têtes) telle quelle - header_str = "\t\t" + "\t".join(map(str, header_row)) - output.append(header_str) - - # Ajouter les autres lignes traitées - for row in cleaned_rows: - row_str = "\t\t" + "\t".join(map(str, row)) - output.append(row_str) - - # print(new_rows) - - return "\n".join(output) + # Ajouter les autres lignes traitées + for row in cleaned_rows: + row_str = "\t\t" + flag = False + for i in row : + if str(i) == " " : + row_str += "" + elif str(i).startswith("#") or flag == True : + row_str += f" {str(i)}" + flag = True + else: + row_str += f"\t{str(i)}" + output.append(row_str) + + return "\n".join(output) ################################################################################################# def find_duplicates_by_date_and_team(data): @@ -1716,8 +1665,19 @@ def merge_duplicate_surveys(data, duplicates, id_offset=10000): # Création des dossiers Th à partir d'un dat # ################################################################################################# def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : -# Input : Dat file for conversion -# Outputs : Th files by survey + """ + Convertit un fichier .dat en fichiers .th. + + Args: + ENTRY_FILE (str): Le chemin vers le fichier .dat d'entrée. + fixPoints (list, optional): Liste des points de fixation. Defaults to []. + crs_wkt (str, optional): Le système de référence spatiale en WKT. Defaults to "". + CONFIG_PATH (str, optional): Le chemin vers le fichier de configuration. Defaults to "". + + Returns: + tuple: Un tuple contenant un DataFrame des stations et le nom du survey. + + """ global Author global Copyright global Copyright_Short @@ -1740,7 +1700,7 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : content = "" ################################################################################################# - # Lecture du fichier dat # + # 1 : Lecture du fichier dat # ################################################################################################# try: result = from_path(ENTRY_FILE) @@ -1757,16 +1717,16 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : content = f.read() if encoding_detected.lower() != 'utf-8': - log.info(f"{Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.GREEN}, encodage : {Colors.ENDC}{encoding_detected}{Colors.GREEN} conversion utf-8") + log.info(f"File: {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.GREEN}, encodage : {Colors.ENDC}{encoding_detected}{Colors.GREEN} conversion utf-8") else : - log.debug(f"{Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.DEBUG}, encodage : {Colors.ENDC}{encoding_detected}") + log.debug(f"File: {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.DEBUG}, encodage : {Colors.ENDC}{encoding_detected}") except FileNotFoundError: log.error(f"The dat file {Colors.ENDC}{safe_relpath(ENTRY_FILE)} {Colors.ERROR}did not exist") global_data.error_count += 1 except Exception as e: - log.error(f"An error occurred (datToThFiles): {Colors.ENDC}{e}{Colors.ERROR}, file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"An error occurred when reading dat file: {Colors.ENDC}{e}{Colors.ERROR}, file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") global_data.error_count += 1 @@ -1781,12 +1741,18 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : totdata = f"\t## Liste inputs\n" totMapsPlan = "" totMapsExtended = "" + totReadMe = "" + totReadMeError = "" + totReadMeFixPoint = f"cs {crs_wkt}\n" # Tableau global pour stocker toutes les stations stationList = pd.DataFrame(columns=['StationName', 'Survey_Name_01', 'Survey_Name_02']) section0 = True; + ################################################################################################# + # 2 : Boucle pour lire les surveys au format dat # + ################################################################################################# for section in sections: listStationSection = pd.DataFrame(columns=['StationName', 'Survey_Name']) @@ -1827,9 +1793,14 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : section_data['SURVEY_TITLE'] = lines[0].strip() lines = lines[1:] # Supprimer la première ligne + jumpLine = False + for line in lines: line = line.strip() - if line.startswith('SURVEY NAME:'): + if jumpLine == True : + jumpLine = False + line = line.strip() + elif line.startswith('SURVEY NAME:'): section_data['SURVEY_NAME'] = sanitize_filename(line.split(':', 1)[1].strip()) elif line.startswith('SURVEY DATE:'): # current_field = 'DATE' @@ -1841,7 +1812,7 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : section_data['SURVEY_DATE'] = date_convertie if section_data['SURVEY_DATE'] == None or section_data['SURVEY_DATE'] == '' : section_data['SURVEY_DATE'] = "2000 01 01" - log.warning(f"Attention, survey {Colors.ENDC}{section_data['SURVEY_NAME']}{Colors.WARNING} with no date, add default date 2000 01 01 ") + log.warning(f"Survey {Colors.ENDC}{section_data['SURVEY_NAME']}{Colors.WARNING} with no date, add default date 2000 01 01 ") if len(date_parts) > 1: section_data['COMMENT'] = date_parts[1].strip() elif line.startswith('SURVEY TEAM:'): @@ -1854,7 +1825,7 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : # current_field = 'DECLINATION' # Découper la ligne en trois parties declination_part = line.split(':', 1)[1].strip() - + jumpLine = True # Sauter une ligne après la ligne DECLINATION # Extraire DECLINATION (premier nombre) declination_val = declination_part.split()[0] section_data['DECLINATION'] = declination_val @@ -1867,6 +1838,7 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : if 'CORRECTIONS:' in format_part: corrections_val = format_part.split('CORRECTIONS:', 1)[1].strip() section_data['CORRECTIONS'] = corrections_val + else : if line.strip() != '' : section_data['DATA'].append(line.strip()) @@ -1879,79 +1851,35 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : section_data['STATION'] = listStationSection data.append(section_data) unique_id += 1 + ################################################################################################# - # Détecter les survey avec plusieurs points de départ # + # Détecter les surveys avec plusieurs points de départ # ################################################################################################# points = pointsUniques(section_data, crs_wkt) if len(points) > 1 : - log.warning(f"Points {Colors.ENDC}{points}{Colors.ERROR} uniques dans la section {Colors.ENDC}{section_data['SURVEY_NAME']}: ") + log.warning(f"Points {Colors.ENDC}{points}{Colors.WARNING} uniques dans la section {Colors.ENDC}{section_data['SURVEY_NAME']}") # global_data.error_count += 1 else : log.debug(f"Points {Colors.ENDC}{points}{Colors.DEBUG} uniques dans la section {section_data['SURVEY_NAME']}") + - - ################################################################################################# # Grouper les sections ayant même date team et un point commun # ################################################################################################# - duplicates = find_duplicates_by_date_and_team(data) - - # for d in duplicates: - # print(d['IDS']) - # for i in range (len(d['IDS'])) : - # log.debug(f"ID: {data[d['IDS'][i]]['ID']}, DATE: {data[d['IDS'][i]]['SURVEY_DATE']}, TEAM: {data[d['IDS'][i]]['SURVEY_TEAM']}, Station : {d['COMMON_STATIONS']}") - # print() - - - - oldLen = len(data) - - # for line in data : - # if line['ID'] == 3 : - # log.debug(f"ID: {Colors.ENDC}{line['ID']}") - # log.debug(f"SURVEY TITLE: {Colors.ENDC}{line['SURVEY_TITLE']}") - # log.debug(f"SURVEY NAME: {Colors.ENDC}{line['SURVEY_NAME']}") - # log.debug(f"SURVEY DATE: {Colors.ENDC}{line['SURVEY_DATE']}") - # log.debug(f"COMMENT: {Colors.ENDC}{line['COMMENT']}") - # log.debug(f"SURVEY TEAM: {Colors.ENDC}{line['SURVEY_TEAM']}") - # log.debug(f"DECLINATION: {Colors.ENDC}{line['DECLINATION']}") - # log.debug(f"FORMAT: {Colors.ENDC}{line['FORMAT']}") - # log.debug(f"CORRECTIONS: {Colors.ENDC}{line['CORRECTIONS']}") - # log.debug(f"DATA: {Colors.ENDC}{(line['DATA'])}") - # log.debug(f"DATA Qté: {Colors.ENDC}{len(line['DATA'])}") - # log.debug(f"STATION: {Colors.ENDC}{(line['STATION'])}") - # log.debug(f"SOURCE: {Colors.ENDC}{line['SOURCE']}\n") - # # print(f"DATA: {Colors.ENDC}{line['DATA']}") + duplicates = find_duplicates_by_date_and_team(data) data = merge_duplicate_surveys(data, duplicates) - # for line in data : - # if line ['ID'] == 10000 : - # log.debug(f"ID: {Colors.ENDC}{line['ID']}") - # log.debug(f"SURVEY TITLE: {Colors.ENDC}{line['SURVEY_TITLE']}") - # log.debug(f"SURVEY NAME: {Colors.ENDC}{line['SURVEY_NAME']}") - # log.debug(f"SURVEY DATE: {Colors.ENDC}{line['SURVEY_DATE']}") - # log.debug(f"COMMENT: {Colors.ENDC}{line['COMMENT']}") - # log.debug(f"SURVEY TEAM: {Colors.ENDC}{line['SURVEY_TEAM']}") - # log.debug(f"DECLINATION: {Colors.ENDC}{line['DECLINATION']}") - # log.debug(f"FORMAT: {Colors.ENDC}{line['FORMAT']}") - # log.debug(f"CORRECTIONS: {Colors.ENDC}{line['CORRECTIONS']}") - # log.debug(f"DATA: {Colors.ENDC}{(line['DATA'])}") - # log.debug(f"DATA Qté: {Colors.ENDC}{len(line['DATA'])}") - # log.debug(f"STATION: {Colors.ENDC}{(line['STATION'])}") - # log.debug(f"SOURCE: {Colors.ENDC}{line['SOURCE']}\n") - # # print(f"DATA: {Colors.ENDC}{line['DATA']}") - - log.info(f"Read dat file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.GREEN} with {Colors.ENDC}{len(data)}/{oldLen}{Colors.GREEN} survey") + log.info(f"Read dat file : {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.GREEN} with {Colors.ENDC}{len(data)}/{len(data)}{Colors.GREEN} survey") ################################################################################################# - # Créer fichier th converti # + # Créer le dossier pour les fichiers convertis # ################################################################################################# if data[0]['SURVEY_TITLE'] !="" : @@ -1971,41 +1899,30 @@ def datToThFiles (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "") : # print(f"destination_path : {_destination}") os.remove(_destination) + # Trie des données par date + data = sorted(data, key=lambda x: x['SURVEY_DATE'] or "") + + ################################################################################################# + # 3 : Boucle pour créer les surveys au format th # + ################################################################################################# + + surveyCount = 1 + SurveyListEqui = [] + + totReadMe += f"* Source file: {os.path.basename(ENTRY_FILE)}\n" for _line in data : - - th_file = """ -encoding utf-8 -# File generated by pyCreateTh.py version {VERSION} date: {DATE} -survey {SURVEY_NAME} -title "{COMMENT}" - -\tcenterline -\t\tdate {SURVEY_DATE} -\t\t# team {SURVEY_TEAM} - -{FIX_POINTS} - -\t\t# explo-date ???? -\t\t# explo-team "????" - -\t\t# FORMAT: {FORMAT}, CORRECTIONS: {CORRECTIONS} -\t\tunits length {LENGTH} -\t\tunits compass {COMPASS} -\t\tunits clino {CLINO} -\t\t{DATA_FORMAT} - -#{DATA} - -\tendcenterline -endsurvey - -{SOURCE} - - """ - - output_file = folderDest + "\\Data\\" + sanitize_filename(_line['SURVEY_NAME']) + ".th" + # output_file = folderDest + "\\Data\\" + sanitize_filename(_line['SURVEY_NAME']) + ".th" + output_file = f"{folderDest}\\Data\\Survey_{surveyCount:02d}.th" + SurveyNameCount = { + 'surveyCount' :f"Survey_{surveyCount:02d}", + 'SURVEY_NAME': _line['SURVEY_NAME'] + } + + SurveyListEqui.append(SurveyNameCount) + ################################################################################################# # gestion des déclinaisons # ################################################################################################# @@ -2037,17 +1954,18 @@ endsurvey if len(list_common_points) >= 1 : fixPoint += f"\t\tcs {crs_wkt}\n" for point in list_common_points : + totReadMeFixPoint += f"\tFix point: {point[0]} [{point[2]:.3f} m, {point[3]:.3f} m, {point[4]:.3f} m], in Survey_{surveyCount:02d}\n" if point[1] == 'm' : - fixPoint += f"\t\tfix {point[0]} {point[2]} {point[3]} {point[4]}\n" + fixPoint += f"\t\tfix {point[0]} {point[2]:.3f} {point[3]:.3f} {point[4]:.3f}\n" elif point[1] == 'f' : - fixPoint += f"\t\tfix {point[0]} {point[2]*0.3048} {point[3]*0.3048} {point[4]*0.3048} # Conversion feet - meter\n" + fixPoint += f"\t\tfix {point[0]} {point[2]*0.3048:.3f} {point[3]*0.3048:.3f} {point[4]*0.3048:.3f} # Conversion feet - meter\n" ################################################################################################# # Gestion des formats ################################################################################################# - if _line['FORMAT'] is None or len(_line['FORMAT']) < 11: - log.error(f"Error in format code ID {Colors.ENDC}{_line['ID']}") + if _line['FORMAT'] is None or len(_line['FORMAT']) < 11 or len(_line['FORMAT']) > 12 : + log.error(f"Error in format code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") log.debug(f"Error in format code SURVEY_NAME {Colors.ENDC}{_line['SURVEY_NAME']}") log.debug(f"Error in format code SURVEY_DATE {Colors.ENDC}{_line['SURVEY_DATE']}") log.debug(f"SURVEY TITLE: {Colors.ENDC}{_line['SURVEY_TITLE']}") @@ -2061,47 +1979,58 @@ endsurvey log.debug(f"STATION: {Colors.ENDC}{(_line['STATION'])}") log.debug(f"SOURCE: {Colors.ENDC}{_line['SOURCE']}\n") global_data.error_count += 1 + totReadMeError += f"\tError in format code {_line['FORMAT']} in Survey_{surveyCount:02d}\n" - if _line['FORMAT'][0] == 'D' : compass = 'degree' - elif _line['FORMAT'][0] == 'R' : compass = 'grads' + dataFormat = "" + type_Data = "normal" + + if _line['FORMAT'][0] == 'D' : compass = 'compass degree' + elif _line['FORMAT'][0] == 'R' : compass = 'compass grads' else : compass = 'Compass_error' - log.error("Compass bearing unit 'quads' not yet implemented") + log.error(f"Compass bearing unit 'quads' not yet implemented in {Colors.ENDC}Survey_{surveyCount:02d}") global_data.error_count += 1 + totReadMeError += f"\tCompass bearing unit 'quads' not yet implemented in survey Survey_{surveyCount:02d}\n" - if _line['FORMAT'][1] == 'D' : length = 'feet' - elif _line['FORMAT'][1] == 'M' : length = 'meter' + if _line['FORMAT'][1] == 'D' : length = 'length feet' + elif _line['FORMAT'][1] == 'M' : length = 'length meter' else : length = 'Length_error' - log.error("Length unit 'Feet and Inches' not yet implemented") + log.error(f"Length unit 'Feet and Inches' not yet implemented in {Colors.ENDC}Survey_{surveyCount:02d}") global_data.error_count += 1 + totReadMeError += f"\tLength unit 'Feet and Inches' not yet implemented in Survey_{surveyCount:02d}\n" - if _line['FORMAT'][3] == 'D' : clino = 'degree' - elif _line['FORMAT'][3] == 'R' : clino = 'grads' + if _line['FORMAT'][3] == 'D' : clino = 'clino degree' + elif _line['FORMAT'][3] == 'R' : clino = 'clino grads' # elif _line['FORMAT'][3] == 'G' : clino = 'percent' # %Grades à vérifier? # elif _line['FORMAT'][3] == 'M' : clino = 'grads' # Degrees and Minutes - # elif _line['FORMAT'][3] == 'W' : clino = 'grads' # Depth Gauge + elif _line['FORMAT'][3] == 'W' : + clino = 'clino degree' # Depth Gauge + type_Data = "normal" # Depth Gauge else : clino = 'Inclination_error' - log.error("Inclination unit not yet implemented") + log.error(f"Inclination unit not yet implemented in {Colors.ENDC}Survey_{surveyCount:02d}") global_data.error_count += 1 + totReadMeError += f"\tInclination unit not yet implemented in Survey_{surveyCount:02d}\n" - dataFormat = "" + if _line['FORMAT'][4] == 'U' : dataFormat = dataFormat + " up" elif _line['FORMAT'][4] == 'D' : dataFormat = dataFormat + " down" elif _line['FORMAT'][4] == 'R' : dataFormat = dataFormat + " right" elif _line['FORMAT'][4] == 'L' : dataFormat = dataFormat + " left" else : - log.error(f"Error in format str 4 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 4 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") global_data.error_count += 1 + totReadMeError += f"\tError in format str 4 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" if _line['FORMAT'][5] == 'U' : dataFormat = dataFormat + " up" elif _line['FORMAT'][5] == 'D' : dataFormat = dataFormat + " down" elif _line['FORMAT'][5] == 'R' : dataFormat = dataFormat + " right" elif _line['FORMAT'][5] == 'L' : dataFormat = dataFormat + " left" else : - log.error(f"Error in format str 5code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 5 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 5 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 if _line['FORMAT'][6] == 'U' : dataFormat = dataFormat + " up" @@ -2109,7 +2038,8 @@ endsurvey elif _line['FORMAT'][6] == 'R' : dataFormat = dataFormat + " right" elif _line['FORMAT'][6] == 'L' : dataFormat = dataFormat + " left" else : - log.error(f"Error in format str 6 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 6 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 6 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 if _line['FORMAT'][7] == 'U' : dataFormat = dataFormat + " up" @@ -2117,16 +2047,20 @@ endsurvey elif _line['FORMAT'][7] == 'R' : dataFormat = dataFormat + " right" elif _line['FORMAT'][7] == 'L' : dataFormat = dataFormat + " left" else : - log.error(f"Error in format str 7 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 7 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 7 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 if _line['FORMAT'][10] == 'L' : dataFormat = " length" + dataFormat elif _line['FORMAT'][10] == 'A' : dataFormat = " compass" + dataFormat - elif _line['FORMAT'][10] == 'D' : dataFormat = " clino" + dataFormat + elif _line['FORMAT'][10] == 'D' : + if clino == 'depth feet' : dataFormat = " depthchange" + dataFormat + else : dataFormat = " clino" + dataFormat elif _line['FORMAT'][10] == 'a' : dataFormat = " backcompass" + dataFormat elif _line['FORMAT'][10] == 'd' : dataFormat = " backclino" + dataFormat else : - log.error(f"Error in format str 10 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 10 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 10 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 if _line['FORMAT'][9] == 'L' : dataFormat = " length" + dataFormat @@ -2135,7 +2069,8 @@ endsurvey elif _line['FORMAT'][9] == 'a' : dataFormat = " backcompass" + dataFormat elif _line['FORMAT'][9] == 'd' : dataFormat = " backclino" + dataFormat else : - log.error(f"Error in format str 9 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 8 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 8 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 if _line['FORMAT'][8] == 'L' : dataFormat = " length" + dataFormat @@ -2144,32 +2079,36 @@ endsurvey elif _line['FORMAT'][8] == 'a' : dataFormat = " backcompass" + dataFormat elif _line['FORMAT'][8] == 'd' : dataFormat = " backclino" + dataFormat else : - log.error(f"Error in format str 8 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}") + log.error(f"Error in format str 8 code {Colors.ENDC}{_line['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{safe_relpath(ENTRY_FILE)}{Colors.ERROR} in {Colors.ENDC}Survey_{surveyCount:02d}") + totReadMeError += f"\tError in format str 8 code {_line['FORMAT']} in {safe_relpath(ENTRY_FILE)} in Survey_{surveyCount:02d}\n" global_data.error_count += 1 - dataFormat = "data normal from to" + dataFormat + " # comment" + dataFormat = "data " + type_Data + " from to" + dataFormat + " # comment" with open(str(output_file), "w+", encoding="utf-8") as f: - f.write(th_file.format( - VERSION = Version, - DATE=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), - SURVEY_NAME = sanitize_filename(_line['SURVEY_NAME']), - SURVEY_DATE = _line['SURVEY_DATE'], - SURVEY_TEAM = _line['SURVEY_TEAM'], - FORMAT = _line['FORMAT'], - COMPASS = compass, - LENGTH = length, - CLINO = clino, - DATA_FORMAT = dataFormat, - CORRECTIONS = _line['CORRECTIONS'], - DATA = formated_Station_List(dfDATA, dataFormat, length, ENTRY_FILE=ENTRY_FILE), - COMMENT = sanitize_filename(_line['SURVEY_NAME'] + " " + _line['COMMENT']).replace('"', "'").replace('_', " "), - FIX_POINTS = fixPoint, - SOURCE = '\n'.join('# ' + line for line in _line['SOURCE'].splitlines()), - ) - ) + f.write(global_data.thFileDat.format( + VERSION = Version, + DATE=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"), + # SURVEY_NAME = sanitize_filename(_line['SURVEY_NAME']), + SURVEY_NAME = f"Survey_{surveyCount:02d}", + SURVEY_DATE = _line['SURVEY_DATE'], + SURVEY_TEAM = _line['SURVEY_TEAM'], + FORMAT = _line['FORMAT'], + COMPASS = compass, + LENGTH = length, + CLINO = clino, + DATA_FORMAT = dataFormat, + CORRECTIONS = _line['CORRECTIONS'], + DATA = formated_Station_List(dfDATA, dataFormat, length, ENTRY_FILE=ENTRY_FILE), + COMMENT = sanitize_filename(_line['SURVEY_NAME'] + " " + _line['COMMENT']).replace('"', "'").replace('_', " "), + FIX_POINTS = fixPoint, + EXPLO_DATE = "????", + EXPLO_TEAM = "????", + SOURCE = '\n'.join('# ' + line for line in _line['SOURCE'].splitlines()), + ) + ) - totdata +=f"\tinput Data/{_line['SURVEY_NAME']}/{_line['SURVEY_NAME']}-tot.th\n" + totdata +=f"\tinput Data/Survey_{surveyCount:02d}/Survey_{surveyCount:02d}-tot.th\n" log.info(f"Therion file : {Colors.ENDC}{safe_relpath(output_file)}{Colors.GREEN} created from {Colors.ENDC}{os.path.basename(ENTRY_FILE)}") @@ -2179,8 +2118,11 @@ endsurvey _Config_PATH = CONFIG_PATH + "../../" - createThFolders( ENTRY_FILE = output_file, SCALE = args.scale, UPDATE = args.update, CONFIG_PATH = _Config_PATH,) + StatCreateFolder, stat = createThFolders( ENTRY_FILE = output_file, SCALE = args.scale, UPDATE = args.update, CONFIG_PATH = _Config_PATH,) + log.info(f"File: {Colors.ENDC}{os.path.basename(ENTRY_FILE)}.dat{Colors.INFO} compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m") + totReadMe += f"\tSurvey_{surveyCount:02d} compilation successful length: {stat["length"]} m, depth: {stat["depth"]} m\n" + _destination = output_file[:-3] + "\\Sources" destination_path = os.path.join(_destination, os.path.basename(output_file)) shutil.move(output_file, destination_path) @@ -2190,9 +2132,14 @@ endsurvey # print(f"destination_path : {_destination}") os.remove(_destination) - totMapsPlan += f"\tMP-{_line['SURVEY_NAME']}-Plan-tot@{_line['SURVEY_NAME']}\n\tbreak\n" - totMapsExtended += f"\tMC-{_line['SURVEY_NAME']}-Extended-tot@{_line['SURVEY_NAME']}\n\tbreak\n" + if not StatCreateFolder : + totMapsPlan += f"\tMP-Survey_{surveyCount:02d}-Plan-tot@Survey_{surveyCount:02d}\n\tbreak\n" + totMapsExtended += f"\tMC-Survey_{surveyCount:02d}-Extended-tot@Survey_{surveyCount:02d}\n\tbreak\n" + surveyCount += 1 +################################################################################################# +# 4 : Finalisation (remplissage des -tot.th et maps.th # +################################################################################################# ################################################################################################# # Gestion des equats @@ -2200,6 +2147,11 @@ endsurvey totdata +=f"\n" + dfEqui = pd.DataFrame(SurveyListEqui) + stationList = stationList.merge(dfEqui, how='left', left_on='Survey_Name_01', right_on='SURVEY_NAME') + stationList['Survey_Name_01'] = stationList['surveyCount'] + stationList.drop(columns=['SURVEY_NAME', 'surveyCount'], inplace=True) + _stationList = stationList.copy() # On numérote les doublons de Survey_Name pour chaque StationName @@ -2240,15 +2192,17 @@ endsurvey log.info(f"No 'equats' found in {Colors.ENDC}{ENTRY_FILE}") totdata +=f"\n\t## Appel des maps\n\tinput {SurveyTitle}-maps.th\n" + + if totReadMeError == "" : totReadMeError = "\tAny error, that's perfect !" config_vars = { 'fileName': SurveyTitle, - 'cavename': SurveyTitle.replace("_", " "), + 'caveName': SurveyTitle.replace("_", " "), 'Author': Author, 'Copyright': Copyright, 'Scale' : args.scale, 'Target' : "TARGET", - 'map_comment' : map_comment, + 'mapComment' : map_comment, 'club' : club, 'thanksto' : thanksto, 'datat' : datat, @@ -2257,6 +2211,9 @@ endsurvey 'totData' : totdata, 'configPath' : CONFIG_PATH, 'other_scraps_plan' : totMapsPlan, + 'readMeList' : totReadMe, + 'errorList' : totReadMeError, + 'fixPointList' : totReadMeFixPoint, 'other_scraps_extended' : totMapsExtended, 'file_info' : f"# File generated by pyCreateTh.py version {Version} date: {datetime.now().strftime("%Y.%m.%d-%H:%M:%S")}", } @@ -2290,7 +2247,7 @@ if __name__ == u'__main__': parser.print_help = colored_help.__get__(parser) parser.add_argument("--survey_file", help="The survey file (*.th, *.mak, *.dat,) to perform e.g. './Therion_file.th'", default="") parser.add_argument("--survey_name", help="Scrap name (if different from 'survey_file' name)", default="None") - #parser.add_argument("--proj", choices=['plan', 'elevation', 'extended', 'none'], help="The scrap projection to produce", default="plan") + parser.add_argument("--proj", choices=['All', 'Plan', 'Extended', 'None'], help="The scrap projection to produce", default="All") #parser.add_argument("--format", choices=['th2', 'plt'], help="Output format. Either th2 for producing skeleton for drawing or plt for visualizing in aven/loch", default="th2") parser.add_argument("--output", default="./", help="Output folder path") # parser.add_argument("--therion-path", help="Path to therion binary", default="therion") @@ -2354,6 +2311,7 @@ if __name__ == u'__main__': createThFolders( ENTRY_FILE = abspath(args.survey_file), TARGET = args.survey_name, + PROJECTION= args.proj, SCALE = args.scale, UPDATE = args.update, CONFIG_PATH = "") diff --git a/Scripts/pyCreateTh/requirements.txt b/Scripts/pyCreateTh/requirements.txt deleted file mode 100644 index 515722d..0000000 --- a/Scripts/pyCreateTh/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -numpy -ttkthemes -matplotlib -pandas -Shapely -Fiona -pyproj -scipy -netCDF4 -xarray -joblib -geopandas -motionless -salem -configparser