From b6d4a2dc47d5041902df4a2fb85b5b0e3a5fc24a Mon Sep 17 00:00:00 2001 From: Alex38Lyon <55714436+Alex38Lyon@users.noreply.github.com> Date: Tue, 24 Jun 2025 09:11:26 +0200 Subject: [PATCH] pyCreateTh --- Scripts/pyCreateTh.log | 13 + Scripts/pyCreateTh/.vscode/launch.json | 16 + Scripts/pyCreateTh/.vscode/settings.json | 2 + .../general_fonctions.cpython-313.pyc | Bin 12189 -> 12189 bytes .../__pycache__/global_data.cpython-313.pyc | Bin 3827 -> 4084 bytes .../Lib/__pycache__/therion.cpython-313.pyc | Bin 12523 -> 14163 bytes Scripts/pyCreateTh/Lib/general_fonctions.py | 1 - Scripts/pyCreateTh/Lib/global_data.py | 14 + Scripts/pyCreateTh/Lib/therion.py | 29 +- Scripts/pyCreateTh/app.log | 0 Scripts/pyCreateTh/pyCreateTh.py | 286 ++++++++++++------ 11 files changed, 256 insertions(+), 105 deletions(-) create mode 100644 Scripts/pyCreateTh/.vscode/launch.json delete mode 100644 Scripts/pyCreateTh/app.log diff --git a/Scripts/pyCreateTh.log b/Scripts/pyCreateTh.log index 92b3a46..fcf1ed7 100644 --- a/Scripts/pyCreateTh.log +++ b/Scripts/pyCreateTh.log @@ -11,3 +11,16 @@ 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 diff --git a/Scripts/pyCreateTh/.vscode/launch.json b/Scripts/pyCreateTh/.vscode/launch.json new file mode 100644 index 0000000..72f6f9c --- /dev/null +++ b/Scripts/pyCreateTh/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + {"name":"Débogueur Python : Fichier actuel","type":"debugpy","request":"launch","program":"${file}","console":"integratedTerminal"}, + { + "name": "Débogueur Python : Fichier actuel", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/Scripts/pyCreateTh/.vscode/settings.json b/Scripts/pyCreateTh/.vscode/settings.json index b1eaafe..37db963 100644 --- a/Scripts/pyCreateTh/.vscode/settings.json +++ b/Scripts/pyCreateTh/.vscode/settings.json @@ -52,6 +52,7 @@ "northamericandatum", "nouvelletriangulationfrançaise", "pulkovo", + "resultats", "sinfo", "sirgas", "southamerican", @@ -62,6 +63,7 @@ "thconfig", "therion", "totdata", + "totfile", "UUUUDDDDSSSB", "UUUUDDDDSSSBL", "UUUUDDDDSSSSSBL", diff --git a/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc index 6e1b5cc7d65841d005f56b4bfc3886a1e0a8875f..2743616caf6a2a1f8439fcc17305111e8d6e5567 100644 GIT binary patch delta 39 scmbOmKR2HDGcPX}0}#A<9g*>SBkwX@M)A#CbRRHsTCg%|6{!Ga01o2|)Bpeg delta 39 scmbOmKR2HDGcPX}0}#xv3(5Gqk$0Icqr~Pdx(^sRtymegid29y0Q=($7XSbN diff --git a/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/global_data.cpython-313.pyc index b67c2f7cf73c0d73f0c5911dccd97db139f7bda5..84173067e46405875605f7b04efbd207f830ec7c 100644 GIT binary patch delta 490 zcmew?`$eAbGcPX}0}!0_iOR?nnaC%>_-&$kZhf#=k(2>Luz0XUJY%qAuoRG#4weCu zvS3m!SRTk$0F#PfQYly&D53%;Rl%fMusTpg159cLYXRBX!8$-v7fkAbN&R30pojqw z8iJuwuyL>n5b~P@n+BWdal0}WNvE4@T5OhMe9l;3^_o*zSs}Qzs4TToAuTf})ru=K zub{L_{=LG^G}y9Nc-V$-P$QU%m*gsI=P zqNF}GFC{gFupvODV3pVn@=Yu##$pEC^}4x01t2dZ&SGR>;7ZL)&QHnAOIIi@*(}C9 zor6(k@;dHo9PB0eC7=+P+{|;3D*zaOK(!3TOD6mA=5TOubF(zCe~{a}o7aSq#SbU} E08GY&S^xk5 delta 223 zcmew&|5=vrGcPX}0}$M>2+d#?p2#P`_-UegZoL6RuvoBoJY%p#uq2R_3YG?vGGJ0R zSPsaR2a^h5QZZNwD54A|RluZbuo_TA9ZYHjYXaF?!P-Dl2TbaMNxfiwpol&Y8i1i; zuu-rv7@7nNnCfx6G8Rdtn`xRSN-{DqOn%51zqyUEnQ`+s<`o=_(v#=&T$^0Sdw|Oy a=ysqyL-E|n9(*~BT$}gsnJ}{W0!09rBsMz$ diff --git a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc index 1bf1b1c360390915ce63ae34d88d79654a189c8c..4f9173f30443dc5e6f26f66048f06046332b8696 100644 GIT binary patch delta 3328 zcmcImYiv`=6`mQ}dE0RwI&@KUVZlTPn5MT~Vn-q5>+UY*Zx1Ypbpze(YBK=^F@LP^*fbaqz;DZWpOq zOZR+p=bU@acV^C+@t>XXkYZgf&q46J?Huxr={{CmE5t=tR|m8)rn zu1MXF_F-;_kPX?grAUDs%8hq~gc9mhZ>h=ID@)sGksaBkc9}iHp81B%mRo@WSs~&m zqYu?pifUvhw!B6hlGr7Jie9eJVL823u|v?<=A7c3cFyM!{o#<-(f@qV9-f}@PkFR| zeDdtsv&Etjqt=z0an5nGNl>}cR5<3sQv}cY9obcVWjV$_rfpS+iKBv!ORI>Wp`YtC z1zD*SO1M4$30j_lJlpYNrW$67mHnBJ>5IvfS!K@N>=&6jwr;pUs09mk)Tu3^e^F)0 zIfK;CjsycFsiIk`YFy7p5+oS8U1o06NrapifSwNL(E^S3bx2aBCJ(2`Nx?NZQWsb3 z&HN@lrC;*#B1d7Go6x{{V8v_1-o+QFHvi>4_97i}>`D8|M9y~+3P~J=^xs<5Yx&$* zbmdFyo61XVmnhITr-X}WP*Z~o=mm|LR#j#bBBP&cYO?!TYXs!~%DYjEQiY;TuMiZ|oYS7Q%z-wc$I@dK_j0p0xtZ*UAoL1iU25EM=NX+PWudy3w`Vb*=SI^l|hdSG?2BJU%w*W1W6x2_%BE z$>8Z&@H7i7vc)rx5n93>-r1 zo_kfA%a%(Pwyp7c-HoVm*?3KThuqCv%}gF0j2#_hL(cfo3Few)?n!pk%gnxnKb-W> z$Nclmx4;%oB~C{n@*+OMBXfWtr?H8HnOHfPNEZivH>arTfyi}Nw#QX(@W|FnR<^zQ zdOGdsx0yGOE|B{#=lg29(QhN)M_Z82`1ElJD$}ha3_E?Vxb&j+Ju9njzinFSy47{F zH6ipTg`t=b9ZCulF#*;)7#F74^b8BlFkzM*6BCisz<&-O=F7|hRy2a!Ikb}=0yWS} z?0kWH$uKwJ0JM^f#OA7E8h8 zLS0F}CT+s6?WWCl{9@TF*L!5%$jPrZMW-IjJJ$8)rmeK z**6gD8%Xwz$NI*Z(;x2(uwaNyg;-yh_0A+_PbO#2#%9m5nI%~KC>Ho`*~k#z1RLxK z>;ebS31p1JIPr2ABR+2FCt+^sC-dBr1L#V9WP#%X5hMVWHVIf3^h@Xmz-`|zCx12d z@zh77w-2wFZ<&)F{jrXIW*>=njIyx_Ha@{RT&&%l@C1{d*_daRxkd01f#U+4SjjOS z&PtB+a2!C_Nd`C!0zc3Vk^t9nfXM+8Qh#N4Olka`QvWyu z6%=30dM}GrHeG-7#)0Jn*LL11yj!|jnzRhXEJJK~B5rXpx0iXm%;IB5{fWR#GO!Q} zEHM8`@O=uW&aR4My2+a^6Qvw3Ga^oDGb{O|T_yHsNL_4?8lM@J=Vak(f8aCg;HMJhpPyT}0q{bwQSp7YEQ;$smWJ zjYb;WXr$5;++IFH=y`*#!Mwwgi&l2Gl>@Bi=2&Yat6L6Bt!l|{)iQW7U~v*E$dLcM z>S)YRuiMWnE>(MBKJs%B;35dZkR`fk+4jzyd3fQa8o5cQwhu>l{(RxXGe0|XC3Ic5 zF|a(4Z0U}*bbsQDw+ygB2ODy*mJ{s2NMh8T91X-q18gM7f=f&u1+KC-@RV*rf!7acwy_Z}Tx~c05NG@XCL(rvs9_8JVuu3Xr?Q><@B(e#`RmfRK_xD6aSnum zh_!rtp5`~`W#5J2GHq@+1h!`yv_(AGH6p?lIu-VM;a(Q~^uq?1i7$l6gRW(695WvA zET4k^BuG5KMJft+C+fIZ;G!4ATGoN-uzP;W(<;782Y0n8^4c&yfgkmdgShaKiT-p~ gojL>8J}5?ciVICYXksNT@!ZyPS?f|6u1vZ451rnJApigX delta 2157 zcmbVNeN0nV6u-A0v=sWN2<4+6w16$OAfH7kg@Fr2pESj1#%T}-^S%#wyb*&oaP7!wl7_J_L<=s?{+?j`Sc&%5`Y z^E>CM@*I*f=;b^4b_Mz)T?^yTCPiME#^HA{ zevQAEX8L?yjoUXk)HmSrbMk?{0otr_ukx%S=iX-WF7^nneW*x-a6kG|xl_<2q5!HA zsMQp3h>L~m{&Xm#+7-~QMjEX`nh>3F0=t$tqC!tpnJ|l!RKT7cU0oj?vF0NHxNL+; z3ne5Pjew|TBTYtf+J?|yq%!_XeE08i>8{_12w*j5iZGo}qhAv0g_vGo* zr|4H*rXtl&yL$S(9!=9)q5FpYL&JWv#vnyI^vawF&&NgtLoR=BM7-a{(q7jf%?Jn^ zQ_Mjr2RZ`iynZCnO9XbDT)^dVu)vdUYJey^r)X^F&DzP@u*DX%*aEE~OEYe1$F1$y z(t*o6ap&HdZaUoEAMEbOdk^A)A$;%<&S4%Y*;!Tgge0UYnp0+cy8FUzoKrTHc~d{B z51Z?P=DNU+khuvvTXAzMHn-ujcHG`M)8!6#^#;3oac3Xy_u@Vu)(t%xQy!XC=_a;@ zR3)6L`U~}VYx&gwaVo52=U?8Lv5nq@m4_ZD18wf|k{qOJ7Xc(mnoCMKSAV7+XPT!< zZBK4ZKJU zX;>cG9}$p&9m$R!s9Un$x=^msBv!7ipfRKT6)L)IwW*EBpXqe$u-i@3J#^1V(lhfk z!}u6dBPr-NeJb7@wPFS!N&lAU73u zqszH<30wF zBbk0)w)vd+jQD)z72P++FN_na>!Z`VLfac~Y2*FF4@U2e2E4eF!D;L-GXL^?Lh2&m z#Tw?~6Hf1bXZLyP^TU^qeRk~P;C0({YN(_R7uVmnKCornvjr+~+u)4XANC#%dXM74 z5qxYEj~vJH6EpE+=vKZqzeaD}25uXxd1Sb=O|mPWe`iN^-mb0uz*ZsoFhFKMmn@2D zBLmZpHWe6^E4PfxCqr{^fCCQ!gP7??T?KU#hJ198m;D%BEoiUGzaH~_+|{^=<5Qi1 zoKS@WTbi)cIU{I(BFGmS{saV;dLW=u!cx^ksp_I5C^d{*X9beCZ6|GSHO``;!f7~+ z3X3X)uM?}EAhxIsve&*U`UuLda5OCh#=%kykfoy6N)&Jo4VIW7i!PP?m~xV=F~>MK zPQbupws7(Zbi||=zCpwv&?Qq9**kC2Z02H&@EAHG8t{2MqysTDN-1?)xp)|kIwD&A z=hDmwH#N$Eg@Y9q&K#rVfaPEhfr!{L=<69Cpevd8&~#}vMO8!C2_HA|EHLr$PL!}+ frxw923vv)ooi@K~#`20#T;;fUF-8a#D`x%yPW)Mg diff --git a/Scripts/pyCreateTh/Lib/general_fonctions.py b/Scripts/pyCreateTh/Lib/general_fonctions.py index 02d9d65..3f5ceaf 100644 --- a/Scripts/pyCreateTh/Lib/general_fonctions.py +++ b/Scripts/pyCreateTh/Lib/general_fonctions.py @@ -275,7 +275,6 @@ def setup_logger(logfile="app.log", debug_log=False): return logger - ################################################################################################# def release_log_file(logger): handlers = logger.handlers[:] diff --git a/Scripts/pyCreateTh/Lib/global_data.py b/Scripts/pyCreateTh/Lib/global_data.py index 47f6b01..f41f247 100644 --- a/Scripts/pyCreateTh/Lib/global_data.py +++ b/Scripts/pyCreateTh/Lib/global_data.py @@ -30,6 +30,20 @@ linesInTh2 = -1 stationNamesInTh2 = -1 +################################################################################################# +totfile = """\t## Survey file: +\tinput Data/{TH_NAME}.th + +\t## Plan file: +\t{ERR}input Data/{TH_NAME}-Plan.th2 + +\t## Extended file: +\t{ERR}input Data/{TH_NAME}-Extended.th2 + +\t## Maps file: +\t{ERR}input {TH_NAME}-maps.th +""" + ################################################################################################# thFileDat = """ diff --git a/Scripts/pyCreateTh/Lib/therion.py b/Scripts/pyCreateTh/Lib/therion.py index cebfe69..429d520 100644 --- a/Scripts/pyCreateTh/Lib/therion.py +++ b/Scripts/pyCreateTh/Lib/therion.py @@ -12,7 +12,6 @@ from Lib.general_fonctions import Colors, safe_relpath log = logging.getLogger("Logger") - ################################################################################################# # Compilation Therion 'Template' (version sans blocage) # # Compiler une configuration générée dynamiquement à partir d'un template texte. # @@ -94,7 +93,7 @@ def compile_file(filename, **kwargs): therion_path = kwargs.get("therion_path", "therion") timeout = kwargs.get("timeout", 240) - log.info(f"Start therion compilation file: {Colors.ENDC}{safe_relpath(filename)}") + log.info(f"Start therion [Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.GREEN}], compilation file") def run(): try: @@ -113,22 +112,22 @@ def compile_file(filename, **kwargs): line = line.rstrip() lower_line = line.lower() if "average loop error" in lower_line: - log.warning(f"[Therion Compile {os.path.basename(filename)[:-9]}] {Colors.ENDC}{line}") + log.warning(f"[Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.WARNING}] {Colors.ENDC}{line}") elif "error" in lower_line: - log.error(f"[Therion_Compile {os.path.basename(filename)[:-9]}] {Colors.ENDC}{line}") + log.error(f"[Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}] {Colors.ENDC}{line}") elif "warning" in lower_line: - log.warning(f"[Therion Compile {os.path.basename(filename)[:-9]}] {Colors.ENDC}{line}") + log.warning(f"[Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.WARNING}] {Colors.ENDC}{line}") else: - log.debug(f"[Therion Compile {os.path.basename(filename)[:-9]}] {Colors.ENDC}{line}") + log.debug(f"[Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.DEBUG}] {Colors.ENDC}{line}") except Exception as e: - log.warning(f"Reading Therion output: {Colors.ENDC}{e}") + log.warning(f"Reading Therion [Therion_Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.WARNING}], output: {Colors.ENDC}{e}") 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 timed out after {Colors.ENDC}{timeout}{Colors.ERROR} seconds. Killing process...") + 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() @@ -136,22 +135,24 @@ def compile_file(filename, **kwargs): process.wait() if process.returncode != 0: - log.error(f"Therion returned error code {Colors.ENDC}{process.returncode}") + 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: - log.info(f"Therion file: {Colors.ENDC}{safe_relpath(filename)}{Colors.GREEN} compilation succeeded") + # 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: - log.error(f"Therion file: {Colors.ENDC}{safe_relpath(filename)}{Colors.ERROR} compilation error: {Colors.ENDC}{e}") + log.error(f"Therion file: [Therion Compile {Colors.WHITE}{os.path.basename(filename)[:-9]}{Colors.ERROR}], compilation error: {Colors.ENDC}{e}") global_data.error_count += 1 # 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} @@ -170,10 +171,9 @@ lengthre = re.compile(r".*Longueur totale de la topographie = \s*(\S+)m") depthre = re.compile(r".*Longueur totale verticale =\s*(\S+)m") def get_stats_from_log(log): - - lenmatch = lengthre.findall(log) depmatch = depthre.findall(log) + if len(lenmatch) == 1 and len(depmatch) == 1: return {"length": lenmatch[0], "depth": depmatch[0]} return {"length": 0, "depth": 0} @@ -182,7 +182,6 @@ def get_stats_from_log(log): ################################################################################################# syscoord = re.compile(r".*output coordinate system: \s*(\S+)") - def get_syscoord_from_log(log): lenmatch = syscoord.findall(log) diff --git a/Scripts/pyCreateTh/app.log b/Scripts/pyCreateTh/app.log deleted file mode 100644 index e69de29..0000000 diff --git a/Scripts/pyCreateTh/pyCreateTh.py b/Scripts/pyCreateTh/pyCreateTh.py index 66135bf..fd890c6 100644 --- a/Scripts/pyCreateTh/pyCreateTh.py +++ b/Scripts/pyCreateTh/pyCreateTh.py @@ -21,28 +21,25 @@ Version 2025 06 16 : Création fonction create_th_folders En cours : - - gérer les visées orphelines dans une même survey - gérer les updates (th, dat, mak) - créer fonction pour faire habillage des th2 files, les jointures... - 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 - - gérer le cas ou il y a 2 SurveyTitle identiques - tester la nouvelle version de DAT (CORRECTION2 et suivants) - - tester différents cas et versions de dat et mak - - pb de equate avec points non valides (non répétable ?) - - vérifier le fonctionnement de merge survey (les valeurs compilées et les critères de compilation... voir ) - comparer résultats Therion - Compass (Stat, kml, etc....) + - intégrer .tro files d'après XRo + """ -Version ="2025.06.18" +Version ="2025.06.24" ################################################################################################# ################################################################################################# -import os, re, unicodedata, argparse, shutil, sys, time +import os, re, unicodedata, argparse, shutil, sys, time, math from os.path import isfile, join, abspath, splitext import pandas as pd pd.set_option('future.no_silent_downcasting', True) @@ -57,7 +54,6 @@ from Lib.therion import compile_template, compile_file, get_stats_from_log from Lib.general_fonctions import setup_logger, Colors, safe_relpath, colored_help, read_config, select_file_tk_window, release_log_file import Lib.global_data as globalData -log = setup_logger(logfile="app.log", debug_log=True) ################################################################################################# configIni = "config.ini" # Default config file name @@ -282,6 +278,36 @@ def str_to_bool(value): else: raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}") +################################################################################################# +def convert_to_line_polaire(lines): + line_polaire = [] + + for line in lines: + try: + x1 = float(line[0]) + y1 = float(line[1]) + x2 = float(line[2]) + y2 = float(line[3]) + name1 = line[4] + name2 = line[5] + + dx = x2 - x1 + dy = y2 - y1 + + # Longueur (distance) + length = math.hypot(dx, dy) + + # Roth = azimut en degrés, 0° = Est, 90° = Nord + roth_rad = math.atan2(dy, dx) + roth_deg = (math.degrees(roth_rad)) % 360 # pour rester entre 0-360 + + line_polaire.append([x1, y1, roth_deg, length, name1, name2]) + + except Exception as e: + print(f"Erreur sur la ligne {line} : {e}") + + return line_polaire + ################################################################################################# def parse_xvi_file(th_name_xvi): @@ -335,9 +361,83 @@ def parse_xvi_file(th_name_xvi): station1 = stations[key1][2] if key1 in stations else None station2 = stations[key2][2] if key2 in stations else None lines.append([x1, y1, x2, y2, station1, station2]) - + + return stations, lines, x_min, x_max, y_min, y_max, x_ecart, y_ecart +################################################################################################# +def wall_construction(stations, lines): + + station_names = {s[2] for s in stations.values()} + + # Séparer lines en lignes valides et splays + splays = {} + filtered_lines = [] + for i, line in enumerate(lines): + if line[4] in station_names and line[5] in station_names: + filtered_lines.append(line) + else: + splays[f"splay_{i}"] = line + + # Conversion polaire + lines_polaire = convert_to_line_polaire(filtered_lines) + splays_polaire = convert_to_line_polaire(list(splays.values())) + + # Index rapide des lignes polaires par nom de station (col. 4) + index_by_station = { + line[4]: idx for idx, line in enumerate(lines_polaire) + } + + # Associer à chaque splay son index de ligne, et récupérer roth/length + 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) + 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)}") + 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 + + + ################################################################################################# # Création des dossiers à partir d'un th file # ################################################################################################# @@ -478,19 +578,10 @@ def create_th_folders(ENTRY_FILE, ################################################################################################# if UPDATE == "": - ERR = "# " if flagErrorCompile else "" - - totdata = f"""\tinput Data/{TH_NAME}.th - -\t## Pour le plan -\t{ERR}input Data/{TH_NAME}-Plan.th2 - -\t## Pour la coupe développée -\t{ERR}input Data/{TH_NAME}-Extended.th2 - -\t## Appel des maps -\t{ERR}input {TH_NAME}-maps.th -""" + totdata = globalData.totfile.format( + TH_NAME = TH_NAME, + ERR = "# " if flagErrorCompile else "" + ) # Adapte templates config_vars = { @@ -533,6 +624,8 @@ def create_th_folders(ENTRY_FILE, stations, lines, x_min, x_max, y_min, y_max, x_ecart, y_ecart = parse_xvi_file(th_name_xvi) + # wall wall_construction(stations, lines) + if UPDATE == "th2": th2_name = DEST_PATH + "/" + TH_NAME else : @@ -897,7 +990,7 @@ def mak_to_th_file(ENTRY_FILE) : stationList = pd.DataFrame(columns=['StationName', 'Survey_Name_01', 'Survey_Name_02']) - totdata = f"\t## Liste inputs\n" + totdata = f"\t## Input list:\n" totMapsPlan = "" totMapsExtended = "" @@ -915,7 +1008,10 @@ def mak_to_th_file(ENTRY_FILE) : with redirect_stdout(sys.__stdout__): for file in datFiles: - bar.text(f"{Colors.INFO}file: {Colors.ENDC}{file}") + if globalData.error_count > 0: + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{file[:-4]}{Colors.ERROR}, error: {Colors.ENDC}{globalData.error_count}") + else : + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{file[:-4]}") _file = os.path.dirname(abspath(args.survey_file)) + "\\" + file shutil.copy(_file, folderDest + "\\Data\\") @@ -933,8 +1029,9 @@ def mak_to_th_file(ENTRY_FILE) : totMapsExtended += f"\tMC-{SurveyTitle}-Extended-tot@{SurveyTitle}\n\tbreak\n" if not Station.empty: - stationList = pd.concat([stationList, Station], ignore_index=True) - stationList.sort_values(by='Survey_Name_02', inplace=True, ignore_index=True) + __stationList = pd.concat([stationList, Station], ignore_index=True) + __stationList.sort_values(by='Survey_Name_02', inplace=True, ignore_index=True) + stationList = __stationList.copy() destination = os.path.join(folderDest, "Sources", os.path.basename(ABS_file)) if os.path.exists(destination): @@ -946,7 +1043,7 @@ def mak_to_th_file(ENTRY_FILE) : ################################################################################################# - # Gestion des equats + # Gestion des equates ################################################################################################# totdata +=f"\n" @@ -966,17 +1063,16 @@ def mak_to_th_file(ENTRY_FILE) : # print(f"tableau_pivot : {Colors.ENDC}{tableau_pivot}{Colors.INFO} in {Colors.ENDC}{args.survey_file}") - totdata +=f"\n\t## Liste equates\n" + totdata +=f"\n\t## Equates list:\n" if 'Survey_Name_2' in tableau_pivot.columns: # On réinitialise l'index pour avoir StationName comme colonne normale tableau_pivot = tableau_pivot.reset_index() tableau_equate = tableau_pivot[tableau_pivot['Survey_Name_2'].notna()] - - log.info(f"Total des 'equats' : {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.survey_file)}") # print(tableau_equate) - # print(f"fixePoints : {Colors.ENDC}{fixed_names}{Colors.INFO} in {Colors.ENDC}{args.survey_file}") + # print(f"fixPoints: {Colors.ENDC}{fixPoints}{Colors.INFO} in {Colors.ENDC}{args.survey_file}") # Pour chaque ligne du tableau for _, row in tableau_equate.iterrows(): @@ -994,7 +1090,7 @@ def mak_to_th_file(ENTRY_FILE) : else: log.info(f"No 'equats' found in {Colors.ENDC}{args.survey_file}") - totdata +=f"\n\t## Appel des maps\n\tinput {SurveyTitleMak}-maps.th\n" + totdata +=f"\n\t## Maps list:\n\tinput {SurveyTitleMak}-maps.th\n" config_vars = { 'fileName': SurveyTitleMak, @@ -1039,7 +1135,7 @@ def mak_to_th_file(ENTRY_FILE) : ################################################################################################# -def station_list(data, list, fixPoints) : +def station_list(data, list, fixPoints, currentSurveyName) : """ Crée une liste de stations à partir des données fournies. @@ -1065,7 +1161,7 @@ def station_list(data, list, fixPoints) : new_entries = pd.DataFrame({ 'StationName': stations, - 'Survey_Name_01': data['SURVEY_NAME'] + 'Survey_Name_01': currentSurveyName }) list = pd.concat([list, new_entries], ignore_index=True) @@ -1341,54 +1437,58 @@ def find_duplicates_by_date_and_team(data): duplicates = [] - # Étape 2 : chercher les entrées ayant des stations communes for key, entries in grouped.items(): if len(entries) < 2: continue - visited_pairs = set() + # Construire un mapping ID -> stations + id_to_entry = {entry['ID']: entry for entry in entries} + id_to_stations = {entry['ID']: set(entry['STATION'].iloc[:, 0]) for entry in entries} - for i in range(len(entries)): - id_i = entries[i]['ID'] - stations_i = set(entries[i]['STATION'].iloc[:, 0]) + # Construire les connexions directes (graphe implicite) + adjacency = defaultdict(set) + ids = list(id_to_entry.keys()) - ids_group = [id_i] - common_stations = set() + for i in range(len(ids)): + for j in range(i + 1, len(ids)): + id_i, id_j = ids[i], ids[j] + if id_to_stations[id_i] & id_to_stations[id_j]: # intersection non vide + adjacency[id_i].add(id_j) + adjacency[id_j].add(id_i) - for j in range(i+1, len(entries)): - pair = tuple(sorted((id_i, entries[j]['ID']))) - if pair in visited_pairs: - continue + # Trouver les composantes connexes (DFS) + visited = set() - visited_pairs.add(pair) - stations_j = set(entries[j]['STATION'].iloc[:, 0]) - intersection = stations_i & stations_j + def dfs(node, component): + visited.add(node) + component.append(node) + for neighbor in adjacency[node]: + if neighbor not in visited: + dfs(neighbor, component) - if intersection: - ids_group.append(entries[j]['ID']) - common_stations.update(intersection) + for id_ in ids: + if id_ not in visited: + component = [] + dfs(id_, component) + if len(component) > 1: + # Calcul des stations communes (fusion de toutes) + stations_union = set() + for i in range(len(component)): + for j in range(i + 1, len(component)): + common = id_to_stations[component[i]] & id_to_stations[component[j]] + stations_union.update(common) - if len(ids_group) > 1: - ids_group = sorted(set(ids_group)) - common_stations = sorted(common_stations) - already_recorded = False - - for d in duplicates: - if set(d['IDS']) == set(ids_group): - already_recorded = True - break - - if not already_recorded: duplicates.append({ 'SURVEY_DATE': key[0], 'SURVEY_TEAM': key[1], - 'IDS': ids_group, - 'COMMON_STATIONS': common_stations + 'IDS': sorted(component), + 'COMMON_STATIONS': sorted(stations_union) }) return duplicates + ################################################################################################# def points_uniques(data, crs_wkt): # Création d'un DataFrame à partir des lignes de données @@ -1694,7 +1794,6 @@ def load_text_file_utf8(filepath, short_filename): return None, "" - ################################################################################################# # Création des dossiers Th à partir d'un dat # ################################################################################################# @@ -1733,7 +1832,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", # Listes pour stocker les données data = [] unique_id = 1 - totdata = f"\t## Liste inputs\n" + totdata = f"\t## Input list:\n" totMapsPlan = "" totMapsExtended = "" totReadMeErrorDat = "" @@ -1844,7 +1943,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", # Ajouter les données de la section à la liste if len(section_data['DATA']) > 0 : - listStationSection, dfDATA = station_list(section_data, listStationSection, fixPoints) + listStationSection, dfDATA = station_list(section_data, listStationSection, fixPoints, section_data['SURVEY_NAME']) section_data['STATION'] = listStationSection data.append(section_data) unique_id += 1 @@ -1911,7 +2010,6 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", ################################################################################################# surveyCount = 1 - SurveyListEqui = [] # totReadMe += f"* Source file: {os.path.basename(ENTRY_FILE)}\n" @@ -1963,14 +2061,13 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", 'SURVEY_NAME': _line['SURVEY_NAME'] } - SurveyListEqui.append(SurveyNameCount) ################################################################################################# # gestion des DATA # ################################################################################################# - - stationList, dfDATA = station_list(_line, stationList, fixPoints) + + stationList, dfDATA = station_list(_line, stationList, fixPoints, currentSurveyName) ################################################################################################# # Recherche des points fixes (entrées) @@ -2057,7 +2154,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", totReadMeError = totReadMeErrorDat) threads += thread2 - log.info(f"File: {Colors.ENDC}{os.path.basename(ENTRY_FILE)}.dat{Colors.INFO} compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m") + log.info(f"File: {Colors.ENDC}{currentSurveyName}{Colors.INFO}, compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m") totReadMe += f"\t{currentSurveyName} compilation successful length: {stat["length"]} m, depth: {stat["depth"]} m\n" _destination = output_file[:-3] + "\\Sources" @@ -2075,6 +2172,10 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", totMapsExtended += f"\tMC-{currentSurveyName}-Extended-tot@{currentSurveyName}\n\tbreak\n" surveyCount += 1 + if globalData.error_count > 0: + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{os.path.basename(ENTRY_FILE)[:-4]}{Colors.INFO}, survey: {Colors.ENDC}{currentSurveyName}{Colors.ERROR}, error: {Colors.ENDC}{globalData.error_count}") + else : + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{os.path.basename(ENTRY_FILE)[:-4]}{Colors.INFO}, survey: {Colors.ENDC}{currentSurveyName}") bar() ################################################################################################# @@ -2082,37 +2183,33 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", ################################################################################################# ################################################################################################# - # Gestion des equats + # Gestion des equates ################################################################################################# totdata +=f"\n" - - dfEqui = pd.DataFrame(SurveyListEqui) - stationList = stationList.merge(dfEqui, how='left', left_on='Survey_Name_01', right_on='SURVEY_NAME') - stationList['Survey_Name_01'] = stationList['surveyCount'] - stationList.drop(columns=['SURVEY_NAME', 'surveyCount'], inplace=True) - + _stationList = stationList.copy() # On numérote les doublons de Survey_Name pour chaque StationName _stationList['Survey_Number'] = _stationList.groupby('StationName').cumcount() + 1 + # print(_stationList) + # On pivote le tableau pour que chaque Survey_Name devienne une colonne tableau_pivot = _stationList.pivot(index='StationName', columns='Survey_Number', values='Survey_Name_01') 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}{ENTRY_FILE}") + # print(f"tableau_pivot: {Colors.ENDC}{tableau_pivot}{Colors.INFO} in {Colors.ENDC}{ENTRY_FILE}") - totdata +=f"\n\t## Liste equates\n" + totdata +=f"\n\t## equates list:\n" if 'Survey_Name_2' in tableau_pivot.columns: # On réinitialise l'index pour avoir StationName comme colonne normale tableau_pivot = tableau_pivot.reset_index() tableau_equate = tableau_pivot[tableau_pivot['Survey_Name_2'].notna()] - - log.info(f"Total 'equats' : {Colors.ENDC}{len(tableau_equate)}{Colors.INFO} in {Colors.ENDC}{shortCurentFile}") + log.info(f"Total 'equates' founds: {Colors.ENDC}{len(tableau_equate)}{Colors.INFO} in {Colors.ENDC}{shortCurentFile}") # print(tableau_equate) # print(f"fixePoints : {Colors.ENDC}{fixed_names}{Colors.INFO} in {Colors.ENDC}{ENTRY_FILE}") @@ -2123,15 +2220,14 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", # On récupère tous les Survey_Name non vides (NaN exclus) surveys = [row[col] for col in tableau_equate.columns if col.startswith('Survey_Name') and pd.notna(row[col])] - # Pour chaque paire unique (i < j), on écrit la ligne 'equate' for i in range(len(surveys)): for j in range(i + 1, len(surveys)): totdata +=f"\tequate {station}@{surveys[i]}.{surveys[i]} {station}@{surveys[j]}.{surveys[j]}\n" else: - log.info(f"No 'equats' found in {Colors.ENDC}{ENTRY_FILE}") + log.info(f"No 'equates' found in {Colors.ENDC}{ENTRY_FILE}") - totdata +=f"\n\t## Appel des maps\n\tinput {SurveyTitle}-maps.th\n" + totdata +=f"\n\t## Maps list:\n\tinput {SurveyTitle}-maps.th\n" if totReadMeErrorDat == "" : totReadMeErrorDat += "\tAny error in this file, that's perfect !\n" @@ -2216,7 +2312,7 @@ if __name__ == u'__main__': #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 exports", default="1000") + parser.add_argument("--scale", help="Scale for the exports", default="100") 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="") @@ -2331,10 +2427,22 @@ if __name__ == u'__main__': log.critical(f"The folder {Colors.ENDC}{SurveyTitleDat}{Colors.ERROR}{Colors.BOLD}, all ready exist : update mode is not possible for mak files") exit(0) - with alive_bar(QtySections, title=f"{Colors.GREEN}Surveys progress: {Colors.BLUE}", length = 20, enrich_print=False) as bar: + with alive_bar( + QtySections, + title=f"{Colors.GREEN}Surveys progress: {Colors.BLUE}", + length = 20, + enrich_print=False, + stats=True, # Désactive les stats par défaut pour plus de lisibilité + elapsed=True, # Optionnel : masque le temps écoulé + monitor=True, # Optionnel : masque les métriques (ex: "eta") + bar="smooth" # Style de la barre (autres options: "smooth", "classic", "blocks") + ) as bar: with redirect_stdout(sys.__stdout__): for i in range(1): - bar.text(f"{Colors.INFO}file: {Colors.ENDC}{os.path.basename(ABS_file)}") + if globalData.error_count > 0: + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{os.path.basename(ABS_file)[:-4]}{Colors.ERROR}, error: {Colors.ENDC}{globalData.error_count}") + else : + bar.text(f"{Colors.INFO}, file: {Colors.ENDC}{os.path.basename(ABS_file)[:-4]}") stationList, fileTitle, totReadMeError, thread2 = dat_to_th_files (ABS_file , fixPoints = [], crs_wkt = "", CONFIG_PATH = _ConfigPath, totReadMeError = "", bar = bar) threads += thread2 bar()