mirror of
https://github.com/Alex38Lyon/Synthese-PSM_LARRA.git
synced 2026-06-01 22:00:53 +00:00
update
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,12 +3,12 @@
|
||||
general_fonctions.py for pyCreateTh.py
|
||||
#############################################################################################
|
||||
"""
|
||||
import os, logging, sys, re, configparser, unicodedata
|
||||
import os, logging, sys, re, configparser, unicodedata, shutil
|
||||
import Lib.global_data as global_data
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog
|
||||
|
||||
|
||||
log = logging.getLogger("Logger")
|
||||
|
||||
#################################################################################################
|
||||
# Couleurs ANSI par niveau de log
|
||||
@@ -48,10 +48,6 @@ class Colors:
|
||||
|
||||
#################################################################################################
|
||||
def safe_relpath(path):
|
||||
"""
|
||||
Renvoie un chemin relatif si possible, sinon un chemin partiel à partir du dossier de référence.
|
||||
"""
|
||||
|
||||
abs_path = os.path.abspath(path)
|
||||
ref_path = os.path.abspath(os.getcwd())
|
||||
|
||||
@@ -119,38 +115,38 @@ def colored_help(parser):
|
||||
#################################################################################################
|
||||
# Mise au format des noms #
|
||||
#################################################################################################
|
||||
def sanitize_filename(th_name):
|
||||
def sanitize_filename(thName):
|
||||
"""
|
||||
Cleans a string to make it compatible with filenames on Windows, Linux, and macOS.
|
||||
Replaces special and accented characters with compatible characters.
|
||||
Replaces parentheses with underscores and enforces proper casing.
|
||||
|
||||
Args:
|
||||
th_name (str): The filename to clean.
|
||||
thName (str): The filename to clean.
|
||||
|
||||
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')
|
||||
thName = unicodedata.normalize('NFKD', thName).encode('ASCII', 'ignore').decode('ASCII')
|
||||
|
||||
# Replace parentheses with underscores
|
||||
th_name = th_name.replace('(', '_').replace(')', '_')
|
||||
thName = thName.replace('(', '_').replace(')', '_')
|
||||
|
||||
# Replace illegal characters with an underscore
|
||||
th_name = re.sub(r'[<>:"/\\|?*\']', '_', th_name) # Illegal on Windows
|
||||
th_name = re.sub(r'\s+', '_', th_name) # Spaces to underscores
|
||||
th_name = re.sub(r'[^a-zA-Z0-9._-]', '_', th_name) # Keep only allowed chars
|
||||
thName = re.sub(r'[<>:"/\\|?*\']', '_', thName) # Illegal on Windows
|
||||
thName = re.sub(r'\s+', '_', thName) # Spaces to underscores
|
||||
thName = re.sub(r'[^a-zA-Z0-9._-]', '_', thName) # Keep only allowed chars
|
||||
|
||||
# Convert to lowercase, then capitalize the first letter
|
||||
# th_name = th_name.lower().capitalize()
|
||||
# th_name = th_name.capitalize()
|
||||
# thName = thName.lower().capitalize()
|
||||
# thName = thName.capitalize()
|
||||
|
||||
# Suppression des underscores en début et fin
|
||||
th_name = th_name.strip('_')
|
||||
thName = thName.strip('_')
|
||||
|
||||
return th_name or "default_filename" # Avoid empty result
|
||||
return thName or "default_filename" # Avoid empty result
|
||||
|
||||
|
||||
#################################################################################################
|
||||
@@ -184,73 +180,71 @@ def select_file_tk_window():
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def read_config(config_file):
|
||||
def load_config(args, configIni="config.ini"):
|
||||
"""
|
||||
Lit le fichier de configuration et initialise les variables globales.
|
||||
Charge un fichier de configuration .ini et initialise les variables globales.
|
||||
|
||||
Args:
|
||||
config_file (str): Le chemin vers le fichier de configuration.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
args: Argument contenant le chemin du fichier principal.
|
||||
configIni: Nom du fichier de configuration.
|
||||
"""
|
||||
try:
|
||||
# Chemin potentiel du fichier config
|
||||
config_file = os.path.join(os.path.dirname(args.file), configIni)
|
||||
if not os.path.isfile(config_file):
|
||||
config_file = configIni # Fallback si fichier absent
|
||||
|
||||
# Initialize the configparser to read .ini files
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_file, encoding="utf-8")
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_file, encoding="utf-8")
|
||||
|
||||
if 'Survey_Data' in config and 'Author' in config['Survey_Data']:
|
||||
global_data.Author = config['Survey_Data']['Author']
|
||||
|
||||
if 'Survey_Data' in config and 'Copyright1' in config['Survey_Data']:
|
||||
global_data.Copyright = config['Survey_Data']['Copyright1'] + "\n" + config['Survey_Data']['Copyright2'] + "\n" + config['Survey_Data']['Copyright3'] + "\n"
|
||||
|
||||
if 'Survey_Data' in config and 'Copyright_Short' in config['Survey_Data']:
|
||||
global_data.CopyrightShort = config['Survey_Data']['Copyright_Short']
|
||||
survey_keys = {
|
||||
'Author': 'Author',
|
||||
'Copyright1': None,
|
||||
'Copyright2': None,
|
||||
'Copyright3': None,
|
||||
'Copyright_Short': 'CopyrightShort',
|
||||
'map_comment': 'mapComment',
|
||||
'club': 'club',
|
||||
'thanksto': 'thanksto',
|
||||
'datat': 'datat',
|
||||
'wpage': 'wpage',
|
||||
'cs': 'cs'
|
||||
}
|
||||
|
||||
for key, attr in survey_keys.items():
|
||||
if 'Survey_Data' in config and key in config['Survey_Data']:
|
||||
if key.startswith('Copyright') and all(
|
||||
k in config['Survey_Data'] for k in ['Copyright1', 'Copyright2', 'Copyright3']
|
||||
):
|
||||
global_data.Copyright = "\n".join([
|
||||
config['Survey_Data']['Copyright1'],
|
||||
config['Survey_Data']['Copyright2'],
|
||||
config['Survey_Data']['Copyright3']
|
||||
])
|
||||
elif attr:
|
||||
setattr(global_data, attr, config['Survey_Data'][key])
|
||||
|
||||
app_keys = {
|
||||
'template_path': 'templatePath',
|
||||
'station_by_scrap': ('stationByScrap', int),
|
||||
'final_therion_exe': ('finalTherionExe', lambda x: x.lower() == 'true'),
|
||||
'therion_path': 'therionPath',
|
||||
'survey_prefix_name': 'SurveyPrefixName',
|
||||
'shot_lines_in_th2_files': ('linesInTh2', lambda x: x.lower() == 'true'),
|
||||
'station_name_in_th2_files': ('stationNamesInTh2', lambda x: x.lower() == 'true'),
|
||||
'kSmooth': ('kSmooth', float),
|
||||
}
|
||||
|
||||
for key, value in app_keys.items():
|
||||
if 'Application_Data' in config and key in config['Application_Data']:
|
||||
attr, caster = (value, str) if isinstance(value, str) else value
|
||||
setattr(global_data, attr, caster(config['Application_Data'][key]))
|
||||
|
||||
if 'Survey_Data' in config and 'map_comment' in config['Survey_Data']:
|
||||
global_data.mapComment = config['Survey_Data']['map_comment']
|
||||
|
||||
if 'Survey_Data' in config and 'club' in config['Survey_Data']:
|
||||
global_data.club = config['Survey_Data']['club']
|
||||
|
||||
if 'Survey_Data' in config and 'thanksto' in config['Survey_Data']:
|
||||
global_data.thanksto = config['Survey_Data']['thanksto']
|
||||
|
||||
if 'Survey_Data' in config and 'datat' in config['Survey_Data']:
|
||||
global_data.datat = config['Survey_Data']['datat']
|
||||
|
||||
if 'Survey_Data' in config and 'wpage' in config['Survey_Data']:
|
||||
global_data.wpage = config['Survey_Data']['wpage']
|
||||
|
||||
if 'Survey_Data' in config and 'cs' in config['Survey_Data']:
|
||||
global_data.cs = config['Survey_Data']['cs']
|
||||
|
||||
if 'Application_Data' in config and 'template_path' in config['Application_Data']:
|
||||
global_data.templatePath = config['Application_Data']['template_path']
|
||||
|
||||
if 'Application_Data' in config and 'station_by_scrap' in config['Application_Data']:
|
||||
global_data.stationByScrap = int(config['Application_Data']['station_by_scrap'])
|
||||
|
||||
if 'Application_Data' in config and 'final_therion_exe' in config['Application_Data']:
|
||||
global_data.finalTherionExe = bool(config['Application_Data']['final_therion_exe'])
|
||||
|
||||
if 'Application_Data' in config and 'therion_path' in config['Application_Data']:
|
||||
global_data.therionPath = config['Application_Data']['therion_path']
|
||||
|
||||
if 'Application_Data' in config and 'therion_path' in config['Application_Data']:
|
||||
global_data.SurveyPrefixName = config['Application_Data']['survey_prefix_name']
|
||||
|
||||
if 'Application_Data' in config and 'shot_lines_in_th2_files' in config['Application_Data']:
|
||||
global_data.linesInTh2 = bool(config['Application_Data']['shot_lines_in_th2_files'])
|
||||
|
||||
if 'Application_Data' in config and 'station_name_in_th2_files' in config['Application_Data']:
|
||||
global_data.stationNamesInTh2 = bool(config['Application_Data']['station_name_in_th2_files'])
|
||||
|
||||
if 'Application_Data' in config and 'kSmooth' in config['Application_Data']:
|
||||
global_data.kSmooth = float(config['Application_Data']['kSmooth'])
|
||||
|
||||
return config_file
|
||||
|
||||
except Exception as e:
|
||||
log.critical(f"Reading {configIni} file error: {Colors.ENDC}{e}")
|
||||
exit(0)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
@@ -300,11 +294,8 @@ def setup_logger(logfile="app.log", debug_log=False):
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.handlers.clear()
|
||||
|
||||
|
||||
|
||||
min_level = logging.DEBUG if debug_log else logging.INFO
|
||||
|
||||
|
||||
# Console stderr handler — affichage à l'écran avec couleurs
|
||||
stderr_handler = logging.StreamHandler(sys.stderr)
|
||||
stderr_handler.setLevel(min_level)
|
||||
@@ -329,3 +320,106 @@ def release_log_file(logger):
|
||||
if isinstance(handler, logging.FileHandler):
|
||||
handler.close()
|
||||
logger.removeHandler(handler)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def copy_template_if_not_exists(template_path, destination_path):
|
||||
# Check if the destination folder exists
|
||||
try:
|
||||
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)}{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:
|
||||
log.critical(f"Copy template error: {Colors.ENDC}{e}")
|
||||
exit(0)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def add_copyright_header(file_path, copyright_text):
|
||||
# Lire le contenu du fichier
|
||||
with open(file_path, 'r', encoding="utf-8") as file:
|
||||
content = file.readlines()
|
||||
|
||||
# Vérifier si le copyright est déjà présent
|
||||
if not any("copyright" in line.lower() for line in content):
|
||||
# Ajouter le copyright en en-tête
|
||||
content.insert(0, f"{copyright_text}\n")
|
||||
|
||||
# Réécrire le fichier avec le copyright ajouté
|
||||
with open(file_path, 'w', encoding="utf-8") as file:
|
||||
file.writelines(content)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def copy_file_with_copyright(th_file, destination_path, copyright_text):
|
||||
# Vérifier si le fichier existe
|
||||
if os.path.exists(th_file):
|
||||
# Créer le dossier de destination s'il n'existe pas
|
||||
os.makedirs(destination_path, exist_ok=True)
|
||||
|
||||
_destFile = sanitize_filename(os.path.basename(th_file)[:-3]) + ".th"
|
||||
# Copier le fichier vers le dossier de destination
|
||||
dest_file = os.path.join(destination_path, _destFile)
|
||||
shutil.copy(th_file, dest_file)
|
||||
|
||||
# Ajouter le copyright dans l'en-tête si nécessaire
|
||||
add_copyright_header(dest_file, copyright_text)
|
||||
|
||||
log.debug(f"File {Colors.ENDC}{safe_relpath(th_file)}{Colors.GREEN} has been copied to {Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN} with the copyright header added.{Colors.ENDC}")
|
||||
else:
|
||||
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 update_template_files(template_path, variables, output_path):
|
||||
"""
|
||||
Process a Therion template file by replacing variables.
|
||||
|
||||
Args:
|
||||
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:
|
||||
# Read the content of the template file
|
||||
with open(template_path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
# Replace variables
|
||||
for var, value in variables.items():
|
||||
# Use regex to replace {variable} with its value
|
||||
pattern = r'\{' + re.escape(var) + r'\}'
|
||||
content = re.sub(pattern, str(value), content)
|
||||
|
||||
# Write the new file
|
||||
with open(output_path, 'w', encoding='utf-8') as file:
|
||||
file.write(content)
|
||||
|
||||
log.info(f"Update template successfully: {Colors.ENDC}{safe_relpath(output_path)}")
|
||||
|
||||
# Delete the original template file
|
||||
os.remove(template_path)
|
||||
|
||||
except FileNotFoundError:
|
||||
log.error(f"Template file {Colors.ENDC}{template_path}{Colors.ERROR} not found")
|
||||
global_Data.error_count += 1
|
||||
|
||||
except PermissionError:
|
||||
log.error(f"Insufficient permissions to write the file")
|
||||
global_Data.error_count += 1
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"An error occurred (update_template_files): {Colors.ENDC}{e}")
|
||||
global_Data.error_count += 1
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ error_count = 0 # Compteur d'erreurs
|
||||
|
||||
## [Survey_Data] default values
|
||||
Author = "Created by pyCreateTh.py"
|
||||
Copyright = "# global_data.Copyright (C) pyCreateTh.py"
|
||||
Copyright = "# Copyright (C) pyCreateTh.py"
|
||||
CopyrightShort = "Licence (C) pyCreateTh.py"
|
||||
mapComment = "Created by pyCreateTh.py"
|
||||
cs = "UTM30"
|
||||
|
||||
@@ -9,6 +9,7 @@ from os.path import join
|
||||
import Lib.global_data as global_data
|
||||
from Lib.general_fonctions import Colors
|
||||
|
||||
|
||||
log = logging.getLogger("Logger")
|
||||
|
||||
#################################################################################################
|
||||
|
||||
+244
-308
@@ -38,7 +38,7 @@ En cours :
|
||||
|
||||
"""
|
||||
|
||||
Version = "2025.07.02"
|
||||
Version = "2025.07.04"
|
||||
|
||||
#################################################################################################
|
||||
#################################################################################################
|
||||
@@ -58,13 +58,14 @@ from contextlib import redirect_stdout
|
||||
from Lib.survey import SurveyLoader, NoSurveysFoundException
|
||||
from Lib.therion import compile_template, compile_file, get_stats_from_log
|
||||
from Lib.general_fonctions import setup_logger, Colors, safe_relpath, colored_help
|
||||
from Lib.general_fonctions import read_config, select_file_tk_window, release_log_file, sanitize_filename
|
||||
from Lib.general_fonctions import load_config, select_file_tk_window, release_log_file, sanitize_filename
|
||||
from Lib.general_fonctions import copy_template_if_not_exists, add_copyright_header, copy_file_with_copyright, update_template_files
|
||||
import Lib.global_data as globalData
|
||||
from Lib.pytro2th.tro2th import convert_tro #Version local modifiée
|
||||
|
||||
|
||||
|
||||
#################################################################################################
|
||||
configIni = "config.ini" # Default config file name
|
||||
debug_log = False # Mode debug des messages
|
||||
|
||||
|
||||
@@ -88,164 +89,15 @@ class StationNameAccessor:
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def copy_template_if_not_exists(template_path, destination_path):
|
||||
# Check if the destination folder exists
|
||||
try:
|
||||
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)}{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:
|
||||
log.critical(f"Copy template error: {Colors.ENDC}{e}")
|
||||
exit(0)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def add_copyright_header(file_path, copyright_text):
|
||||
# Lire le contenu du fichier
|
||||
with open(file_path, 'r', encoding="utf-8") as file:
|
||||
content = file.readlines()
|
||||
|
||||
# Vérifier si le copyright est déjà présent
|
||||
if not any("copyright" in line.lower() for line in content):
|
||||
# Ajouter le copyright en en-tête
|
||||
content.insert(0, f"{copyright_text}\n")
|
||||
|
||||
# Réécrire le fichier avec le copyright ajouté
|
||||
with open(file_path, 'w', encoding="utf-8") as file:
|
||||
file.writelines(content)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def copy_file_with_copyright(th_file, destination_path, copyright_text):
|
||||
|
||||
# Vérifier si le fichier existe
|
||||
if os.path.exists(th_file):
|
||||
# Créer le dossier de destination s'il n'existe pas
|
||||
os.makedirs(destination_path, exist_ok=True)
|
||||
|
||||
_destFile = sanitize_filename(os.path.basename(th_file)[:-3]) + ".th"
|
||||
# Copier le fichier vers le dossier de destination
|
||||
dest_file = os.path.join(destination_path, _destFile)
|
||||
shutil.copy(th_file, dest_file)
|
||||
|
||||
# Ajouter le copyright dans l'en-tête si nécessaire
|
||||
add_copyright_header(dest_file, copyright_text)
|
||||
|
||||
log.debug(f"File {Colors.ENDC}{safe_relpath(th_file)}{Colors.GREEN} has been copied to {Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN} with the copyright header added.{Colors.ENDC}")
|
||||
else:
|
||||
log.error(f"The file .th does not exist {Colors.ENDC}{safe_relpath(th_file)}")
|
||||
globalData.error_count += 1
|
||||
|
||||
|
||||
#################################################################################################
|
||||
# Remplir les template avec les variables vers output_path # #
|
||||
#################################################################################################
|
||||
def update_template_files(template_path, variables, output_path):
|
||||
"""
|
||||
Process a Therion template file by replacing variables.
|
||||
|
||||
Args:
|
||||
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:
|
||||
# Read the content of the template file
|
||||
with open(template_path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
# Replace variables
|
||||
for var, value in variables.items():
|
||||
# Use regex to replace {variable} with its value
|
||||
pattern = r'\{' + re.escape(var) + r'\}'
|
||||
content = re.sub(pattern, str(value), content)
|
||||
|
||||
# Write the new file
|
||||
with open(output_path, 'w', encoding='utf-8') as file:
|
||||
file.write(content)
|
||||
|
||||
log.info(f"Update template successfully: {Colors.ENDC}{safe_relpath(output_path)}")
|
||||
|
||||
# Delete the original template file
|
||||
os.remove(template_path)
|
||||
|
||||
except FileNotFoundError:
|
||||
log.error(f"Template file {Colors.ENDC}{template_path}{Colors.ERROR} not found")
|
||||
globalData.error_count += 1
|
||||
|
||||
except PermissionError:
|
||||
log.error(f"Insufficient permissions to write the file")
|
||||
globalData.error_count += 1
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"An error occurred (update_template_files): {Colors.ENDC}{e}")
|
||||
globalData.error_count += 1
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def parse_therion_surveysOld(file_path):
|
||||
"""
|
||||
Reads a Therion file and extracts survey names.
|
||||
|
||||
Args:
|
||||
file_path (str): Path to the Therion file to parse
|
||||
|
||||
Returns:
|
||||
list: List of survey names
|
||||
|
||||
"""
|
||||
|
||||
survey_names = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
# Read all lines from the file
|
||||
lines = file.readlines()
|
||||
|
||||
for line in lines:
|
||||
# Look for lines starting with survey
|
||||
line = line.strip()
|
||||
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 ')
|
||||
survey_name = line[start_index:end_index].strip()
|
||||
survey_names.append(survey_name)
|
||||
|
||||
except FileNotFoundError:
|
||||
log.error(f"File {Colors.ENDC}{safe_relpath(file_path)}{Colors.ERROR} not found.{Colors.ENDC}")
|
||||
globalData.error_count += 1
|
||||
|
||||
except PermissionError:
|
||||
log.error(f"Insufficient permissions to read {Colors.ENDC}{safe_relpath(file_path)}")
|
||||
globalData.error_count += 1
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"An error occurred (parse_therion_surveys): {Colors.ENDC}{e}{Colors.ERROR}, file: {Colors.ENDC}{safe_relpath(file_path)}")
|
||||
globalData.error_count += 1
|
||||
|
||||
return survey_names
|
||||
|
||||
def parse_therion_surveys(file_path):
|
||||
"""
|
||||
Reads a Therion file and extracts survey names.
|
||||
|
||||
"""Parse les enquêtes Therion à partir d'un fichier.
|
||||
|
||||
Args:
|
||||
file_path (str): Path to the Therion file to parse
|
||||
|
||||
file_path (str): Le chemin d'accès au fichier à analyser.
|
||||
|
||||
Returns:
|
||||
list: List of survey names
|
||||
|
||||
"""
|
||||
|
||||
list: Une liste des noms d'enquête trouvés dans le fichier.
|
||||
"""
|
||||
survey_names = []
|
||||
|
||||
try:
|
||||
@@ -279,26 +131,18 @@ def parse_therion_surveys(file_path):
|
||||
|
||||
return survey_names
|
||||
|
||||
#################################################################################################
|
||||
def str_to_bool(value):
|
||||
"""
|
||||
Function to convert string to boolean
|
||||
"""
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if value.lower() in ('true', '1', 'yes', 'y'):
|
||||
return True
|
||||
elif value.lower() in ('false', '0', 'no', 'n'):
|
||||
return False
|
||||
else:
|
||||
raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}")
|
||||
|
||||
#################################################################################################
|
||||
def convert_to_line_polaire_df(df_lines):
|
||||
"""
|
||||
Convertit un DataFrame de lignes cartésiennes (x1, y1, x2, y2, name1, name2)
|
||||
"""Convertit un DataFrame de lignes cartésiennes (x1, y1, x2, y2, name1, name2)
|
||||
en un DataFrame avec représentation polaire (x1, y1, azimut_deg, longueur, name1, name2).
|
||||
|
||||
Args:
|
||||
df_lines (pd.DataFrame): Le DataFrame contenant les lignes à convertir.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: Un DataFrame avec les colonnes polaires.
|
||||
"""
|
||||
|
||||
try:
|
||||
# Forcer la conversion des colonnes numériques
|
||||
df_lines = df_lines.copy() # évite de modifier l'original
|
||||
@@ -349,33 +193,27 @@ def convert_to_line_polaire_df(df_lines):
|
||||
globalData.error_count += 1
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def parse_xvi_file(th_name_xvi):
|
||||
"""
|
||||
Parse un fichier .xvi et extrait les stations et les lignes.
|
||||
def parse_xvi_file(thNameXvi):
|
||||
"""Parse un fichier .xvi et extrait les stations et les lignes.
|
||||
|
||||
Args:
|
||||
th_name_xvi (str): chemin complet du fichier .xvi à lire.
|
||||
thNameXvi (str): chemin complet du fichier .xvi à lire.
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
- stations (dict): dictionnaire des stations indexées par "x.y".
|
||||
- lines (list): liste des lignes [x1, y1, x2, y2, station1, station2].
|
||||
- x_bounds (tuple): (x_min, x_max)
|
||||
- y_bounds (tuple): (y_min, y_max)
|
||||
- ecarts (tuple): (x_ecart, y_ecart)
|
||||
tuple: Un tuple contenant les stations, les lignes, et les bornes (x_min, x_max, y_min, y_max, x_ecart, y_ecart).
|
||||
"""
|
||||
|
||||
stations = {}
|
||||
lines = []
|
||||
splays = []
|
||||
|
||||
with open(join(th_name_xvi), "r", encoding="utf-8") as f:
|
||||
with open(join(thNameXvi), "r", encoding="utf-8") as f:
|
||||
xvi_content = f.read()
|
||||
xvi_stations, xvi_shots = xvi_content.split("XVIshots")
|
||||
xviStations, xviShots = xvi_content.split("XVIshots")
|
||||
|
||||
# Extraction des stations
|
||||
for line in xvi_stations.split("\n"):
|
||||
for line in xviStations.split("\n"):
|
||||
match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line)
|
||||
if match:
|
||||
x, y, station_number, namespace = match.groups()
|
||||
@@ -387,14 +225,14 @@ def parse_xvi_file(th_name_xvi):
|
||||
stations[f"{x}.{y}"] = [x, y, station]
|
||||
|
||||
# Calcul des bornes x et y
|
||||
x_values = [float(value[0]) for value in stations.values()]
|
||||
y_values = [float(value[1]) for value in stations.values()]
|
||||
x_min, x_max = min(x_values), max(x_values)
|
||||
y_min, y_max = min(y_values), max(y_values)
|
||||
xValues = [float(value[0]) for value in stations.values()]
|
||||
yValues = [float(value[1]) for value in stations.values()]
|
||||
x_min, x_max = min(xValues), max(xValues)
|
||||
y_min, y_max = min(yValues), max(yValues)
|
||||
x_ecart = x_max - x_min
|
||||
y_ecart = y_max - y_min
|
||||
|
||||
for line in xvi_shots.split("\n"):
|
||||
for line in xviShots.split("\n"):
|
||||
match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s+(-?\d+\.\d+)\s+(-?\d+\.\d+)\s+(-?\d+\.\d+)(.*)}", line)
|
||||
if match:
|
||||
x1, y1, x2, y2, rest = match.groups()
|
||||
@@ -421,6 +259,15 @@ def parse_xvi_file(th_name_xvi):
|
||||
|
||||
#################################################################################################
|
||||
def assign_groups_and_ranks(df_lines):
|
||||
"""Assigne des groupes et des rangs aux lignes du DataFrame.
|
||||
|
||||
Args:
|
||||
df_lines (pd.DataFrame): Le DataFrame contenant les lignes à traiter.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: Un DataFrame avec les colonnes "group_id" et "rank_in_group" ajoutées.
|
||||
"""
|
||||
|
||||
G = nx.Graph()
|
||||
for _, row in df_lines.iterrows():
|
||||
G.add_edge(row["name1"], row["name2"])
|
||||
@@ -509,6 +356,16 @@ def assign_groups_and_ranks(df_lines):
|
||||
|
||||
#################################################################################################
|
||||
def add_start_end_splays(df_splays_complet, df_equates):
|
||||
"""Ajoute des splays de début et de fin au DataFrame des splays.
|
||||
|
||||
Args:
|
||||
df_splays_complet (pd.DataFrame): Le DataFrame complet des splays.
|
||||
df_equates (pd.DataFrame): Le DataFrame des équivalences.
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: Le DataFrame des splays mis à jour avec les nouveaux splays.
|
||||
"""
|
||||
|
||||
df_splays_new = df_splays_complet.copy()
|
||||
|
||||
for _, row in df_equates.iterrows():
|
||||
@@ -567,6 +424,23 @@ def add_start_end_splays(df_splays_complet, df_equates):
|
||||
|
||||
#################################################################################################
|
||||
def align_points(smoothX1, smoothY1, X, Y, smoothX2, smoothY2):
|
||||
"""Aligne les points en fonction de leur position l'un par rapport à l'autre.
|
||||
|
||||
Args:
|
||||
smoothX1 (float): Coordonnée X du premier point lissé.
|
||||
smoothY1 (float): Coordonnée Y du premier point lissé.
|
||||
X (float): Coordonnée X du point central.
|
||||
Y (float): Coordonnée Y du point central.
|
||||
smoothX2 (float): Coordonnée X du deuxième point lissé.
|
||||
smoothY2 (float): Coordonnée Y du deuxième point lissé.
|
||||
|
||||
Raises:
|
||||
ValueError: Si les deux points lissés sont confondus.
|
||||
|
||||
Returns:
|
||||
tuple: Les coordonnées des points lissés alignés.
|
||||
"""
|
||||
|
||||
# Vecteurs d'origine vers smooth1 et smooth2
|
||||
dx1, dy1 = smoothX1 - X, smoothY1 - Y
|
||||
dx2, dy2 = smoothX2 - X, smoothY2 - Y
|
||||
@@ -598,8 +472,20 @@ def align_points(smoothX1, smoothY1, X, Y, smoothX2, smoothY2):
|
||||
|
||||
#################################################################################################
|
||||
def wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max):
|
||||
"""Construit les murs en utilisant les lignes et les splays fournis.
|
||||
|
||||
Args:
|
||||
df_lines (pd.DataFrame): Le DataFrame des lignes.
|
||||
df_splays (pd.DataFrame): Le DataFrame des splays.
|
||||
x_min (float): La coordonnée X minimale.
|
||||
x_max (float): La coordonnée X maximale.
|
||||
y_min (float): La coordonnée Y minimale.
|
||||
y_max (float): La coordonnée Y maximale.
|
||||
|
||||
Returns:
|
||||
list: Une liste de murs construits.
|
||||
"""
|
||||
|
||||
|
||||
th2_walls=[]
|
||||
_list = ""
|
||||
|
||||
@@ -668,10 +554,10 @@ def wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max):
|
||||
group_id = match["group_id"].values[0]
|
||||
max_rank = df_lines_polaire[df_lines_polaire["group_id"] == group_id]["rank_in_group"].max()
|
||||
|
||||
df_splays_complet.at[idx, "bissectrice"] = match["azimut_deg"].values[0]
|
||||
df_splays_complet.at[idx, "longueur_ref"] = match["longueur"].values[0]
|
||||
df_splays_complet.at[idx, "group_id"] = group_id
|
||||
df_splays_complet.at[idx, "rank_in_group"] = max_rank + 1
|
||||
df_splays_complet.loc[idx, "bissectrice"] = match["azimut_deg"].values[0]
|
||||
df_splays_complet.loc[idx, "longueur_ref"] = match["longueur"].values[0]
|
||||
df_splays_complet.loc[idx, "group_id"] = group_id
|
||||
df_splays_complet.loc[idx, "rank_in_group"] = max_rank + 1
|
||||
|
||||
df_splays_complet = add_start_end_splays(df_splays_complet, df_equates)
|
||||
|
||||
@@ -679,17 +565,8 @@ def wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max):
|
||||
|
||||
df_splays_complet["delta_azimut"] = df_splays_complet["bissectrice"] - df_splays_complet["azimut_deg"]
|
||||
|
||||
df_splays_complet["proj"] = np.sin(np.radians(df_splays_complet["bissectrice"] - df_splays_complet["azimut_deg"])) * df_splays_complet["longueur"]
|
||||
|
||||
# Calcul de la projection : sin(delta azimut) * longueur_ref
|
||||
def calc_projection(row):
|
||||
try:
|
||||
delta = math.radians(row["bissectrice"] - row["azimut_deg"])
|
||||
return math.sin(delta) * row["longueur"]
|
||||
|
||||
except:
|
||||
return None
|
||||
|
||||
df_splays_complet["proj"] = df_splays_complet.apply(calc_projection, axis=1)
|
||||
df_splays_complet["group_id"] = df_splays_complet["group_id"].astype(int)
|
||||
df_splays_complet["rank_in_group"] = df_splays_complet["rank_in_group"].astype(int)
|
||||
|
||||
@@ -893,10 +770,6 @@ def wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max):
|
||||
return th2_walls, x_min, x_max, y_min, y_max
|
||||
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
|
||||
#################################################################################################
|
||||
# Création des dossiers à partir d'un th file #
|
||||
#################################################################################################
|
||||
@@ -908,23 +781,24 @@ def create_th_folders(ENTRY_FILE,
|
||||
UPDATE = False,
|
||||
CONFIG_PATH = "",
|
||||
totReadMeError = "") :
|
||||
"""
|
||||
Création des dossiers et fichiers à partir d'un fichier .th
|
||||
|
||||
"""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 (bool): Le mode de mise à jour.
|
||||
CONFIG_PATH (str): Le chemin vers le fichier de configuration.
|
||||
|
||||
Returns:
|
||||
True or False
|
||||
|
||||
"""
|
||||
ENTRY_FILE (str): Chemin du fichier Therion d'entrée.
|
||||
PROJECTION (str): Type de projection à utiliser.
|
||||
TARGET (str): Cible de la projection.
|
||||
FORMAT (str): Format de sortie, par défaut "th2".
|
||||
SCALE (str): Échelle à utiliser, par défaut "500".
|
||||
UPDATE (bool): Indique si l'on met à jour les fichiers existants.
|
||||
CONFIG_PATH (str): Chemin vers le fichier de configuration Therion.
|
||||
totReadMeError (str): Message d'erreur pour le fichier README.
|
||||
|
||||
Returns:
|
||||
bool: True si la création des dossiers et fichiers a réussi, False sinon.
|
||||
|
||||
"""
|
||||
|
||||
threads = []
|
||||
TH_NAME = sanitize_filename(os.path.splitext(os.path.basename(ENTRY_FILE))[0])
|
||||
DEST_PATH = os.path.dirname(ENTRY_FILE) + "/" + TH_NAME
|
||||
@@ -1083,16 +957,16 @@ def create_th_folders(ENTRY_FILE,
|
||||
other_scraps_plan = ""
|
||||
if PROJECTION.lower() == "plan" or PROJECTION.lower() == "all" and not flagErrorCompile :
|
||||
if UPDATE:
|
||||
th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Plan.xvi"
|
||||
thNameXvi = DEST_PATH + "/" + TH_NAME + "-Plan.xvi"
|
||||
else :
|
||||
th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Plan.xvi"
|
||||
thNameXvi = DEST_PATH + "/Data/" + TH_NAME + "-Plan.xvi"
|
||||
|
||||
log.info(f"Parsing Plan XVI file: {Colors.ENDC}{safe_relpath(th_name_xvi)}")
|
||||
log.info(f"Parsing Plan XVI file: {Colors.ENDC}{safe_relpath(thNameXvi)}")
|
||||
|
||||
stations = {}
|
||||
lines = []
|
||||
|
||||
stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart = parse_xvi_file(th_name_xvi)
|
||||
stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart = parse_xvi_file(thNameXvi)
|
||||
|
||||
# df_stations = pd.DataFrame.from_dict(stations, orient='index')
|
||||
df_lines = pd.DataFrame(lines, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
|
||||
@@ -1104,14 +978,8 @@ def create_th_folders(ENTRY_FILE,
|
||||
# Identifier les groupes avec au moins un splay non nul
|
||||
non_zero_groups = df_splays.loc[~df_splays["is_zero_length"], ["name1", "name2"]]
|
||||
non_zero_group_keys = set(tuple(x) for x in non_zero_groups.to_numpy())
|
||||
|
||||
def keep_row2(row):
|
||||
if not row["is_zero_length"]:
|
||||
return True
|
||||
return (row["name1"], row["name2"]) in non_zero_group_keys
|
||||
|
||||
|
||||
df_splays = df_splays[df_splays.apply(keep_row2, axis=1)]
|
||||
|
||||
df_splays = df_splays[(~df_splays["is_zero_length"]) | df_splays[["name1", "name2"]].apply(tuple, axis=1).isin(non_zero_group_keys) ]
|
||||
|
||||
# Supprimer la colonne temporaire si elle existe
|
||||
if "is_zero_length" in df_splays.columns:
|
||||
@@ -1193,7 +1061,7 @@ def create_th_folders(ENTRY_FILE,
|
||||
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 {}",
|
||||
+ os.path.basename(thNameXvi) + " 0 {}",
|
||||
)
|
||||
)
|
||||
if scrap_to_add >= 1 :
|
||||
@@ -1216,17 +1084,17 @@ def create_th_folders(ENTRY_FILE,
|
||||
other_scraps_extended = ""
|
||||
if PROJECTION.lower() == "extended" or PROJECTION.lower() == "all" and not flagErrorCompile :
|
||||
if UPDATE:
|
||||
th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Extended.xvi"
|
||||
thNameXvi = DEST_PATH + "/" + TH_NAME + "-Extended.xvi"
|
||||
else :
|
||||
th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi"
|
||||
thNameXvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi"
|
||||
|
||||
log.info(f"Parsing extended XVI file: {Colors.ENDC}{safe_relpath(th_name_xvi)}")
|
||||
log.info(f"Parsing extended XVI file: {Colors.ENDC}{safe_relpath(thNameXvi)}")
|
||||
|
||||
# Parse the Extended XVI file
|
||||
stations = {}
|
||||
lines = []
|
||||
|
||||
stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart = parse_xvi_file(th_name_xvi)
|
||||
stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart = parse_xvi_file(thNameXvi)
|
||||
|
||||
# df_stations = pd.DataFrame.from_dict(stations, orient='index')
|
||||
df_lines = pd.DataFrame(lines, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
|
||||
@@ -1237,13 +1105,9 @@ def create_th_folders(ENTRY_FILE,
|
||||
# Identifier les groupes avec au moins un splay non nul
|
||||
non_zero_groups = df_splays.loc[~df_splays["is_zero_length"], ["name1", "name2"]]
|
||||
non_zero_group_keys = set(tuple(x) for x in non_zero_groups.to_numpy())
|
||||
|
||||
def keep_row(row):
|
||||
if not row["is_zero_length"]:
|
||||
return True
|
||||
return (row["name1"], row["name2"]) in non_zero_group_keys
|
||||
|
||||
df_splays = df_splays[(~df_splays["is_zero_length"]) | df_splays[["name1", "name2"]].apply(tuple, axis=1).isin(non_zero_group_keys) ]
|
||||
|
||||
df_splays = df_splays[df_splays.apply(keep_row, axis=1)]
|
||||
|
||||
# Supprimer la colonne temporaire si elle existe
|
||||
if "is_zero_length" in df_splays.columns:
|
||||
@@ -1324,7 +1188,7 @@ def create_th_folders(ENTRY_FILE,
|
||||
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 {}",
|
||||
+ os.path.basename(thNameXvi) + " 0 {}",
|
||||
)
|
||||
)
|
||||
if scrap_to_add >= 1 :
|
||||
@@ -1391,16 +1255,16 @@ def create_th_folders(ENTRY_FILE,
|
||||
# lecture d'un fichier .mak #
|
||||
#################################################################################################
|
||||
def mak_to_th_file(ENTRY_FILE) :
|
||||
"""
|
||||
Convertit un fichier .mak en fichier .th.
|
||||
"""Convertit un fichier .mak en fichier .th.
|
||||
|
||||
Args:
|
||||
ENTRY_FILE (str): Le chemin vers le fichier .mak d'entrée.
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
bool: True si la conversion a réussi, False sinon.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# Liste des threads lancés
|
||||
threads = []
|
||||
|
||||
@@ -1683,17 +1547,19 @@ def mak_to_th_file(ENTRY_FILE) :
|
||||
|
||||
#################################################################################################
|
||||
def station_list(data, list, fixPoints, currentSurveyName) :
|
||||
"""
|
||||
Crée une liste de stations à partir des données fournies.
|
||||
"""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.
|
||||
currentSurveyName (str): Le nom de l'enquête en cours.
|
||||
|
||||
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']]
|
||||
@@ -1718,21 +1584,21 @@ def station_list(data, list, fixPoints, currentSurveyName) :
|
||||
|
||||
#################################################################################################
|
||||
def formated_station_list(df, dataFormat, unit = "meter", shortCurentFile ="None") :
|
||||
"""
|
||||
Formate la liste des stations selon le format spécifié.
|
||||
|
||||
"""Formate une liste de stations à partir d'un DataFrame.
|
||||
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).
|
||||
|
||||
dataFormat (str): Le format des données à utiliser pour le traitement.
|
||||
unit (str): L'unité de mesure à utiliser (par défaut "meter").
|
||||
shortCurentFile (str): Le nom du fichier en cours de traitement (pour les logs).
|
||||
|
||||
Returns:
|
||||
DataFrame: Le DataFrame formaté.
|
||||
DataFrame: Le DataFrame formaté avec les colonnes appropriées.
|
||||
"""
|
||||
|
||||
|
||||
# Remplacer les None/NaN par des espaces
|
||||
df = df.fillna(" ")
|
||||
|
||||
|
||||
# Conserver la première ligne (en-têtes) séparément
|
||||
header_row = df.iloc[0]
|
||||
@@ -1975,6 +1841,15 @@ def formated_station_list(df, dataFormat, unit = "meter", shortCurentFile ="None
|
||||
|
||||
#################################################################################################
|
||||
def find_duplicates_by_date_and_team(data):
|
||||
"""Finds duplicates in the data based on SURVEY_DATE and SURVEY_TEAM.
|
||||
|
||||
Args:
|
||||
data (list): A list of dictionaries containing survey data.
|
||||
|
||||
Returns:
|
||||
list: A list of dictionaries containing information about duplicates found.
|
||||
|
||||
"""
|
||||
grouped = defaultdict(list)
|
||||
|
||||
# Étape 1 : regroupement par (SURVEY_DATE, SURVEY_TEAM)
|
||||
@@ -2035,7 +1910,17 @@ def find_duplicates_by_date_and_team(data):
|
||||
return duplicates
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def find_duplicates_by_date(data):
|
||||
"""Finds duplicates in the data based on SURVEY_DATE.
|
||||
|
||||
Args:
|
||||
data (list): A list of dictionaries containing survey data.
|
||||
|
||||
Returns:
|
||||
list: A list of dictionaries containing information about duplicates found.
|
||||
"""
|
||||
|
||||
grouped = defaultdict(list)
|
||||
|
||||
# Étape 1 : regroupement uniquement par SURVEY_DATE
|
||||
@@ -2099,9 +1984,19 @@ def find_duplicates_by_date(data):
|
||||
return duplicates
|
||||
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def points_uniques(data, crs_wkt):
|
||||
"""Extrait les points uniques de la colonne 0 du DataFrame 'data' et les compare avec la colonne 1.
|
||||
Exclut les points présents dans 'crs_wkt' si fourni.
|
||||
|
||||
Args:
|
||||
data (DataFrame): Le DataFrame contenant les données.
|
||||
crs_wkt (list, optional): Une liste de points à exclure.
|
||||
|
||||
Returns:
|
||||
list: Une liste de points uniques.
|
||||
"""
|
||||
|
||||
# Création d'un DataFrame à partir des lignes de données
|
||||
rows = [line.split() for line in data['DATA']]
|
||||
dfDATA = pd.DataFrame(rows)
|
||||
@@ -2129,6 +2024,19 @@ def points_uniques(data, crs_wkt):
|
||||
|
||||
#################################################################################################
|
||||
def merge_duplicate_surveys(data, duplicates, id_offset=10000):
|
||||
"""Merges duplicate survey entries into a single entry.
|
||||
|
||||
Args:
|
||||
data (list): A list of dictionaries containing survey data.
|
||||
duplicates (list): A list of dictionaries containing information about duplicates found.
|
||||
id_offset (int, optional): An offset to apply to the IDs of merged entries. Defaults to 10000.
|
||||
|
||||
Returns:
|
||||
list: A list of merged survey entries.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
id_to_entry = {entry['ID']: entry for entry in data}
|
||||
merged_data = []
|
||||
used_ids = set()
|
||||
@@ -2233,7 +2141,20 @@ def merge_duplicate_surveys(data, duplicates, id_offset=10000):
|
||||
|
||||
|
||||
#################################################################################################
|
||||
def dat_survey_format_extract(section_data, headerData, currentSurveyName, fichier, totReadMeError) :
|
||||
def dat_survey_format_extract(section_data, headerData, currentSurveyName, fichier, totReadMeError):
|
||||
"""Extracts and validates the format code from the section data.
|
||||
|
||||
Args:
|
||||
section_data (dict): The section data containing survey information.
|
||||
headerData (dict): The header data for the survey.
|
||||
currentSurveyName (str): The name of the current survey.
|
||||
fichier (str): The file being processed.
|
||||
totReadMeError (str): A string to accumulate error messages.
|
||||
|
||||
Returns:
|
||||
dataFormat (str), length (int), compass (str), clino (str), totReadMeError (str)
|
||||
|
||||
"""
|
||||
|
||||
if section_data['FORMAT'] is None or len(section_data['FORMAT']) < 11 or len(section_data['FORMAT']) > 15 :
|
||||
log.error(f"Error in format code {Colors.ENDC}{section_data['FORMAT']}{Colors.ERROR} in {Colors.ENDC}{currentSurveyName}")
|
||||
@@ -2334,17 +2255,11 @@ def dat_survey_format_extract(section_data, headerData, currentSurveyName, fichi
|
||||
totReadMeError += f"\tInclination unit not yet implemented in {currentSurveyName}\n"
|
||||
|
||||
################################################ Section dimensions 4-7 ###############################################
|
||||
# dataFormat = Dimension(section_data['FORMAT'][4])
|
||||
# dataFormat += Dimension(section_data['FORMAT'][5])
|
||||
# dataFormat += Dimension(section_data['FORMAT'][6])
|
||||
# dataFormat += Dimension(section_data['FORMAT'][7])
|
||||
|
||||
dataFormat = " " + headerData[5].lower()
|
||||
dataFormat += " " + headerData[6].lower()
|
||||
dataFormat += " " + headerData[7].lower()
|
||||
dataFormat += " " + headerData[8].lower()
|
||||
|
||||
|
||||
################################################ Section Shot 8-11 ou 13 ###############################################
|
||||
if len(section_data['FORMAT']) == 11 or len(section_data['FORMAT']) == 12 or len(section_data['FORMAT']) == 13:
|
||||
if len(section_data['FORMAT']) == 13 : # UUUUDDDDSSSBL
|
||||
@@ -2369,9 +2284,19 @@ def dat_survey_format_extract(section_data, headerData, currentSurveyName, fichi
|
||||
|
||||
return dataFormat, length, compass, clino, totReadMeError
|
||||
|
||||
#
|
||||
# ################################################################################################
|
||||
|
||||
#################################################################################################
|
||||
def load_text_file_utf8(filepath, short_filename):
|
||||
"""Loads a text file with various encodings and converts it to UTF-8.
|
||||
|
||||
Args:
|
||||
filepath (str): The path to the file to be loaded.
|
||||
short_filename (str): The name of the file (for logging purposes).
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing the file content, a log message, and the encoding used.
|
||||
"""
|
||||
|
||||
encodings_to_try = [
|
||||
'utf-8-sig', # UTF-8 avec BOM
|
||||
'utf-8', # UTF-8 standard
|
||||
@@ -2919,6 +2844,17 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "",
|
||||
|
||||
#################################################################################################
|
||||
def wait_until_file_is_released(filepath, timeout=30):
|
||||
"""Wait until a file is released (i.e., not locked by another process).
|
||||
|
||||
Args:
|
||||
filepath (str): The path to the file to check.
|
||||
timeout (int, optional): The maximum time to wait in seconds. Defaults to 30.
|
||||
|
||||
Returns:
|
||||
bool: True if the file is released, False if the timeout is reached.
|
||||
|
||||
"""
|
||||
|
||||
start = time.time()
|
||||
while True:
|
||||
try:
|
||||
@@ -2979,36 +2915,43 @@ if __name__ == u'__main__':
|
||||
|
||||
#################################################################################################
|
||||
# Reading config.ini #
|
||||
#################################################################################################
|
||||
try:
|
||||
config_file = os.path.dirname(args.file) + "\\" + configIni
|
||||
if os.path.isfile(config_file):
|
||||
read_config(config_file)
|
||||
else :
|
||||
config_file = configIni
|
||||
read_config(configIni)
|
||||
|
||||
except ValueError as e:
|
||||
log.critical(f"Reading {configIni} file error: {Colors.ENDC}{e}")
|
||||
exit(0)
|
||||
|
||||
#################################################################################################
|
||||
config_file = load_config(args)
|
||||
|
||||
#################################################################################################
|
||||
# titre #
|
||||
#################################################################################################
|
||||
_titre =[f'********************************************************************************************************************************************\033[0m',
|
||||
f'* Conversion Th, Dat, Mak, Tro, files to Therion files and folders',
|
||||
f'* Script pyCreateTh by : {Colors.ENDC}alexandre.pont@yahoo.fr',
|
||||
f'* Version : {Colors.ENDC}{Version}',
|
||||
f'* Input file : {Colors.ENDC}{safe_relpath(args.file)}',
|
||||
f'* Output folder : {Colors.ENDC}{safe_relpath(splitext(abspath(args.file))[0])}',
|
||||
f'* Log file : {Colors.ENDC}{os.path.basename(output_log)}',
|
||||
f'* Config file: {Colors.ENDC}{safe_relpath(config_file)}',
|
||||
f'* ',
|
||||
f'* ',
|
||||
f'********************************************************************************************************************************************\033[0m']
|
||||
titre_largeur = 150
|
||||
bordure = "#" * titre_largeur + Colors.ENDC
|
||||
ansi_escape = re.compile(r'\x1b\[[0-9;]*m')
|
||||
|
||||
for i in range(11): log.info(_titre[i])
|
||||
def pad_line(texte, center=False):
|
||||
# Supprimer les séquences ANSI pour le calcul de longueur visuelle
|
||||
visible_len = len(ansi_escape.sub('', texte))
|
||||
espace_total = titre_largeur - visible_len - 2 # 2 pour les * à gauche et droite
|
||||
|
||||
if center:
|
||||
left = espace_total // 2
|
||||
right = espace_total - left
|
||||
return f"#{' ' * left}{texte}{' ' * right}{Colors.ENDC}{Colors.INFO}#"
|
||||
else:
|
||||
return f"# {texte}{' ' * max(0, espace_total - 1)}{Colors.INFO}#"
|
||||
|
||||
_titre = [
|
||||
bordure,
|
||||
pad_line(f"{Colors.BOLD}{Colors.YELLOW}Conversion Th, Dat, Mak, Tro, files to Therion files and folders", center=True),
|
||||
pad_line(f"Script pyCreateTh by : {Colors.BLUE}alexandre.pont@yahoo.fr"),
|
||||
pad_line(f"Version : {Colors.ENDC}{Version}"),
|
||||
pad_line(f"Input file : {Colors.ENDC}{safe_relpath(args.file)}"),
|
||||
pad_line(f"Output folder : {Colors.ENDC}{safe_relpath(splitext(abspath(args.file))[0])}"),
|
||||
pad_line(f"Log file : {Colors.ENDC}{os.path.basename(output_log)}"),
|
||||
pad_line(f"Config file: {Colors.ENDC}{safe_relpath(config_file)}"),
|
||||
pad_line(""),
|
||||
bordure
|
||||
]
|
||||
|
||||
for line in _titre:
|
||||
log.info(line)
|
||||
|
||||
|
||||
#################################################################################################
|
||||
@@ -3111,11 +3054,6 @@ if __name__ == u'__main__':
|
||||
Errorfiles = False
|
||||
)
|
||||
|
||||
# print(f"cavename: {fileTitle}")
|
||||
# print(f"coordinates: {coordinates}")
|
||||
# print(f"coordsyst: {coordsyst}")
|
||||
# print(f"fle_th_fnme: {fle_th_fnme}")
|
||||
|
||||
content, val, encodage = load_text_file_utf8(fle_th_fnme, os.path.basename(fle_th_fnme))
|
||||
|
||||
if encodage != "utf-8":
|
||||
@@ -3165,14 +3103,12 @@ if __name__ == u'__main__':
|
||||
release_log_file(log)
|
||||
|
||||
|
||||
# Supprimer le fichier cible s’il existe déjà
|
||||
# Supprimer le fichier cible si il existe déjà
|
||||
if os.path.isfile(destination_file):
|
||||
os.remove(destination_file)
|
||||
|
||||
shutil.move(output_log, destination_path)
|
||||
|
||||
print(output_log)
|
||||
print(destination_path)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,12 @@
|
||||
"wpage",
|
||||
"writecenterlineheader",
|
||||
"XTHERION"
|
||||
]
|
||||
],
|
||||
"yaml.schemas": {
|
||||
"c:\\Users\\alexa\\.vscode\\extensions\\continue.continue-1.0.15-win32-x64\\config-yaml-schema.json": [
|
||||
".continue/**/*.yaml",
|
||||
"file:///c%3A/Users/alexa/.continue/config.yaml"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user