mirror of
https://github.com/Alex38Lyon/Synthese-PSM_LARRA.git
synced 2026-06-01 22:00:53 +00:00
pyCreateTh
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user