From 92a0450475d9676e94fec5f1a327d9ed764617c3 Mon Sep 17 00:00:00 2001 From: Alex38Lyon <55714436+Alex38Lyon@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:37:18 +0200 Subject: [PATCH] pyCreateTh --- Scripts/pyCreateTh/.vscode/settings.json | 2 + .../__pycache__/global_data.cpython-313.pyc | Bin 4199 -> 4199 bytes .../Lib/__pycache__/therion.cpython-313.pyc | Bin 14230 -> 14647 bytes Scripts/pyCreateTh/Lib/therion.py | 38 +++--- Scripts/pyCreateTh/pyCreateTh.py | 115 +++--------------- .../pyCreateTh_VSCode.code-workspace | 2 + 6 files changed, 40 insertions(+), 117 deletions(-) diff --git a/Scripts/pyCreateTh/.vscode/settings.json b/Scripts/pyCreateTh/.vscode/settings.json index 4697aa2..923d829 100644 --- a/Scripts/pyCreateTh/.vscode/settings.json +++ b/Scripts/pyCreateTh/.vscode/settings.json @@ -57,6 +57,7 @@ "LRUD", "migovec", "NODRAW", + "Noeuds", "northamerican", "northamericandatum", "nouvelletriangulationfrançaise", @@ -78,6 +79,7 @@ "totdata", "totfile", "triees", + "Urruty", "UUUUDDDDSSSB", "UUUUDDDDSSSBL", "UUUUDDDDSSSSSBL", diff --git a/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc index b6ca3158cc810002fb2b1169e5cf1eafc6262dac..1d2128260cfc0555189953ce4e356edfad23ad48 100644 GIT binary patch delta 20 acmaE^@LYlWGcPX}0}v>fr*7nq5dZ)`as?Ft delta 20 acmaE^@LYlWGcPX}0}$vPjN8Z^BLDzG?FFU) diff --git a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc index c4b22433d2fc26cb145fe55faa90b6681a6804b7..5d43cda30feca732dfd9269716b792d5282d132d 100644 GIT binary patch delta 2660 zcmbtVZ%kX)6+idAXZvCNjIp0F7=xd&9k9WHq|gXxXaY+ZgruF{Bkk%8O0YxS*_gg( z*eJ?yyKY$Yqg0hh@sDM3Xjk+NNyLKG>m?nMI~f+J~(lT1e2+Y3j6l z4Ng1OsZ#f3pL5T>=bm$Z=bU@*E2*oh`HmnMfqc?Ku_xNS3+8H6ztH%F5OauEc^S#< zp|U}vYLtMCnM37+Ce>6NbBBaMvuc*$m@ZtuaK>F@kSx3U*ClT)U*JHn{0xK>X zzEvmS8JAD@SAby#FL^~#W@SSsl3<%TU&)-pg-C)FzUwT&*qZc9r!7?jpZZN zxQ%mhW{9|Of^#*6Jtd8gxuWYpo01H283#nU8h=nXKU6hb!HpUg1ltPPzQP zveHHp;*OH$UPRMcC9@#`Kw}d3Vj6~UGtPOOyaW$9hM90B6|7BL`^Ff6!}p-$kLm;z zq6&Hm$i|%%j@{JtH3Iazp8{0)|A3me1LcZ7E8U**&&D-D@{UJzb!^4w4&s`wzD>5= zcdrl?WLR=VC+SJN%p@A{P|rL3tYJ!H@+iPZij6AxRf~L@ggh!lILOPHI5ts zW`uni>LIe#KcsOX%;2B6ZHOxt40VvI($5C{=!=&DlB~kwHAW=O&YP3$w#GJ>8at^| z*l;;s_te!g!>F4WD7MFb0GZvAlK}Yr8aHudc6yMAa}6#gT!TMyxedBv4_j#G>&+nR zBNn_w&e;bImHwX+3x+KVr%4~Vi_sA>%(f$XEj-D~W!Ud^mzzo}VGo6ZjQ`sYNhS9Q zFBWq@I@}8c@!cY~HeA*&McKl(aOrq5hO><$NRL~acDM?b#F&;IO--k# zrqiQzQ6o1eNRqTKgGZYBj!sd(-y}`)58{;*D<5Z8CEo?*Vq__j_jl&}o!55frJhA@ z#qB*m_r1ASPcCw+&8 z>WC0v3i|YzIuT13IKs35c|u6UxUad_5tOvpcxp1LNvRW3d~$3&9iNG(XYq^8OQ;sN zwN&j?kJBubrJtaAicd}y^h$A9&}qbIy1>V^(Xm8)CZ@8~XsX3-87BiZN=b~86ZmXP zN6=U>OsT2yn5L#T|9;TY)IDneK@3&N!(KnN1SlWlppw?5lHGlk4wXmGC&T(T2Yrs-IuegH6g?n{w8syfv7!23IU~c}qji z(r{^4mh#Z5&2g^trB2+P_3X;oc3tjYwso(Hj&lPG16k?7uTNZ0{4(+O$UDl>yb{SN zk-QSkDbZ{!xvWfPQ)+ff%_>?}PQNofcNbs=^)l<5Yz<%<&G#{c_c2GA4S+|OuP{XC z5#~76p^U5@WyUFsGGC=^oJmm4B%@KyBr{7jDI;qM=4r~FW}+-%?ifoH?I+k((VZ8Y zZ;H*Ap2~@Be-N8j#M*O13qxm*tcW#LYr-e-FI$6a77(2HB5hXa_3P&BEeG+uB^k%FdE$ zRih+L2|3LW;7I{rZyVIj6Cr}{w4L`qpbM-6AsgR7V0Pq%x|>4X1vw`KG6z>UH6@Eqj+8%tS-Hy5Ycl2b4NaCkgM8H`vjE+WAkkggraUm1&t*#bhqRv%`k_;tB z2r2LnBvaApM65?$BqDuZv}XueV-Z5@42QV8CO`*K9u92&Zb9`e@ZW-_clAPE@3^UV hEb{hcy(hzNnEDVphHi(M0fel#AI0H4`?w6T^>4F9W_$nu delta 2312 zcmb7EdrXs86hHTS^!fEg%d@2qpp-&EQ1BTh>V^)))qW7CFrY(*MWk?xn)pJan`VnM zc%8DC&6&k%wq-Lh%lyX-lSSuT77ChTrwiGC+y0mjHr-#_y)8xd$fnKLbMC$8eCPbm z@0|O6j*o}+4|F;W&|ms@8#jHMH>A%(8AG0D^Z9yJof@m1AS0Qp*VJjTHnA4!r8*tf zIiW=)m)(}34|P_9td|uz(2cNBR^|XU$to(-T7*C$G1)9eSzU!#1^{eH9TE-FYSU#c zb<9Ye*<@+PF;mu2Q&tz}H3ZY?+ZwVKwOsfZ8BNH1;ZoYyD#bS%^BoyuHD$E{HM{X znKx6t6PgQBuT~>Ujw|0xoOYGYoH}iSfOj@D@=KnIoU)6g(w@sT0htsnlB`|49Uyq* zF;?j*uRkDhh3LM(UsjZ3B z>iSjtIj$RCCG-8*Q4NG=tReuTYn7X**z9tbt4@FIV1;1lir z#F|)&-qEMwbm|sY;K%?D^^u!Jt%%+*Z=pIuKPljJI%~)_?~3X$3%Hr~{&yOVGn?AE z31`7s?HTQ`FyY8Qwe#(rCwJ4O+k1Ay=?(9<3~MH=bIvaww^rY>IVXvs_+Z8~fCmiA zLl6qszQ991Djq~0Qc^OYbb-tFXey6m5rS1L5C%K0lxmX)k3;lC;o>Bh^& z6$3%s)j1FssEUvszU6A0Gt$`+?%fz63MF3qjPJUdr~ zB5lE*(6&y@t~#z_g5C_k^OBceEmpw)VB6e!-SL_ zlN?dWaYJ%Vvb8-b*@w5^kUSFxTg>2&8r(61Cu;EAHkwbUht#9CWnUIv^YH8!y5=)Xi&{ZUyx$x)qmZ|$U@IkH}*gNz=R$w1;F=R*U=S zn`g+2m5b1>3r8!DBlH>Z&TmD#$f5a{GGAwj4lwZ=6<#hmG6zY^0*^?)N^qGRT2QlS z7qcO(WGXwZY-`&X?r3YnF1p8ym}sXW&f(6uvM1ct73%FumQhR;3)jzO&@n?1S9XNA z^o4pl@qTvnDiiF3ixVhVI_zX(7a3Y;UVDr#5&cJ)^IaYxbdM8|@K6F&gJQ6hKI5?T x4rJW{_Z=v@s{o}wrpO#qWDcvw6|TMfl(Yh&7IZ(rJ%>=*{Q!Beuts2|{0YZD15yA0 diff --git a/Scripts/pyCreateTh/Lib/therion.py b/Scripts/pyCreateTh/Lib/therion.py index 6c79a6d..89e05be 100644 --- a/Scripts/pyCreateTh/Lib/therion.py +++ b/Scripts/pyCreateTh/Lib/therion.py @@ -4,12 +4,11 @@ therion.py for pyCreateTh.py ############################################################################################# """ -import tempfile, shutil, os, re, logging, threading, subprocess +import tempfile, shutil, os, re, logging, threading, subprocess, time from os.path import join import Lib.global_data as global_data from Lib.general_fonctions import Colors - log = logging.getLogger("Logger") ################################################################################################# @@ -108,22 +107,26 @@ def compile_file(filename, **kwargs): bufsize=1 ) + last_output_time = time.time() + def read_output(proc): + nonlocal last_output_time try: - for line in proc.stdout: + for line in iter(proc.stdout.readline, ''): line = line.rstrip() + last_output_time = time.time() # ← reset du timer ici lower_line = line.lower() + if "average loop error" in lower_line: - None - # log.warning(f"[Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.WARNING}] {Colors.ENDC}{line}") + continue elif "error" in lower_line: log.error(f"[Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}] {Colors.ENDC}{line}") - elif "warning" in lower_line : - if not any( msg in line for msg in [ + elif "warning" in lower_line: + if not any(msg in line for msg in [ "invalid scrap outline", "average loop error", "multiple scrap outer outlines not supported yet" - ]): + ]): log.warning(f"[Therion compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.WARNING}] {Colors.ENDC}{line}") else: log.debug(f"[Therion compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.DEBUG}] {Colors.ENDC}{line}") @@ -133,20 +136,22 @@ def compile_file(filename, **kwargs): output_thread = threading.Thread(target=read_output, args=(process,)) output_thread.start() - output_thread.join(timeout) - if output_thread.is_alive(): - log.error(f"Therion compilation [Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}], timed out after {Colors.ENDC}{timeout}{Colors.ERROR} seconds. Killing process...") - global_data.error_count += 1 - process.kill() + # Boucle de surveillance du timeout + while output_thread.is_alive(): + output_thread.join(timeout=1) + if time.time() - last_output_time > timeout: + log.error(f"Therion compilation [Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}], timed out after {Colors.ENDC}{timeout}{Colors.ERROR} seconds of inactivity. Killing process...") + global_data.error_count += 1 + process.kill() + break - output_thread.join() # Toujours attendre proprement + output_thread.join() process.wait() if process.returncode != 0: log.error(f"Therion [Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}], returned error code {Colors.ENDC}{process.returncode}") global_data.error_count += 1 else: - # stat = get_stats_from_log(log_file) log.info(f"Therion file: [Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.GREEN}], compilation succeeded") except Exception as e: @@ -155,12 +160,9 @@ def compile_file(filename, **kwargs): # Lancer le thread principal pour cette compilation et le retourner thread = threading.Thread(target=run) - thread.start() - return thread - ################################################################################################# def compile_file_th(filepath, **kwargs): template = """source {filepath} diff --git a/Scripts/pyCreateTh/pyCreateTh.py b/Scripts/pyCreateTh/pyCreateTh.py index 7b872de..a9e46f9 100644 --- a/Scripts/pyCreateTh/pyCreateTh.py +++ b/Scripts/pyCreateTh/pyCreateTh.py @@ -30,14 +30,10 @@ Sources documentaires : Création Alex le 2025 06 09 En cours : - - trouver une solution pour les teams et les clubs - tester la avec les dernières option de la version de DAT (CORRECTION2 et suivants) - - comparer résultats Therion - Compass (Stat, kml, etc....) - - ajouter codes pour lat/long - - créer fonction wall shot pour faire habillage des th2 files, les jointures... + - améliorer fonction wall shot pour faire habillage des th2 files, les jointures... - traiter les series avec 1 ou 2 stations - PB des cartouches et des échelles pour faire des pdf automatiquement - - gérer les différentes options --proj (All, Plan, ....) - tester différentes version pour les fichiers .tro """ @@ -424,87 +420,6 @@ def parse_xvi_file(th_name_xvi): return stations, lines, splays, x_min, x_max, y_min, y_max, x_ecart, y_ecart ################################################################################################# -def assign_groups_and_ranks_Old(df_lines): - G = nx.Graph() - for _, row in df_lines.iterrows(): - G.add_edge(row["name1"], row["name2"]) - - used_edges = set() - results = [] - equates = [] # Liste des (group_id, start_point, end_point) - group_id = 0 - - def walk_path(u, prev=None): - path = [] - current = u - while True: - neighbors = [n for n in G.neighbors(current) if n != prev] - if len(neighbors) != 1: - break - 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 - - start_nodes = [n for n in G.nodes if G.degree(n) != 2] - - for node in start_nodes: - for neighbor in G.neighbors(node): - 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) - if rank == 0: - start_point = n1 - end_point = path[-1][1] if path else start_point - equates.append((group_id, str(start_point), str(end_point))) - group_id += 1 - - # Création du DataFrame principal - df_result = pd.DataFrame(results) - - # Création du DataFrame equates - df_equates = pd.DataFrame(equates, columns=["group_id", "start_point", "end_point"]) - df_equates["group_id"] = df_equates["group_id"].astype(int) - df_equates["start_point"] = df_equates["start_point"].astype(str) - df_equates["end_point"] = df_equates["end_point"].astype(str) - - print("df_result columns:", df_result.columns) - print("df_result empty:", df_result.empty) - - # Ajout de la colonne max_rank - max_ranks = df_result.groupby("group_id")["rank_in_group"].max().reset_index() - max_ranks.rename(columns={"rank_in_group": "max_rank"}, inplace=True) - max_ranks["max_rank"] = max_ranks["max_rank"].astype(int) - df_equates = df_equates.merge(max_ranks, on="group_id", how="left") - - # Ajout de la colonne start_group (raccord entre start_point <-> end_point d'un autre groupe) - end_to_group = df_equates[["end_point", "group_id"]].copy() - end_to_group.rename(columns={"end_point": "start_point", "group_id": "start_group"}, inplace=True) - end_to_group["start_point"] = end_to_group["start_point"].astype(str) - df_equates = df_equates.merge(end_to_group, on="start_point", how="left") - - # Remplacer les NaN dans start_group par 0 (entier) - df_equates["start_group"] = df_equates["start_group"].fillna(0).astype(int) - - return df_result, df_equates - def assign_groups_and_ranks(df_lines): G = nx.Graph() for _, row in df_lines.iterrows(): @@ -2318,7 +2233,7 @@ def merge_duplicate_surveys(data, duplicates, id_offset=10000): ################################################################################################# -def dat_survey_format_extract(section_data, currentSurveyName, fichier, totReadMeError) : +def dat_survey_format_extract(section_data, headerData, currentSurveyName, fichier, totReadMeError) : 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}") @@ -2419,10 +2334,16 @@ def dat_survey_format_extract(section_data, currentSurveyName, fichier, totReadM 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 = 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: @@ -2776,6 +2697,8 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", stationList, dfDATA = station_list(_line, stationList, fixPoints, currentSurveyName) + headerData = dfDATA.iloc[0].tolist() + ################################################################################################# # Recherche des points fixes (entrées) ################################################################################################# @@ -2801,13 +2724,14 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", fixPoint += f"\t\tfix {point[0]} {point[2]:.3f} {point[3]:.3f} {point[4]:.3f}\n" elif point[1] == 'f' : fixPoint += f"\t\tfix {point[0]} {point[2]*0.3048:.3f} {point[3]*0.3048:.3f} {point[4]*0.3048:.3f} # Conversion feet - meter\n" + fixPoint += f'\t\tstation {point[0]} "{point[0]}" entrance\n' ################################################################################################# # Gestion des formats ################################################################################################# - dataFormat, length, compass, clino, totReadMeErrorDat = dat_survey_format_extract(_line, currentSurveyName, shortCurentFile, totReadMeErrorDat) + dataFormat, length, compass, clino, totReadMeErrorDat = dat_survey_format_extract(_line, headerData, currentSurveyName, shortCurentFile, totReadMeErrorDat) if "grads" in compass: _compass = "grads" @@ -3023,15 +2947,8 @@ if __name__ == u'__main__': formatter_class=argparse.RawDescriptionHelpFormatter) parser.print_help = colored_help.__get__(parser) parser.add_argument("--file", help="the file (*.th, *.mak, *.dat, *.tro) to perform e.g. './Therion_file.th'", default="") - # parser.add_argument("--survey_name", help="Scrap name (if different from 'survey_file' name)", default="None") parser.add_argument("--proj", choices=['All', 'Plan', 'Extended', 'None'], help="the th2 files scrap projection to produce, default: All", default="All") - #parser.add_argument("--format", choices=['th2', 'plt'], help="Output format. Either th2 for producing skeleton for drawing or plt for visualizing in aven/loch", default="th2") - # parser.add_argument("--output", default="./", help="Output folder path") - # parser.add_argument("--therion-path", help="Path to therion binary", default="therion") parser.add_argument("--scale", help="scale for the pdf layout exports, default value: 1000 (i.e. xvi files scale is 100)", default="1000") - # parser.add_argument("--lines", type=str_to_bool, help="Shot lines in th2 files", default=-1) - # parser.add_argument("--names", type=str_to_bool, help="Stations names in th2 files", default=-1) - # parser.add_argument("--update", help="Mode update, option th2", default="") parser.add_argument("--update", help="th2 files update mode (only for th input files, no folders created)", action="store_true", default=False) parser.epilog = ( diff --git a/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace b/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace index f2e7e5c..9fea0b7 100644 --- a/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace +++ b/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace @@ -28,6 +28,7 @@ "geocentricofaustralia", "icomments", "Makto", + "Noeuds", "northamerican", "northamericandatum", "nouvelletriangulationfrançaise", @@ -36,6 +37,7 @@ "thanksto", "thconfig", "therion", + "Urruty", "vtopo", "vtopofile", "vtopotools",