pyCreateTh

This commit is contained in:
Alex38Lyon
2025-06-24 22:31:52 +02:00
parent b6d4a2dc47
commit 9d2e7cef5c
9 changed files with 330 additions and 178 deletions
-26
View File
@@ -1,26 +0,0 @@
2025-06-20 17:00:03,464 - INFO - ********************************************************************************************************************************************
2025-06-20 17:00:03,465 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders
2025-06-20 17:00:03,465 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr
2025-06-20 17:00:03,465 - INFO - * Version : 2025.06.18
2025-06-20 17:00:03,465 - INFO - * Input file :
2025-06-20 17:00:03,465 - INFO - * Output file : ~\.
2025-06-20 17:00:03,466 - INFO - * Log file : ~\..\pyCreateTh.log
2025-06-20 17:00:03,466 - INFO - *
2025-06-20 17:00:03,466 - INFO - *
2025-06-20 17:00:03,466 - INFO - *
2025-06-20 17:00:03,470 - INFO - ********************************************************************************************************************************************
2025-06-20 17:00:03,472 - ERROR - !!! file not yet supported
2025-06-20 17:00:03,472 - ERROR - !!! There were 1 errors during 7.63 secondes, check the log file: pyCreateTh.log
2025-06-23 12:45:03,041 - INFO - ********************************************************************************************************************************************
2025-06-23 12:45:03,043 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders
2025-06-23 12:45:03,043 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr
2025-06-23 12:45:03,044 - INFO - * Version : 2025.06.23
2025-06-23 12:45:03,044 - INFO - * Input file :
2025-06-23 12:45:03,044 - INFO - * Output file : ~\.
2025-06-23 12:45:03,044 - INFO - * Log file : ~\..\pyCreateTh.log
2025-06-23 12:45:03,045 - INFO - *
2025-06-23 12:45:03,045 - INFO - *
2025-06-23 12:45:03,045 - INFO - *
2025-06-23 12:45:03,045 - INFO - ********************************************************************************************************************************************
2025-06-23 12:45:03,046 - ERROR - !!! file not yet supported
2025-06-23 12:45:03,047 - ERROR - !!! There were 1 errors during 4.73 secondes, check the log file: pyCreateTh.log
+4
View File
@@ -13,6 +13,7 @@
"clarke", "clarke",
"clino", "clino",
"CLINO", "CLINO",
"colwidth",
"cumcount", "cumcount",
"datat", "datat",
"depmatch", "depmatch",
@@ -53,6 +54,8 @@
"nouvelletriangulationfrançaise", "nouvelletriangulationfrançaise",
"pulkovo", "pulkovo",
"resultats", "resultats",
"roth",
"rsuffix",
"sinfo", "sinfo",
"sirgas", "sirgas",
"southamerican", "southamerican",
@@ -64,6 +67,7 @@
"therion", "therion",
"totdata", "totdata",
"totfile", "totfile",
"triees",
"UUUUDDDDSSSB", "UUUUDDDDSSSB",
"UUUUDDDDSSSBL", "UUUUDDDDSSSBL",
"UUUUDDDDSSSSSBL", "UUUUDDDDSSSSSBL",
+5 -1
View File
@@ -199,12 +199,16 @@ def read_config(config_file):
if global_data.linesInTh2 == -1 : if global_data.linesInTh2 == -1 :
if 'Application_Data' in config and 'shot_lines_in_th2_files' in config['Application_Data']: if 'Application_Data' in config and 'shot_lines_in_th2_files' in config['Application_Data']:
linesInTh2 = 0 if config['Application_Data']['shot_lines_in_th2_files'] == "False" else 1 global_data.linesInTh2 = 0 if config['Application_Data']['shot_lines_in_th2_files'] == "False" else 1
if global_data.stationNamesInTh2 == -1 : if global_data.stationNamesInTh2 == -1 :
if 'Application_Data' in config and 'station_name_in_th2_files' in config['Application_Data']: if 'Application_Data' in config and 'station_name_in_th2_files' in config['Application_Data']:
global_data.stationNamesInTh2 = 0 if config['Application_Data']['station_name_in_th2_files'] == "False" else 1 global_data.stationNamesInTh2 = 0 if config['Application_Data']['station_name_in_th2_files'] == "False" else 1
if global_data.wallLineInTh2 == -1 :
if 'Application_Data' in config and 'wall_lines_in_th2_files' in config['Application_Data']:
global_data.wallLineInTh2 = 0 if config['Application_Data']['wall_lines_in_th2_files'] == "False" else 1
################################################################################################# #################################################################################################
# Supprime les codes ANSI (pour l'écriture dans les fichiers) # Supprime les codes ANSI (pour l'écriture dans les fichiers)
+14 -8
View File
@@ -28,6 +28,7 @@ therionPath = "C:/Therion/therion.exe"
SurveyPrefixName = f"Survey_" SurveyPrefixName = f"Survey_"
linesInTh2 = -1 linesInTh2 = -1
stationNamesInTh2 = -1 stationNamesInTh2 = -1
wallLineInTh2 = -1
################################################################################################# #################################################################################################
@@ -73,6 +74,7 @@ endsurvey
{SOURCE} {SOURCE}
""" """
################################################################################################# #################################################################################################
thconfigTemplate = """ thconfigTemplate = """
source "{th_file}" source "{th_file}"
@@ -87,12 +89,13 @@ export map -projection plan -o "{th_name}-Plan.xvi" -layout minimal -layout-debu
export map -projection extended -o "{th_name}-Extended.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""" th2FileHeader = """encoding utf-8"""
th2File = """ th2File = """
##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max} ##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max}
##XTHERION## xth_me_area_zoom_to 100 ##XTHERION## xth_me_area_zoom_to 25
##XTHERION## xth_me_image_insert {insert_XVI} ##XTHERION## xth_me_image_insert {insert_XVI}
{Copyright} {Copyright}
@@ -103,25 +106,27 @@ th2File = """
scrap S{projection_short}-{name}_01 -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" scrap S{projection_short}-{name}_01 -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}"
{points}
{names} {names}
{lines} {lines}
{walls}
{points}
endscrap endscrap
""" """
th2Point = """ point {x} {y} station -name {station}""" th2Point = """\tpoint {x} {y} station -name {station}"""
th2Name = """ point {x} {y} station-name -align tr -scale xs -text {station}""" th2Name = """\tpoint {x} {y} station-name -align tr -scale xs -text {station}"""
th2Line = """ th2Line = """
line u:Shot_Survey line u:Shot_Survey
{x1} {y1} \t{x1} {y1}
{x2} {y2} \t{x2} {y2}
endline endline
""" """
th2wall = """{list}"""
th2Scrap = """ th2Scrap = """
scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}" scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}"
@@ -129,6 +134,7 @@ scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projectio
endscrap endscrap
""" """
################################################################################################# #################################################################################################
datumToEPSG = { datumToEPSG = {
# Datums globaux # Datums globaux
+1
View File
@@ -21,3 +21,4 @@ therion_path = C:\Program Files\Therion\therion.exe
survey_prefix_name = Explo_ survey_prefix_name = Explo_
shot_lines_in_th2_files = True shot_lines_in_th2_files = True
station_name_in_th2_files = True station_name_in_th2_files = True
wall_lines_in_th2_files = True
+291 -130
View File
@@ -21,16 +21,13 @@ Version 2025 06 16 : Création fonction create_th_folders
En cours : En cours :
- gérer les updates (th, dat, mak) - créer fonction wall shot pour faire habillage des th2 files, les jointures...
- créer fonction pour faire habillage des th2 files, les jointures... - reprendre les options en ligne de commande, tester, documenter
- reprendre l'option shot lines dans les th2 files pour supprimer les splays.
- créer l'option wall shot lines dans les th2 files.
- reprendre les options en ligne de commande, tester
- trouver une solution pour les teams et les clubs manquants - trouver une solution pour les teams et les clubs manquants
- tester la nouvelle version de DAT (CORRECTION2 et suivants) - tester la nouvelle version de DAT (CORRECTION2 et suivants)
- comparer résultats Therion - Compass (Stat, kml, etc....) - comparer résultats Therion - Compass (Stat, kml, etc....)
- intégrer .tro files d'après XRo - intégrer .tro files d'après XRo
- ajouter codes pour lat/long
""" """
@@ -41,6 +38,8 @@ Version ="2025.06.24"
################################################################################################# #################################################################################################
import os, re, unicodedata, argparse, shutil, sys, time, math import os, re, unicodedata, argparse, shutil, sys, time, math
from os.path import isfile, join, abspath, splitext from os.path import isfile, join, abspath, splitext
import numpy as np
import networkx as nx
import pandas as pd import pandas as pd
pd.set_option('future.no_silent_downcasting', True) pd.set_option('future.no_silent_downcasting', True)
from datetime import datetime from datetime import datetime
@@ -279,34 +278,60 @@ def str_to_bool(value):
raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}") raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}")
################################################################################################# #################################################################################################
def convert_to_line_polaire(lines): def convert_to_line_polaire_df(df_lines):
line_polaire = [] """
Convertit un DataFrame de lignes cartésiennes (x1, y1, x2, y2, name1, name2)
for line in lines: en un DataFrame avec représentation polaire (x1, y1, azimut_deg, longueur, name1, name2).
"""
try: try:
x1 = float(line[0]) # Forcer la conversion des colonnes numériques
y1 = float(line[1]) df_lines = df_lines.copy() # évite de modifier l'original
x2 = float(line[2]) cols_to_float = ["x1", "y1", "x2", "y2"]
y2 = float(line[3]) for col in cols_to_float:
name1 = line[4] df_lines[col] = pd.to_numeric(df_lines[col], errors="coerce")
name2 = line[5]
dx = x2 - x1 # Supprimer les lignes invalides (NaN après conversion)
dy = y2 - y1 df_lines = df_lines.dropna(subset=cols_to_float)
# Longueur (distance)
length = math.hypot(dx, dy)
# Roth = azimut en degrés, 0° = Est, 90° = Nord dx = df_lines["x2"] - df_lines["x1"]
roth_rad = math.atan2(dy, dx) dy = df_lines["y2"] - df_lines["y1"]
roth_deg = (math.degrees(roth_rad)) % 360 # pour rester entre 0-360
line_polaire.append([x1, y1, roth_deg, length, name1, name2]) # Calcul de la longueur et de l'azimut
length = np.hypot(dx, dy)
azimut = (np.degrees(np.arctan2(dy, dx))) % 360
if "group_id" in df_lines.columns:
df_polaire = pd.DataFrame({
"x1": df_lines["x1"],
"y1": df_lines["y1"],
"x2": df_lines["x2"],
"y2": df_lines["y2"],
"azimut_deg": azimut,
"longueur": length,
"name1": df_lines["name1"],
"name2": df_lines["name2"],
"group_id": df_lines["group_id"],
"rank_in_group": df_lines["rank_in_group"],
})
else :
df_polaire = pd.DataFrame({
"x1": df_lines["x1"],
"y1": df_lines["y1"],
"x2": df_lines["x2"],
"y2": df_lines["y2"],
"azimut_deg": azimut,
"longueur": length,
"name1": df_lines["name1"],
"name2": df_lines["name2"],
})
return df_polaire
except Exception as e: except Exception as e:
print(f"Erreur sur la ligne {line} : {e}") log.error(f"Issue in polar conversion: {Colors.ENDC}{e}")
globalData.error_count += 1
return line_polaire return pd.DataFrame()
################################################################################################# #################################################################################################
@@ -327,6 +352,7 @@ def parse_xvi_file(th_name_xvi):
""" """
stations = {} stations = {}
lines = [] lines = []
splays = []
with open(join(th_name_xvi), "r", encoding="utf-8") as f: with open(join(th_name_xvi), "r", encoding="utf-8") as f:
xvi_content = f.read() xvi_content = f.read()
@@ -341,6 +367,7 @@ def parse_xvi_file(th_name_xvi):
station = station_number station = station_number
if len(namespace_array) > 1: if len(namespace_array) > 1:
station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1])) station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1]))
if station != "." and station != "-":
stations[f"{x}.{y}"] = [x, y, station] stations[f"{x}.{y}"] = [x, y, station]
# Calcul des bornes x et y # Calcul des bornes x et y
@@ -360,84 +387,189 @@ def parse_xvi_file(th_name_xvi):
key2 = f"{x2}.{y2}" key2 = f"{x2}.{y2}"
station1 = stations[key1][2] if key1 in stations else None station1 = stations[key1][2] if key1 in stations else None
station2 = stations[key2][2] if key2 in stations else None station2 = stations[key2][2] if key2 in stations else None
if station1 != "." and station1 != "-" and station1 != None and station2 != "." and station2 != "-" and station2 != None:
lines.append([x1, y1, x2, y2, station1, station2]) lines.append([x1, y1, x2, y2, station1, station2])
else :
splays.append([x1, y1, x2, y2, station1, station2])
return stations, lines, x_min, x_max, y_min, y_max, x_ecart, y_ecart return stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart
################################################################################################# #################################################################################################
def wall_construction(stations, lines): def assign_groups_and_ranks(df_lines):
G = nx.Graph()
for _, row in df_lines.iterrows():
G.add_edge(row["name1"], row["name2"])
station_names = {s[2] for s in stations.values()} used_edges = set()
results = []
group_id = 0
# Séparer lines en lignes valides et splays def walk_path(u, prev=None):
splays = {} path = []
filtered_lines = [] current = u
for i, line in enumerate(lines): while True:
if line[4] in station_names and line[5] in station_names: neighbors = [n for n in G.neighbors(current) if n != prev]
filtered_lines.append(line) if len(neighbors) != 1: # fin de chemin : cul-de-sac ou embranchement
else: break
splays[f"splay_{i}"] = line next_node = neighbors[0]
edge = tuple(sorted((current, next_node)))
if edge in used_edges:
break
used_edges.add(edge)
path.append(edge)
prev = current
current = next_node
return path
# Conversion polaire # Départ depuis toutes les feuilles ou nœuds d'ordre >2 (embranchements)
lines_polaire = convert_to_line_polaire(filtered_lines) start_nodes = [n for n in G.nodes if G.degree(n) != 2]
splays_polaire = convert_to_line_polaire(list(splays.values()))
# Index rapide des lignes polaires par nom de station (col. 4) for node in start_nodes:
index_by_station = { for neighbor in G.neighbors(node):
line[4]: idx for idx, line in enumerate(lines_polaire) edge = tuple(sorted((node, neighbor)))
} if edge in used_edges:
continue
used_edges.add(edge)
path = [(node, neighbor)] + walk_path(neighbor, node)
for rank, (n1, n2) in enumerate(path):
match = df_lines[(df_lines["name1"] == n1) & (df_lines["name2"] == n2)]
if match.empty:
match = df_lines[(df_lines["name1"] == n2) & (df_lines["name2"] == n1)]
if not match.empty:
row = match.iloc[0].copy()
row["group_id"] = group_id
row["rank_in_group"] = rank
results.append(row)
group_id += 1
# Associer à chaque splay son index de ligne, et récupérer roth/length return pd.DataFrame(results)
splays_complet = []
for splay in splays_polaire:
station_name = splay[4]
idx = index_by_station.get(station_name)
if idx is not None:
roth_ref = lines_polaire[idx][2]
length_ref = lines_polaire[idx][3]
else:
roth_ref = length_ref = None
splays_complet.append(splay + [idx, roth_ref, length_ref])
# Ajouter sin(delta roth) * length_ref
for ligne in splays_complet:
roth_splay, roth_ref, length_ref = ligne[2], ligne[7], ligne[8]
if None not in (roth_splay, roth_ref, length_ref):
delta_rad = math.radians(roth_ref - roth_splay)
proj = math.sin(delta_rad) * length_ref
else:
proj = None
ligne.append(proj)
# Filtrer les extrêmes (min/max) par station (col. 4) #################################################################################################
groupes = defaultdict(list) def wall_construction(df_stations, df_lines, df_splays, x_min, x_max, y_min, y_max):
for ligne in splays_complet:
station, proj = ligne[4], ligne[9]
if proj is not None:
groupes[station].append(ligne)
resultats = []
for station, lignes in groupes.items():
lignes_triees = sorted(lignes, key=lambda x: x[9])
resultats.append(lignes_triees[0]) # min
if lignes_triees[0] != lignes_triees[-1]: # max ≠ min
resultats.append(lignes_triees[-1]) # max
print(f"\nlines_polaires: {len(lines_polaire)}") df_lines = assign_groups_and_ranks(df_lines)
print(f"{lines_polaire}")
print(f"\nsplays_polaire: {len(splays_complet)}")
print(f"{splays_complet}")
print(f"\nresultats: {len(resultats)}")
print(f"{resultats}")
exit(0)
return resultats # Conversion en polaire
df_lines_polaire = convert_to_line_polaire_df(df_lines)
df_splays_polaire = convert_to_line_polaire_df(df_splays)
# Index des lignes polaires par station name1
index_by_station = df_lines_polaire.set_index("name1")[["azimut_deg", "longueur"]]
# Jointure pour récupérer azimut_ref et longueur_ref
_df_splays_complet = df_splays_polaire.copy()
_df_splays_complet = _df_splays_complet.join(index_by_station, on="name1", rsuffix="_ref")
# Remplacer les valeurs manquantes par défaut : azimut_ref = 0, longueur_ref = 0
_df_splays_complet["azimut_deg_ref"] = _df_splays_complet["azimut_deg_ref"].fillna(0)
_df_splays_complet["longueur_ref"] = _df_splays_complet["longueur_ref"].fillna(0)
df_splays_complet = _df_splays_complet.merge(
df_lines[["name1", "group_id", "rank_in_group"]],
on="name1",
how="left"
)
print(f"\n df_splays_complet: {len(df_splays_complet)}")
print(df_splays_complet)
missing_mask = df_splays_complet["group_id"].isna()
for idx, row in df_splays_complet[missing_mask].iterrows():
name1 = row["name1"]
match = df_lines_polaire[df_lines_polaire["name2"] == name1]
if not match.empty:
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, "azimut_deg_ref"] = 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
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', None)
df_splays_complet = df_splays_complet.sort_values(by=["group_id", "rank_in_group"]).reset_index(drop=True)
print(f"\n df_splays_complet: {len(df_splays_complet)}")
print(df_splays_complet)
# Calcul de la projection : sin(delta azimut) * longueur_ref
def calc_projection(row):
try:
delta = math.radians(row["azimut_deg_ref"] - row["azimut_deg"])
return math.sin(delta) * row["longueur"]
except:
return None
df_splays_complet["proj"] = df_splays_complet.apply(calc_projection, axis=1)
# Filtrage des extrêmes min/max par station name1
df_valid_proj = df_splays_complet.dropna(subset=["proj"])
idx_min = df_valid_proj.groupby("name1")["proj"].idxmin()
idx_max = df_valid_proj.groupby("name1")["proj"].idxmax()
df_result01 = pd.concat([df_valid_proj.loc[idx_max]]).drop_duplicates()
df_result02 = pd.concat([df_valid_proj.loc[idx_min]]).drop_duplicates()
df_result01["group_id"] = df_result01["group_id"].astype(int)
df_result01["rank_in_group"] = df_result01["rank_in_group"].astype(int)
df_sorted01 = df_result01.sort_values(by=["group_id", "rank_in_group"]).reset_index(drop=True)
# Convertir les colonnes en entiers
df_result02["group_id"] = df_result02["group_id"].astype(int)
df_result02["rank_in_group"] = df_result02["rank_in_group"].astype(int)
df_sorted02 = df_result02.sort_values(by=["group_id", "rank_in_group"]).reset_index(drop=True)
# Affichage de contrôle
print(f"\n df_sorted01: {len(df_sorted01)}")
print(df_sorted01)
# print(f"\n df_sorted02: {len(df_sorted02)}")
# print(df_sorted02)
th2_walls=[]
_list = ""
for gid in sorted(df_sorted01["group_id"].unique()):
df_group = df_sorted01[df_sorted01["group_id"] == gid]
_list += f"line wall\n"
for line in df_group.itertuples(index=False):
_list += f"\t{line.x2} {line.y2}\n"
if line.x2 > x_max: x_max = line.x2
if line.x2 < x_min: x_min = line.x2
if line.y2 > y_max: y_max = line.y2
if line.y2 < y_min: y_min = line.y2
_list += "endline\n\nline wall -reverse on\n"
df_group = df_sorted02[df_sorted02["group_id"] == gid]
for line in df_group.itertuples(index=False):
_list += f"\t{line.x2} {line.y2}\n"
if line.x2 > x_max: x_max = line.x2
if line.x2 < x_min: x_min = line.x2
if line.y2 > y_max: y_max = line.y2
if line.y2 < y_min: y_min = line.y2
_list += f"endline\n"
th2_walls.append(globalData.th2wall.format(list = _list))
return th2_walls, x_min, x_max, y_min, y_max
################################################################################################# #################################################################################################
# Création des dossiers à partir d'un th file # # Création des dossiers à partir d'un th file #
################################################################################################# #################################################################################################
@@ -497,7 +629,6 @@ def create_th_folders(ENTRY_FILE,
log.info(f"Parsing survey entry file: {Colors.ENDC}{shortCurentFile}") log.info(f"Parsing survey entry file: {Colors.ENDC}{shortCurentFile}")
survey_list = parse_therion_surveys(ENTRY_FILE) survey_list = parse_therion_surveys(ENTRY_FILE)
# print(survey_list)
if TARGET == "None" : if TARGET == "None" :
if len(survey_list) > 1 : if len(survey_list) > 1 :
@@ -517,7 +648,7 @@ def create_th_folders(ENTRY_FILE,
if UPDATE == "th2": if UPDATE == "th2":
log.info(f" Update th2 files {Colors.ENDC}") log.info(f" Update th2 files {Colors.ENDC}")
log.info(f"\t{Colors.BLUE}survey_file : {Colors.ENDC} {args.survey_file}") log.info(f"\t{Colors.BLUE}survey_file : {Colors.ENDC} {args.file}")
log.info(f"\t{Colors.BLUE}ENTRY_FILE: {Colors.ENDC} {ENTRY_FILE}") log.info(f"\t{Colors.BLUE}ENTRY_FILE: {Colors.ENDC} {ENTRY_FILE}")
log.info(f"\t{Colors.BLUE}PROJECTION: {Colors.ENDC} {PROJECTION}") log.info(f"\t{Colors.BLUE}PROJECTION: {Colors.ENDC} {PROJECTION}")
log.info(f"\t{Colors.BLUE}TARGET: {Colors.ENDC} {TARGET}") log.info(f"\t{Colors.BLUE}TARGET: {Colors.ENDC} {TARGET}")
@@ -525,7 +656,7 @@ def create_th_folders(ENTRY_FILE,
log.info(f"\t{Colors.BLUE}FORMAT: {Colors.ENDC} {FORMAT}") log.info(f"\t{Colors.BLUE}FORMAT: {Colors.ENDC} {FORMAT}")
log.info(f"\t{Colors.BLUE}SCALE: {Colors.ENDC} {SCALE}") log.info(f"\t{Colors.BLUE}SCALE: {Colors.ENDC} {SCALE}")
log.info(f"\t{Colors.BLUE}TH_NAME: {Colors.ENDC} {TH_NAME}") log.info(f"\t{Colors.BLUE}TH_NAME: {Colors.ENDC} {TH_NAME}")
DEST_PATH = os.path.dirname(args.survey_file) DEST_PATH = os.path.dirname(args.file)
log.info(f"\t{Colors.BLUE}DEST_PATH: {Colors.ENDC} {DEST_PATH}") log.info(f"\t{Colors.BLUE}DEST_PATH: {Colors.ENDC} {DEST_PATH}")
log.info(f"\t{Colors.BLUE}ABS_PATH: {Colors.ENDC} {ABS_PATH}") log.info(f"\t{Colors.BLUE}ABS_PATH: {Colors.ENDC} {ABS_PATH}")
@@ -549,7 +680,7 @@ def create_th_folders(ENTRY_FILE,
"th_file": DEST_PATH + "/" + TH_NAME + ".th", "th_file": DEST_PATH + "/" + TH_NAME + ".th",
"selector": survey.therion_id, "selector": survey.therion_id,
"th_name": DEST_PATH + "/" + TH_NAME, "th_name": DEST_PATH + "/" + TH_NAME,
"scale": SCALE, "scale": int(int(SCALE)/10),
} }
else : else :
@@ -557,7 +688,7 @@ def create_th_folders(ENTRY_FILE,
"th_file": DEST_PATH + "/Data/" + TH_NAME + ".th", "th_file": DEST_PATH + "/Data/" + TH_NAME + ".th",
"selector": survey.therion_id, "selector": survey.therion_id,
"th_name": DEST_PATH + "/Data/" + TH_NAME, "th_name": DEST_PATH + "/Data/" + TH_NAME,
"scale": SCALE, "scale": int(int(SCALE)/10),
} }
logfile, tmpdir, totReadMeError = compile_template(globalData.thconfigTemplate, template_args, totReadMeError, cleanup=False, therion_path=globalData.therionPath) logfile, tmpdir, totReadMeError = compile_template(globalData.thconfigTemplate, template_args, totReadMeError, cleanup=False, therion_path=globalData.therionPath)
@@ -622,9 +753,17 @@ def create_th_folders(ENTRY_FILE,
stations = {} stations = {}
lines = [] lines = []
stations, lines, 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(th_name_xvi)
df_stations = pd.DataFrame.from_dict(stations, orient='index')
df_lines = pd.DataFrame(lines, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
df_splays = pd.DataFrame(splays, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
th2_walls = []
if globalData.wallLineInTh2 :
th2_walls, x_min, x_max, y_min, y_max = wall_construction(df_stations, df_lines, df_splays, x_min, x_max, y_min, y_max)
# wall wall_construction(stations, lines)
if UPDATE == "th2": if UPDATE == "th2":
th2_name = DEST_PATH + "/" + TH_NAME th2_name = DEST_PATH + "/" + TH_NAME
@@ -664,9 +803,9 @@ def create_th_folders(ENTRY_FILE,
if isfile(output_path): if isfile(output_path):
log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done") log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - overwrite")
else : if True :
# name = TARGET, # name = TARGET,
log.debug(f"Therion output path: {Colors.ENDC}{safe_relpath(output_path)}") log.debug(f"Therion output path: {Colors.ENDC}{safe_relpath(output_path)}")
@@ -678,6 +817,7 @@ def create_th_folders(ENTRY_FILE,
Copyright_Short = globalData.CopyrightShort, Copyright_Short = globalData.CopyrightShort,
points="\n".join(th2_points), points="\n".join(th2_points),
lines="\n".join(th2_lines) if globalData.linesInTh2 else "", lines="\n".join(th2_lines) if globalData.linesInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLineInTh2 else "",
names="\n".join(th2_names) if globalData.stationNamesInTh2 else "", names="\n".join(th2_names) if globalData.stationNamesInTh2 else "",
projection="plan", projection="plan",
projection_short="P", projection_short="P",
@@ -727,7 +867,16 @@ def create_th_folders(ENTRY_FILE,
stations = {} stations = {}
lines = [] lines = []
stations, lines, 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(th_name_xvi)
df_stations = pd.DataFrame.from_dict(stations, orient='index')
df_lines = pd.DataFrame(lines, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
df_splays = pd.DataFrame(splays, columns=["x1", "y1", "x2", "y2", "name1", "name2"])
th2_walls = []
if globalData.wallLineInTh2 :
th2_walls, x_min, x_max, y_min, y_max, = wall_construction(df_stations, df_lines, df_splays, x_min, x_max, y_min, y_max)
if UPDATE == "th2": if UPDATE == "th2":
@@ -745,6 +894,7 @@ def create_th_folders(ENTRY_FILE,
th2_lines = [] th2_lines = []
th2_points = [] th2_points = []
th2_names = [] th2_names = []
other_scraps_extended = f"\tSC-{TARGET}_01\n\tbreak\n" other_scraps_extended = f"\tSC-{TARGET}_01\n\tbreak\n"
for line in lines: for line in lines:
@@ -765,8 +915,9 @@ def create_th_folders(ENTRY_FILE,
if isfile(output_path): if isfile(output_path):
log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done{Colors.ENDC}") log.warning(f"{Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - overwrite")
else :
if True :
log.debug(f"Therion output path :\t{Colors.ENDC}{output_path}") log.debug(f"Therion output path :\t{Colors.ENDC}{output_path}")
with open(str(output_path), "w+") as f: with open(str(output_path), "w+") as f:
@@ -777,6 +928,7 @@ def create_th_folders(ENTRY_FILE,
Copyright_Short = globalData.CopyrightShort, Copyright_Short = globalData.CopyrightShort,
points="\n".join(th2_points), points="\n".join(th2_points),
lines="\n".join(th2_lines) if globalData.linesInTh2 else "", lines="\n".join(th2_lines) if globalData.linesInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLineInTh2 else "",
names="\n".join(th2_names) if globalData.stationNamesInTh2 else "", names="\n".join(th2_names) if globalData.stationNamesInTh2 else "",
projection="extended", projection="extended",
projection_short="C", projection_short="C",
@@ -971,15 +1123,15 @@ def mak_to_th_file(ENTRY_FILE) :
QtySections = 0 QtySections = 0
for file in datFiles : for file in datFiles :
ABS_file = os.path.dirname(abspath(args.survey_file)) + "\\"+ file ABS_file = os.path.dirname(abspath(args.file)) + "\\"+ file
content, val = load_text_file_utf8(ABS_file, os.path.basename(ABS_file)) content, val = load_text_file_utf8(ABS_file, os.path.basename(ABS_file))
section = content.split('\x0c') section = content.split('\x0c')
QtySections += len(section) QtySections += len(section)
SurveyTitleMak = sanitize_filename(os.path.basename(abspath(args.survey_file))[:-4]) SurveyTitleMak = sanitize_filename(os.path.basename(abspath(args.file))[:-4])
folderDest = os.path.dirname(abspath(args.survey_file)) + "/" + SurveyTitleMak folderDest = os.path.dirname(abspath(args.file)) + "/" + SurveyTitleMak
copy_template_if_not_exists(globalData.templatePath,folderDest) copy_template_if_not_exists(globalData.templatePath,folderDest)
@@ -1013,7 +1165,7 @@ def mak_to_th_file(ENTRY_FILE) :
else : else :
bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{file[:-4]}") bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{file[:-4]}")
_file = os.path.dirname(abspath(args.survey_file)) + "\\" + file _file = os.path.dirname(abspath(args.file)) + "\\" + file
shutil.copy(_file, folderDest + "\\Data\\") shutil.copy(_file, folderDest + "\\Data\\")
ABS_file = folderDest + "\\Data\\" + file ABS_file = folderDest + "\\Data\\" + file
@@ -1061,7 +1213,7 @@ def mak_to_th_file(ENTRY_FILE) :
tableau_pivot.columns = [f'Survey_Name_{i}' for i in tableau_pivot.columns] tableau_pivot.columns = [f'Survey_Name_{i}' for i in tableau_pivot.columns]
# print(f"tableau_pivot : {Colors.ENDC}{tableau_pivot}{Colors.INFO} in {Colors.ENDC}{args.survey_file}") # print(f"tableau_pivot : {Colors.ENDC}{tableau_pivot}{Colors.INFO} in {Colors.ENDC}{args.file}")
totdata +=f"\n\t## Equates list:\n" totdata +=f"\n\t## Equates list:\n"
@@ -1070,9 +1222,9 @@ def mak_to_th_file(ENTRY_FILE) :
tableau_pivot = tableau_pivot.reset_index() tableau_pivot = tableau_pivot.reset_index()
tableau_equate = tableau_pivot[tableau_pivot['Survey_Name_2'].notna()] tableau_equate = tableau_pivot[tableau_pivot['Survey_Name_2'].notna()]
log.info(f"Total des 'equates' in mak file: {Colors.ENDC}{len(tableau_equate)}{Colors.INFO} in {Colors.ENDC}{safe_relpath(args.survey_file)}") log.info(f"Total des 'equates' in mak file: {Colors.ENDC}{len(tableau_equate)}{Colors.INFO} in {Colors.ENDC}{safe_relpath(args.file)}")
# print(tableau_equate) # print(tableau_equate)
# print(f"fixPoints: {Colors.ENDC}{fixPoints}{Colors.INFO} in {Colors.ENDC}{args.survey_file}") # print(f"fixPoints: {Colors.ENDC}{fixPoints}{Colors.INFO} in {Colors.ENDC}{args.file}")
# Pour chaque ligne du tableau # Pour chaque ligne du tableau
for _, row in tableau_equate.iterrows(): for _, row in tableau_equate.iterrows():
@@ -1088,7 +1240,7 @@ def mak_to_th_file(ENTRY_FILE) :
totdata +=f"\tequate {station}@{surveys[i]} {station}@{surveys[j]}\n" totdata +=f"\tequate {station}@{surveys[i]} {station}@{surveys[j]}\n"
# print(f"\tequate {station}@{surveys[i]} {station}@{surveys[j]}") # print(f"\tequate {station}@{surveys[i]} {station}@{surveys[j]}")
else: else:
log.info(f"No 'equats' found in {Colors.ENDC}{args.survey_file}") log.info(f"No 'equats' found in {Colors.ENDC}{args.file}")
totdata +=f"\n\t## Maps list:\n\tinput {SurveyTitleMak}-maps.th\n" totdata +=f"\n\t## Maps list:\n\tinput {SurveyTitleMak}-maps.th\n"
@@ -1115,7 +1267,7 @@ def mak_to_th_file(ENTRY_FILE) :
'file_info' : f"# File generated by pyCreateTh.py version: {Version} date: {datetime.now().strftime("%Y.%m.%d-%H:%M:%S")}", 'file_info' : f"# File generated by pyCreateTh.py version: {Version} date: {datetime.now().strftime("%Y.%m.%d-%H:%M:%S")}",
} }
DEST_PATH = os.path.dirname(args.survey_file) + '/' + SurveyTitleMak DEST_PATH = os.path.dirname(args.file) + '/' + SurveyTitleMak
update_template_files(DEST_PATH + '/template.thconfig', config_vars, DEST_PATH + '/' + SurveyTitleMak + '.thconfig') update_template_files(DEST_PATH + '/template.thconfig', config_vars, DEST_PATH + '/' + SurveyTitleMak + '.thconfig')
update_template_files(DEST_PATH + '/template-tot.th', config_vars, DEST_PATH + '/' + SurveyTitleMak + '-tot.th') update_template_files(DEST_PATH + '/template-tot.th', config_vars, DEST_PATH + '/' + SurveyTitleMak + '-tot.th')
@@ -1488,7 +1640,6 @@ def find_duplicates_by_date_and_team(data):
return duplicates return duplicates
################################################################################################# #################################################################################################
def points_uniques(data, crs_wkt): def points_uniques(data, crs_wkt):
# Création d'un DataFrame à partir des lignes de données # Création d'un DataFrame à partir des lignes de données
@@ -1752,6 +1903,7 @@ def dat_survey_format_extract(section_data, currentSurveyName, fichier, totReadM
return dataFormat, length, compass, clino, totReadMeError return dataFormat, length, compass, clino, totReadMeError
#
# ################################################################################################ # ################################################################################################
def load_text_file_utf8(filepath, short_filename): def load_text_file_utf8(filepath, short_filename):
encodings_to_try = [ encodings_to_try = [
@@ -1997,7 +2149,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "",
copy_template_if_not_exists(globalData.templatePath,folderDest) copy_template_if_not_exists(globalData.templatePath,folderDest)
if args.survey_file[-3:].lower() != "dat" : if args.file[-3:].lower() != "dat" :
_destination = folderDest + "\\config.thc" _destination = folderDest + "\\config.thc"
# print(f"destination_path : {_destination}") # print(f"destination_path : {_destination}")
os.remove(_destination) os.remove(_destination)
@@ -2161,7 +2313,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "",
destination_path = os.path.join(_destination, os.path.basename(output_file)) destination_path = os.path.join(_destination, os.path.basename(output_file))
shutil.move(output_file, destination_path) shutil.move(output_file, destination_path)
if args.survey_file[-3:].lower() != "dat" : if args.file[-3:].lower() != "dat" :
_destination = output_file[:-3] + "\\config.thc" _destination = output_file[:-3] + "\\config.thc"
destination_path = os.path.join(_destination, os.path.basename(output_file)) destination_path = os.path.join(_destination, os.path.basename(output_file))
# print(f"destination_path : {_destination}") # print(f"destination_path : {_destination}")
@@ -2306,7 +2458,7 @@ if __name__ == u'__main__':
description=f"{Colors.HEADER}Create a skeleton folder and th, th2 files with scraps from *.mak, *.dat, *.th Therion files, version: {Colors.ENDC}{Version}\n", description=f"{Colors.HEADER}Create a skeleton folder and th, th2 files with scraps from *.mak, *.dat, *.th Therion files, version: {Colors.ENDC}{Version}\n",
formatter_class=argparse.RawDescriptionHelpFormatter) formatter_class=argparse.RawDescriptionHelpFormatter)
parser.print_help = colored_help.__get__(parser) 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("--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("--survey_name", help="Scrap name (if different from 'survey_file' name)", default="None")
parser.add_argument("--proj", choices=['All', 'Plan', 'Extended', 'None'], help="The scrap projection to produce", default="All") 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("--format", choices=['th2', 'plt'], help="Output format. Either th2 for producing skeleton for drawing or plt for visualizing in aven/loch", default="th2")
@@ -2326,11 +2478,11 @@ if __name__ == u'__main__':
f"\t> python pyCreateTh.py\n\n") f"\t> python pyCreateTh.py\n\n")
args = parser.parse_args() args = parser.parse_args()
if args.survey_file == "": if args.file == "":
args.survey_file = select_file_tk_window() args.file = select_file_tk_window()
# print(f"Selected file : {args.survey_file}") # print(f"Selected file : {args.file}")
output_log = splitext(abspath(args.survey_file))[0]+".log" output_log = splitext(abspath(args.file))[0]+".log"
log = setup_logger(output_log, debug_log) log = setup_logger(output_log, debug_log)
# log.debug("Ceci est un message de debug") # log.debug("Ceci est un message de debug")
@@ -2348,8 +2500,8 @@ if __name__ == u'__main__':
f'* Conversion Th, Dat, Mak files to Therion files and folders', f'* Conversion Th, Dat, Mak files to Therion files and folders',
f'* Script pyCreateTh by : {Colors.ENDC}alexandre.pont@yahoo.fr', f'* Script pyCreateTh by : {Colors.ENDC}alexandre.pont@yahoo.fr',
f'* Version : {Colors.ENDC}{Version}', f'* Version : {Colors.ENDC}{Version}',
f'* Input file : {Colors.ENDC}{safe_relpath(args.survey_file)}', f'* Input file : {Colors.ENDC}{safe_relpath(args.file)}',
f'* Output file : {Colors.ENDC}{safe_relpath(splitext(abspath(args.survey_file))[0])}', f'* Output file : {Colors.ENDC}{safe_relpath(splitext(abspath(args.file))[0])}',
f'* Log file : {Colors.ENDC}{safe_relpath(output_log)}', f'* Log file : {Colors.ENDC}{safe_relpath(output_log)}',
f'* ', f'* ',
f'* ', f'* ',
@@ -2372,43 +2524,43 @@ if __name__ == u'__main__':
################################################################################################# #################################################################################################
# Fichier TH # # Fichier TH #
################################################################################################# #################################################################################################
if args.survey_file[-2:].lower() == "th" : if args.file[-2:].lower() == "th" :
flagErrorCompile, stat, totReadMeError, thread2 = create_th_folders( flagErrorCompile, stat, totReadMeError, thread2 = create_th_folders(
ENTRY_FILE = abspath(args.survey_file), ENTRY_FILE = abspath(args.file),
TARGET = args.survey_name, TARGET = args.survey_name,
PROJECTION= args.proj, PROJECTION= args.proj,
SCALE = args.scale, SCALE = args.scale,
UPDATE = args.update, UPDATE = args.update,
CONFIG_PATH = "") CONFIG_PATH = "")
threads += thread2 threads += thread2
fileTitle = sanitize_filename(os.path.basename(args.survey_file))[:-3] fileTitle = sanitize_filename(os.path.basename(args.file))[:-3]
################################################################################################# #################################################################################################
# Fichier MAK # # Fichier MAK #
################################################################################################# #################################################################################################
elif args.survey_file[-3:].lower() == "mak" : elif args.file[-3:].lower() == "mak" :
SurveyTitleMak = sanitize_filename(os.path.basename(abspath(args.survey_file))[:-4]) SurveyTitleMak = sanitize_filename(os.path.basename(abspath(args.file))[:-4])
DEST_PATH = os.path.dirname(args.survey_file) + '/' + SurveyTitleMak DEST_PATH = os.path.dirname(args.file) + '/' + SurveyTitleMak
if os.path.isdir(DEST_PATH): if os.path.isdir(DEST_PATH):
log.critical(f"The folder {Colors.ENDC}{SurveyTitleMak}{Colors.ERROR}{Colors.BOLD}, all ready exist : update mode is not possible for mak files") log.critical(f"The folder {Colors.ENDC}{SurveyTitleMak}{Colors.ERROR}{Colors.BOLD}, all ready exist : update mode is not possible for mak files")
exit(0) exit(0)
fileTitle, thread2 = mak_to_th_file(abspath(args.survey_file)) fileTitle, thread2 = mak_to_th_file(abspath(args.file))
threads += thread2 threads += thread2
################################################################################################# #################################################################################################
# Fichier DAT # # Fichier DAT #
################################################################################################# #################################################################################################
elif args.survey_file[-3:].lower() == "dat" : elif args.file[-3:].lower() == "dat" :
_ConfigPath = "./" _ConfigPath = "./"
QtySections = 0 QtySections = 0
ABS_file = abspath(args.survey_file) ABS_file = abspath(args.file)
content, val = load_text_file_utf8(ABS_file, os.path.basename(ABS_file)) content, val = load_text_file_utf8(ABS_file, os.path.basename(ABS_file))
section = content.split('\x0c') section = content.split('\x0c')
@@ -2418,10 +2570,10 @@ if __name__ == u'__main__':
if lines[0] !="" : if lines[0] !="" :
SurveyTitleDat = sanitize_filename(lines[0]) SurveyTitleDat = sanitize_filename(lines[0])
folderDest = os.path.dirname(args.survey_file) + "\\" + SurveyTitleDat folderDest = os.path.dirname(args.file) + "\\" + SurveyTitleDat
else : else :
SurveyTitleDat = sanitize_filename(os.path.basename(args.survey_file)[:-4]) SurveyTitleDat = sanitize_filename(os.path.basename(args.file)[:-4])
folderDest = os.path.dirname(args.survey_file) + "\\" + SurveyTitleDat folderDest = os.path.dirname(args.file) + "\\" + SurveyTitleDat
if os.path.isdir(folderDest): if os.path.isdir(folderDest):
log.critical(f"The folder {Colors.ENDC}{SurveyTitleDat}{Colors.ERROR}{Colors.BOLD}, all ready exist : update mode is not possible for mak files") log.critical(f"The folder {Colors.ENDC}{SurveyTitleDat}{Colors.ERROR}{Colors.BOLD}, all ready exist : update mode is not possible for mak files")
@@ -2448,7 +2600,7 @@ if __name__ == u'__main__':
bar() bar()
else : else :
log.error(f"file {Colors.ENDC}{safe_relpath(args.survey_file)}{Colors.ERROR} not yet supported") log.error(f"file {Colors.ENDC}{safe_relpath(args.file)}{Colors.ERROR} not yet supported")
globalData.error_count += 1 globalData.error_count += 1
duration = (datetime.now() - start_time).total_seconds() duration = (datetime.now() - start_time).total_seconds()
@@ -2457,6 +2609,9 @@ if __name__ == u'__main__':
t.join() t.join()
destination_path = os.path.dirname(output_log) + "\\" + fileTitle destination_path = os.path.dirname(output_log) + "\\" + fileTitle
file_name = os.path.basename(output_log)
destination_file = os.path.join(destination_path, file_name)
wait_until_file_is_released(output_log) wait_until_file_is_released(output_log)
if globalData.error_count == 0 : if globalData.error_count == 0 :
@@ -2466,6 +2621,12 @@ if __name__ == u'__main__':
wait_until_file_is_released(output_log) wait_until_file_is_released(output_log)
release_log_file(log) release_log_file(log)
# Supprimer le fichier cible sil existe déjà
if os.path.isfile(destination_file):
os.remove(destination_file)
shutil.move(output_log, destination_path) shutil.move(output_log, destination_path)
@@ -12,6 +12,7 @@
"cavename", "cavename",
"clarke", "clarke",
"clino", "clino",
"colwidth",
"datat", "datat",
"ecart", "ecart",
"ENDC", "ENDC",
@@ -25,6 +26,7 @@
"northamerican", "northamerican",
"northamericandatum", "northamericandatum",
"nouvelletriangulationfrançaise", "nouvelletriangulationfrançaise",
"roth",
"thanksto", "thanksto",
"thconfig", "thconfig",
"therion", "therion",