From 77d57d67dcfb057fb8ca7a8b45169b5f602dcc79 Mon Sep 17 00:00:00 2001 From: Alex38Lyon <55714436+Alex38Lyon@users.noreply.github.com> Date: Tue, 1 Jul 2025 16:17:33 +0200 Subject: [PATCH] pyCreateTh --- Scripts/pyCreateTh/.vscode/settings.json | 9 + .../general_fonctions.cpython-313.pyc | Bin 12202 -> 13369 bytes .../Lib/__pycache__/therion.cpython-313.pyc | Bin 14250 -> 14227 bytes Scripts/pyCreateTh/Lib/general_fonctions.py | 49 +- Scripts/pyCreateTh/Lib/pytro2th/__init__.py | 28 + .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 579 bytes .../__pycache__/_version.cpython-313.pyc | Bin 0 -> 200 bytes .../__pycache__/buildparam.cpython-313.pyc | Bin 0 -> 1219 bytes .../__pycache__/buildthconfig.cpython-313.pyc | Bin 0 -> 66627 bytes .../datathwritetools.cpython-313.pyc | Bin 0 -> 24594 bytes .../__pycache__/tro2th.cpython-313.pyc | Bin 0 -> 21327 bytes .../__pycache__/vtopotools.cpython-313.pyc | Bin 0 -> 8400 bytes Scripts/pyCreateTh/Lib/pytro2th/_version.py | 4 + .../pyCreateTh/Lib/pytro2th/bin/tro2therion | 4 + Scripts/pyCreateTh/Lib/pytro2th/buildparam.py | 95 ++ .../pyCreateTh/Lib/pytro2th/buildthconfig.py | 1186 +++++++++++++++++ .../pyCreateTh/Lib/pytro2th/command_line.py | 100 ++ .../Lib/pytro2th/datathwritetools.py | 569 ++++++++ Scripts/pyCreateTh/Lib/pytro2th/tests/Test.py | 131 ++ .../pyCreateTh/Lib/pytro2th/tests/__init__.py | 0 Scripts/pyCreateTh/Lib/pytro2th/tro2th.py | 501 +++++++ Scripts/pyCreateTh/Lib/pytro2th/vtopotools.py | 304 +++++ Scripts/pyCreateTh/Lib/therion.py | 2 +- Scripts/pyCreateTh/README.md | 9 - .../__pycache__/pyCreateTh.cpython-313.pyc | Bin 89991 -> 146918 bytes Scripts/pyCreateTh/pyCreateTh.py | 216 ++- .../pyCreateTh_VSCode.code-workspace | 10 + 27 files changed, 3133 insertions(+), 84 deletions(-) create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__init__.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/__init__.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/_version.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildparam.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildthconfig.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/datathwritetools.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/tro2th.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/__pycache__/vtopotools.cpython-313.pyc create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/_version.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/bin/tro2therion create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/buildparam.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/buildthconfig.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/command_line.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/datathwritetools.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/tests/Test.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/tests/__init__.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/tro2th.py create mode 100644 Scripts/pyCreateTh/Lib/pytro2th/vtopotools.py delete mode 100644 Scripts/pyCreateTh/README.md diff --git a/Scripts/pyCreateTh/.vscode/settings.json b/Scripts/pyCreateTh/.vscode/settings.json index f2b2959..4697aa2 100644 --- a/Scripts/pyCreateTh/.vscode/settings.json +++ b/Scripts/pyCreateTh/.vscode/settings.json @@ -14,7 +14,9 @@ "clino", "CLINO", "colwidth", + "coordsyst", "cumcount", + "dataold", "datat", "depmatch", "depthchange", @@ -31,15 +33,20 @@ "endscrap", "endsurvey", "equats", + "Errorfiles", "etrs", "ETRS", "european", "explo", + "fnme", "formated", "geocentricdatumofaustralia", "geocentricofaustralia", "Geophysicaya", + "icomments", + "icoupe", "isin", + "istructure", "Koef", "Larra", "lengthre", @@ -54,6 +61,7 @@ "northamericandatum", "nouvelletriangulationfrançaise", "pulkovo", + "pytro", "resultats", "roth", "rsuffix", @@ -66,6 +74,7 @@ "thanksto", "thconfig", "therion", + "thlang", "totdata", "totfile", "triees", diff --git a/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc index 0db41efc24c796df8b48c5b9f43d7bfc8b2fa6f9..22e7d3868302e2d7387fc68377e5e4f2015d8e3a 100644 GIT binary patch delta 2017 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:"/\\|?*\']', '_', th_name) # Illegal on Windows + th_name = re.sub(r'\s+', '_', th_name) # Spaces to underscores + th_name = re.sub(r'[^a-zA-Z0-9._-]', '_', th_name) # Keep only allowed chars + + # Convert to lowercase, then capitalize the first letter + # th_name = th_name.lower().capitalize() + # th_name = th_name.capitalize() + + # Suppression des underscores en début et fin + th_name = th_name.strip('_') + + return th_name or "default_filename" # Avoid empty result + + ################################################################################################# def select_file_tk_window(): """ @@ -131,7 +170,13 @@ def select_file_tk_window(): # Afficher la boite de dialogue de sélection de fichier file_path = filedialog.askopenfilename( title="Select your file", - filetypes=[("MAK files", "*.mak"), ("Compatibles files", "*.th *.mak *.dat"), ("TH files", "*.th"), ("DAT files", "*.dat"), ("All files", "*.*")] + filetypes=[ + ("Compatibles files", "*.th *.mak *.dat *.tro"), + ("MAK files", "*.mak"), + ("TH files", "*.th"), + ("DAT files", "*.dat"), + ("TRO files", "*.tro"), + ("All files", "*.*")] ) diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__init__.py b/Scripts/pyCreateTh/Lib/pytro2th/__init__.py new file mode 100644 index 0000000..7a6fb21 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/__init__.py @@ -0,0 +1,28 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later + + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer +from __future__ import absolute_import +from __future__ import print_function + +# Import modules +import sys +import os + +from . _version import __version__ + +# Import all the functions +__all__ = ['vtopotools', 'datathwritetools', 'buildthconfig', 'buildthconfig', 'tro2th.tro2th'] + +#from .text import joke +#from datathwritetools import writeheader_th, writecenterlineheader, writedata +from .buildparam import * +from .vtopotools import * +from .datathwritetools import * +from .buildthconfig import * +from .tro2th import * diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/__init__.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4aa8fc48fd6dcd8974cc8b34cf94351ca79d2400 GIT binary patch literal 579 zcmX|-&uSDw5XP(L|IRuw2Ne{-RZv*LBuGFBA_N5`6Gbx~2in=)PNrdYdZ_MM*&M`| z@FB!EYBwjzAvbaLZugGaK2-mzy1x3FS|&*h=9J%aw(A1?w8`ah{=@RKfv=E3Mp8H+ zNCuW2!wxztb`87euGmXG^vt`L`sinV7No&Jh~WUXAq(FVj7%*`drz#=QoN@Any#!V zv2@}Mdl&XIL!zSzpK-}WZTM<2lA>xAqkP&3RHn4iAg>iYZtJl!O>ZwqC+kx>V`z1h z4t*WZlxTz!qLO-ZQm8_epO7ooRgzK5tBESdqCVy)Xg744C=`!Xxz%09i98%`=$INS z)gq%5UDJl14ZaE5m2;^bA$4@=jG?WElonM*sg74JO@YM}BP;9KV9j*UxqO4A$v~$s z_wt>mgI8R=Zbx}GuT{w;d-N`QLl5_lj`s6xjJ#1YZ{{zM6^eZ*^Fux|X*VaQl-FEQ zy4B2e^lU07ZN;AB4Kv%WNA8;N%O!;T-2`&?93Gs({bc~8{{wpGaPM~j{g32J_$LB# SYXLVGaAyIx&)_;^M96-iYhG2#whIB?vrYcrLJ!3rsKTXD4-0|^c zsYS(^`FZj2D;Yk6)Zg-Uv5GOUP;k#I@hDA-39ig5$w)0u)eQ*tjrVa33UZ7IPA$0GGbsx>J?Pp;;_lhPbtkwwJTx+nhkPLF%OXV Uz|6?V_<@6gU#yY4hy^GB09>av1poj5 literal 0 HcmV?d00001 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildparam.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildparam.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6949845146216f27b4c44f68a7aed97073ad1acf GIT binary patch literal 1219 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 literal 0 HcmV?d00001 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/datathwritetools.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/datathwritetools.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d0353d39bacec0f245967b60989a301185eae55 GIT binary patch literal 24594 zcmeHvYj7J^mR>hr1e!1LDUy0MNl_vt5`5`NNgmOpELsmzQVSMs$>y|xCJ6}ypl*N? zq4f-9Z!(-XKj_+>M6TJ&(8*LqO7@4Q@<&sfRB58Aic`rCVA&E`Sl6zSOr=WsC5`P# z#($FU+(tJ53J~S>Olne-me}aN_uO;OIrq`$o^$T~qP$$-aNYQof4c1g$Ne{YF)v%@ z;fr}Z{D_k{m6LeMc9K6~Q*9zW+fUk0I8+CFcARvoPNX?bx>OhYEm2F@uUmEF*Ll)& zLQsVhrD`eQT}_-?CY9h`F1c~9kjf-a6L*DIEAb?-rwvlMRLY*JrW_p=GRJeAAoq^RNe7>H2ZFOf4Q26MrODx7ESOLx zsN%3Zql|Xg(vCA~c zAP(~toMiLy?APwIv0q1jiJ32QQ_c>Te2^OJjd++bNL*i6gE2@Ma+_A<09q(A$=--& zZ)`d%T2W+;i62oM5NBmIC|?dyNjV0AK_-O5ECm?9Jj<8{F!65UrDQa+2r)tgeq~Lz zm8`{NY6Ail#(d|E=EV!UMk8T{guNJDhkA~2F^&voCSud=Mys3DbXpa6SOtW^IQo@3 zkl#l;Me3xik9PO$>+ahx2#E$I?2iP3;VCg5o9sFu3W63_XO%heYme9!3&tRimPC1r z*k!TNlCZak0yVso(WN@joE`SGgUCv|O|sH%vxG)%3r5n?@W7>>1LE;uY$Sg9k~9~F zd^M%(jC6Y9)Zn>ugO`jUr(KH94XKJ8Q_fFcIu*Q(*O(gVi%nmmejS@;wZ)l!XAE7f`3;Yz7q+9)+hjZ%}>5#Atek~ZUSle7hIRnk`c z+a`%pGv2C;449VeAn-YAxVLIFTQ{fKM#?!ZT;t!aq_=Ij=P<>#U-D`n@4IL7{_xfo(m7u?K$-phG@$|jI{&f4u-L%D8`*x z_#$<-=Ri264n})VQGC06PBu~O&P*JgK9|(x1cxm3WpCd8(ris*-9@PB&fxF)cKD^< zaIMtmvmL_hC8Li?oj#k?FZJ)>q(0>AK@MmRxRA5gc$UEggW4zU+fl52_UBBbHt7KI zZSvFwT;{Ww+w$FzrP=b;Mdf-hTXt-t)vg#PMdUP)g)aheD38{|xwIN>HU7_~Ba}*i zEakO+=ek(G<11OiY2ki)G_UrTNvd%9!58YujwM5)M$a!U(bu!QFo_ytued~qvhe6D z!z7h+bX#*t$4t0$=vQkm=?ybCTvw!Bj++qBo~VZcg*;ZYokzz1T6)uLrB{;t3F_%o zA|F~hnW?L>XkDkq|EsjGa9!qzk!y>VKApqYo^b70qcyT>Ua8DzxVDJI#&UaVVXoLn zKC>=|XMw2*hehf>=d1M9l1wu5+XhL>d8>k~+3c5-R_d!;lXl)mX{=35IA1kNTJ4&_ zT?VN95$Wr%$V$~`mmF+%-dI$gZ~5$9pjGnGJzH|BL$ev*rb({jf_xvJ-XbcUA6kW? zhDggb6rvneIioFQl{zH6ieAUcnc51yPxD7+4DFj$D#cV%#F+l+kEp7mMI+$=skEesDtOFjvYG+datdOAF2;y? z;l|JeB4Ria6JNw;QfL)sYlaMx0b>O*sYYf{^~=bQr~z#be3Q(EB6!2XCZ>R2Bq}Hz zAw@bvenva?XThw>bJBq5n5jtTBxgZG@yjN!1LA0o9zLZ;;!#6-%8h6!qAHLb1ZV2! ztW+>Zq-m!oWVPOr;&T1=9B8s+{K1j?1$DDi#p-;h>tfzZsrQRELzwn5YJ) zreh)+F%Y>PPE;GOEGLuJVOJY4aj5u2aB2H!B#?H}gb<|V$6N7`pRGkF)6QWf9Gp$t z4)&z&y*)i?R~XAuIg~DmMWPY3ZQ4bP+VE6b@XIPKLV|J_E0?)YG!l~4v=9hFu(amY z((Z7?7`q*A;=wPco#zQj+BM8js9T5>=MdpZJBEOQxSB~jMkCr>x+F7YU~z=8l(xkp zi4tQ}MLHZR)C5k2Cd;Y449P5!mv&)gJr$cyR1u&*62~e%7Gb|ALh8EOK{s0CWGeS# zI*g=C14+Mu9+@rE)0zJHgmGCKfhKwNS@N)R!zm$Vor#Kr4qRT2Un_P}W zu8Noi@G=?nPm|3=xq(SM+#QACU{7~g4sf4n4t|sG>xFNNLs3>%t;jm8-LmTU}(c8cQp2;_jtJRB#X z(VWgooB5goDhkSnW+l_uV@kx75k5Y!+{DSiAPR|V8M4r~E$e_GtIYgNrlhN3jIvG< zmJ?(4gSjX`f|@hy$clzOOF1$lv|-T5Bm==f8lwrP$K%(;gj*Cmp2^@1G0lrA8TJx( z7!?vOP(;}t%5J6nY+rtgHIUJlSr>gu289H`@JUj{Hcfa+Mx=NEH)0F@lVwmp1izR% zAKs+~W-~aom~1qc*b-1^WH6&kODCnXa+;#bRzXFKQp+LFFNgf`kfI8Sw==?H(D?Yp zH6>tGz`iJ~JFLY|LSaR&2SXw8vO?wP0|?4sy+gyrghU0H$`U0$C2i{|6Os+BR!J4d z6nRE$X@kv9NK_$#eagBRVu&J9M=(ZOE@VF?x1%=HOBIF`d>1-JIS>$MTNkoLw&e&X3!DkDo zG_4-M`O1pFsr%tJ}6(yLGj8({rb-bjy7G zGdEXVw_4Tk+|Ik3=4)VltKYp^w`;Yo0RUx9^BV!Msdcq!3;rWz!?yWNNNL=<+OTD{ zVJlK9#QDZ&wcJK=wI2VsvHz{B_06mGbbnr1BDBueJ*(!Lwy!pdt0>sm`n<$m)&|T1 z*VwY!(7D>sjQ^C_$`YGeRvVjF8+YQ4#EMqnFJmUdTTRI_QRkbVySTd^mImgJl==7M0 z-CrTC2T7jF#kP+sEpYpWU0-r`=WcLn0`nVA0|W0I<)1h!7Pl`u>sRe1KN$F6;BR^k z{?&m87n5ht{qnt}@4HF)vhMRIm1y#ssw*1onw4?>D~@-}Qq`b`iu4Zr)yRXZ$#c># z!^yYgZ;QeBSg{1eZH`MOm{+2Y8uWAkct{e1hv;DS8wT@|Y5 z+g2T=3pbV>8*d+2y0N^e+sN)+I6L13y2->!^4k0t{-yRiy`S!0-s(-2d3C<~Zyn`p z#lvqn3=*A3p13RWM>K=64>|UtBFIU#$D^`?noG5k3);t(x8td*a@(SoOow6?aq0-E@2Zvb%M~-H~#4 z+}XbD?w+r;Fz?p+P7<4Y+0n2HQS7?4D_P!kuk^v$pPx+ijHJp(blaO&hWB2>{pO!- zN|hhhZAYFsshG2YHSeu~WQF%$HePgNY(?IWhxt>PWJZP%($b*pXFRk7H< z>}pz*Q#0RY5w_#b4p!B!BdN02bpAUgvfKNYrk6K)t&(kb>hD+mtTfeeI8}Z`x4p&? ze9*L7S-a@_$A5DB!qT|D#e1*hzWYJd&r9{5;nm9O#XYzAkM|=}TB===Ki&A_OLq?5 z8^16A?4rJVaJ902F?M_K?Vo z-&E39f@l2F^Y|1w7EXKd)b>({?-&Mmn4cXChf6A>{3XsdZSUo*Hg%2F9$3xHq3gE~gz_W@;`bX#>Fz{5jg~5hN1u!3|7g zGAUVYBvmmp)LSossAdqyAo;?4!c|j{&$_09wHBh=f!0~eEnG(R4vu(`Hs*6a_WeRQ z@_28sc>m^fH@-kOlVqVfzaibNMI^Yzb#pNRGEOx4^k(%Z`e(MW>0`z_9 z$KMyjxV55pP~^f0%-V6(5v|6oW6a}j%pW$1XZ;j8l5LFl*=D&PIYrLuSN8q(Ngm4t zB1nA~w=~~1dY3%rHZRBuruiGDhuqMvJ%^_htgfT#Yw68Q(WZ9t9u7sY;?Z97TDi5L zSlb1JPdO;toPE3Vzf|tM6`Q~I%+8gTEnNF($Ku)Bt$#LttAD9iw{K5Z?)|NXPbT-l zR*}z$X*A8h2?4Z<>HsqGL_or1B51*bB?7GRB2^g%!8{u{95Hy8A5{Z@ylYbx{HRm7 zX@o-*8CU8wr3P`^3bMa|SB#OJY#vW_UAV*lwE3^QF8uZjMqYU(|MY+3QirI>>$rUz z!qgeULZqo-+zQhqf+jUWFj3qRHRuv#f`L5*g97VT>L(3W?;#scP7fOGaHj28S*4w@ zeoZOHdeCtt5)7w33XD9kH^h_%v0B%7d+?Li zkKew1ZK>)L?c?_r+CFN3?%~R+u!JfpTNnhYHYk6jdoIQAoc;91z3rcV|Msz^=1)dG zFWs=%hEk=e>g`KsQ`I}}I7x+1wGTWlJv1*rvFKRZbKCi2_j4y#b{JS)!h-L^cP$;b zL$~jOvWOKAH0g!6Z`b{#>651C)WLsM*>JlKbk*JCKfRf1?oT%E(JS|U;Y8LKoW02j zpb96HO}p#M3eM$OsQd7p#l0YGQ>v!z4xg&&Sa$A$Fc#Zy_kO%PRkn4hDpl5!a3$e-~OQY=etvT z-gs~=wP)l%4<*m|{?iF`<>lt_<;L;k+wUYVzME`(FID+oQl3mzPCjx>eeNz@IQEgS zs4SiR!ehD=d!yivk?5Y=uIl)j~sPRXtj82U_sICwZ!iMDC37x<=axO=B4w? zt`1Ao?Yg~V)#=F-f0u5@(!f4{_SW_fo1dTNxyqVnXLy9ksFmn)dAc}hd`uS~MRzS8 z-Iep@wY8%NU2+I>r(LqKxf4?cGz1L7wU=biYQz_5c3{^z>&Z-kE4(E8Y(AOV*Et$Y zYc7+fe0OaTDjX)XSd7k`z=W}@;ESy_$Df0i zwe~`&RH?asVUFdpys(aJ55XGC>LG>}Sg41T=d_I}_u|mG?&`ulu5x{ zwjva6%fc6d5Z8rhUKb)aEHNv$SL;8mS?sUWe_kOJas7VrE&KeAZ%Fei1UvrTY3}%j zH1Ep77wI_&wfu&2OW{$}nXPH6tHUe*7Snx^Fd(+hHbafOVv$(Uz;4o@Uu7|FB4ZkN zegKdeKw`OK44i-5!6OJnhuB|;MHek0b;4CjAuH=gr5{I_OoSru`+E9%yL<4zUl6{o zdLc4hJpfhW>(^QlX%w9^f>{Uw-rM?e1q-G@TzQQ#;#qvj^Zz<2E3E%YeM23 zl!s$hm1ku*YT+M;9~oYBcq++p45t=C4p{hka25~n)gcT-9E@4+^)6`|-t)mw@T$^< zsC|M^{6RT{ogQEBZ}l9Wj>Vz_-Q9kQUMpFiaL`f$6OeH;-E%np<1j6_Q zA$}4mSpT0PFE~PqA}ZXpEa-vuh&;SYn?w}YOU&>Ocz?4Qni zp-@U34rL?Ki$YU6;h{$01qkUB;p8?biYjUV0U$!+C}9|cJ3Ql$Hp-EY96=K-pvsUD zr66+adJrbQP=vY$+YX@#@j;N$>hWYEdc+~w+uwT>eXnKr{sZESMFjeF!K*Ts5g; zQe>rjMfTGtb}^s17#7{7n zo6#Et%fd@AH)Plp5(>lgQWmdM93kV;iap9OM!{|v3v*}=Fc!j)$Z*DHBnkm#Y=JAW z)l;C3R#T4XV;ju&$Lwk}X%$l5z_6k>5xeHDW8|+L_FDOf49XqJuoVJF6gG zA&OCs_>l}M!#;;$1&i6Nv9T)An1_=niqeiRV8&Qz6$hhHCB){B8FU{6iXd%BMz9V| zv6N&O^%Kac>fzwA{UftsVg+kiF-Zc(C3z$v z&r(_Xig5WB&BCkQ^7V18u}&1m^J*5&b+~(_nsP0gg=wi;pC@L6g9r7MXl}l$d?>UF=4ILOa>5HM{}xM{npL zxxZlPu!Qt24IS$Hm~5D7L;W6}z8;5CYS|}#m(~gO`&1EG8q|5*5+z_uJbk8%83fc@ zlvLeC8amn2vYY>HEkeTMkn(gwGS2ssK-Eu2ZnU0D^X*p z-}$(JXDEY*O0(xaDAca3LalyC1j5wLssDg(wBbYj0d8v)<}y=Zrp8e}0>H*^I7fVzR~2F@s%^*O`Socuaca)`uI#JSvI5d zVN0vIJ-)J~E48KTPT=0~@|J_CvH_hxWaggM`6lyu?Dq5uf^xTd@5Jt%U*0;9Dm$d} zht1rRI^Vz)vJaZ>9a!lfO7#yt82)Vgx-wVOKU)vd$I>mt_6Q<5L%% zRymtwqZiW>otIIFR4Qm$v#Vev>lbEo9a@tGGY>&Zr9UZhwlcAc}H%oO;{3wUQOpE=2W&1FjE z1#O`a6@m#Zl257-MDB45SHV}={}X)W`kU9~s|e>6&?MlaUVG6|A*Q~$M#kAb@S~hQ za176dX~^*)7lFw485e4wnsr++*XMh}YQf>6ROS183)NY_Zk;)CrA0VvSQkg*x)8Y@ z;KCB#w0;{hU3c>8Vrwpp&D}hyhUW0@7XPcqup#dtga7Q zW5w{;7lP06(-x^S-!oeX$L?&MMR2S?5^}tVa_)4;m4e4`m@>QKjF`Ns%=eOZjaDFwmQ z0j-;SMRYiuHj%T(a&6E6EqA~9f|`|jh429bE_+7C+A}jUhkFcVj+4uP1D^JV(p$kJ zHfYl}?V~pi_@kpB*k!Fw>FtmGpbNNFj7_#LEaG!I18won2pj%H@~WZFz$f;tq8Jh$ zI@w@gPk-M&V|xPa0!Y-h4^1ont44)hcGiNo!wAX8xe;MyjY&ZLM<}#*^}abI!y6d0 z4ok^&Y;6L&#D(mV-gNMvGN7-;v3nlA%OExjzv$+l%@~j9Tm|_3!?g1|09QKs+C+3q zKQ@g+<)nZCIv0V-DM0X8YMV+ zmY^;x8gp~+jN^D8lNjc2rQr+rA4&}xrC=h-2!P@@Wb*7`%R0Gc;dIR846*i{7%@(P z^as1h)r{KU4jcsw8Ih1rR1vR}Bbpta$@cMEo?4R%It)@~2TH_b>l{ynih|EL@II4yD zV>1lGEsH%NA(VpSmZ~qv_+>axuY>0b4^Dc7Wl6a~eoc0|z$Nf}DK>p29=>{0d_Omd zcAL;)5^4TsqLSv2t}YQ0i+M4bB+A86@sM~5K^W|{Ogx6y!H|*Z5NCi%V4(-74;7cu zvq2i(8VeE0dTnAT+bZTEoQy4OP0}C+Bc6f|)+r`xoLidM1U7Mo#j*Se-xwG1w~gMz zJi*jaERkh;2fE_gf+C9x$ad1q@Og3c2#HS6pY1R-)>tHng3tlu428UrM0=S~puk8n zLK`Tkg+dQ-%z}zD77$E>Ap(lcZe#RfjAQBp#$lxy(aM)2h+TStku^QtI2|b)m?I=Q z^5}nQhd%<)Vy!@f>7^YW?s$)f^*x-f!_Kn0i7sQN#ilhJF?%CKX*dBR(?=<-K++6B z^#Lk4c>_J!D0#_5n^P9}`g`8Lq~P?XOOrt%(UVsuRH#VkX5XHi61{mPW(t*9j7>wvRB+^`kl2lVM3)pc@MfYnGo$Z)(O_UEdP$jy#^yvusE}v_u;=C_V(Vgt zy_t8#OPZD`cWGABAb=9WNnC-(eB|ahZqtfY(MeU%yh6wG-~bCY18LKkxG}AuArT2h z-V=p)Sc9iCX zPMoBoC+KDcQKVhLFgty?1SGNtM@WwO(@qKy!)Z`*DCXD5IYcv9<}%_fjALUh#XyBs zh5HX=Kpux(Z=U9$Bp*OjyFD3NN?^!LaU%d9i*OHt2 zQ>Fd$dsjWRi)Vkh_11PeabY`l^W%60da_*N6y}k2fLnIwZx)pCf5&7^p7*YM?vA|;jJ^5~UR*;Snn zSpY|MJ{xN^y2kyne0C3pMwX7kz>HG@y+tU6jPo@cJO4yXE0F!hX% zW?rk)B@+{Yh<{=tElf;I#$$0+nV3+?0g|r6Vc1^U8?4HqiOGm@;<;u7o7u5QOxq$j zb&s?k=0r=oqI0w|%+9&&aBOx=58FY?;>?)qj7@*WCfQ2VWK5Cn!!wZpj>LLR{bxuc z*NQfT8%~Vj`RCQ;yyGh`$2Wf^aQvRXAFTmO!0`L(N_cmI0NWgG6NoP#{?{_=$F UJ^C58_wnwpLcEF>7KHPE0136CaR2}S literal 0 HcmV?d00001 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/tro2th.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/tro2th.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35eae6bd67618986906995429bb5afc202ed03d0 GIT binary patch literal 21327 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 literal 0 HcmV?d00001 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/vtopotools.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/vtopotools.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef1a773a1af4895ffd582a46255238215a07bf43 GIT binary patch literal 8400 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 NXxmYN^R4uA{x{KHLcIV0 literal 0 HcmV?d00001 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/_version.py b/Scripts/pyCreateTh/Lib/pytro2th/_version.py new file mode 100644 index 0000000..8d3d05e --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/_version.py @@ -0,0 +1,4 @@ +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later + +__version__ = "1.3.0" diff --git a/Scripts/pyCreateTh/Lib/pytro2th/bin/tro2therion b/Scripts/pyCreateTh/Lib/pytro2th/bin/tro2therion new file mode 100644 index 0000000..d025f95 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/bin/tro2therion @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +import ..... +print tro2therion() \ No newline at end of file diff --git a/Scripts/pyCreateTh/Lib/pytro2th/buildparam.py b/Scripts/pyCreateTh/Lib/pytro2th/buildparam.py new file mode 100644 index 0000000..1db0668 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/buildparam.py @@ -0,0 +1,95 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later + + +""" +Script to build Therion files +By Xavier Robert +Lima, 2016.06.21 + +USAGE : + 1- Run in the terminal: $ python buildthconfig.py + + +INPUTS: +The inputs are in the script file, in the "# Define data to analysis" section. +The different arguments are described. + +""" + +###### To DO : ####### +# - +###### End To DO ####### + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer + +# Import modules +import sys +import os +import copy + +######################## + +def builddictcave(): + """ + + """ + + ######################## + # Define parameters + + # thlang: language to set in the files, can be english [en] or french [fr] + thlang = 'fr' + # thcfile: set to True to build a config file, or False if not + thcfile = True + # thcfnme: name of the thc file + thcfnme = 'config.thc' + # thcpath: path where to add the config file. + # if None, it will be in the folder from where is run the code + thcpath = None + # thconfigfile: set to True to build a thconfig file, or False if not + thconfigfile = True + # thconfigpath: path where to add the thconfig file. + # if None, it will be in the folder from where is run the code + thconfigpath = None + # thconfigfnme: name of the thconfig file + thconfigfnme= 'Test.thconfig' + #icomments: True if we add comments inside the thconfig file, + # False if there is no comments inside the thconfig file + icomments = True + #icoupe: True if we want a layout for extended projection in the thconfig + # False if not + icoupe = True + + # Errfiles: True to write on previous files; be careful in that case !! + # False if not + Errfiles = True + + + # sourcefiles: source files + sourcefile = ['example.th', 'example.th2', 'example-coupe.th2'] + # xviscale: scale of the xvi file + # 1000 corresponds to 1/1000 + xviscale = 1000 + # xvigrid: spacing of the grid for the xvi, in meters + xvigrid = 10 + # cavefnme: cave fnme + cavefnme = 'Example' + # coord: coordinate system + # Can be set to None + coord = None + # scale: scale of the map + # 500 corresponds to 1/500 + scale = 500 + + + data = [thlang, thcfile, thcfnme, thcpath, + thconfigfile, thconfigpath, thconfigfnme, + icomments, icoupe, Errfiles] + dictcave = [sourcefile, xviscale, xvigrid, cavefnme, coord, scale] + + return dictcave, data diff --git a/Scripts/pyCreateTh/Lib/pytro2th/buildthconfig.py b/Scripts/pyCreateTh/Lib/pytro2th/buildthconfig.py new file mode 100644 index 0000000..7a17c0a --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/buildthconfig.py @@ -0,0 +1,1186 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- +# coding: utf8 + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later + + +""" + Script to build Therion files + By Xavier Robert + Lima, 2016.06.21 + + USAGE : + - function called by other programs + + + INPUTS: + The inputs are in the script file, in the "# Define data to analysis" section. + The different arguments are described. + +""" + +###### To DO : ####### +# - Add a maps.th file +# - Add a cave-tot.th file +# - Update cave output structure +# - +###### End To DO ####### + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer +#from __future__ import unicode_literals + +# Import modules +import sys, os, datetime + +######################## + +def builddictcave(thlang = u'en', icomments = True, icoupe = True, Errfiles = True, + thcfile = True, thcfnme = u'config.thc', thcpath = None, + thconfigfile = True, thconfigpath = None, thconfigfnme= u'Test.thconfig'): + """ + + """ + + ######################## + # Define parameters + # thlang: language to set in the files, can be english [en] or french [fr] + #thlang = 'fr' + # thcfile: set to True to build a config file, or False if not + #thcfile = True + # thcfnme: name of the thc file + #thcfnme = 'config.thc' + # thcpath: path where to add the config file. + # if None, it will be in the folder from where is run the code + #thcpath = None + # thconfigfile: set to True to build a thconfig file, or False if not + #thconfigfile = True + # thconfigpath: path where to add the thconfig file. + # if None, it will be in the folder from where is run the code + #thconfigpath = None + # thconfigfnme: name of the thconfig file + #thconfigfnme= 'Test.thconfig' + #icomments: True if we add comments inside the thconfig file, + # False if there is no comments inside the thconfig file + #icomments = True + #icoupe: True if we want a layout for extended projection in the thconfig + # False if not + #icoupe = True + + # Errfiles: True to write on previous files; be careful in that case !! + # False if not + #Errfiles = True + + + # sourcefiles: source files + sourcefile = [u'cave.th', u'cave.th2', u'cave-coupe.th2'] + # xviscale: scale of the xvi file + # 1000 corresponds to 1/1000 + xviscale = 1000 + # xvigrid: spacing of the grid for the xvi, in meters + xvigrid = 10 + # cavefnme: cave fnme + cavefnme = u'cave' + # coord: coordinate system + # Can be set to None + coord = None + # scale: scale of the map + # 500 corresponds to 1/500 + scale = 500 + + + datac = [thlang, thcfile, thcfnme, thcpath, + thconfigfile, thconfigpath, thconfigfnme, + icomments, icoupe, Errfiles] + dictcave = [sourcefile, xviscale, xvigrid, cavefnme, coord, scale] + + return dictcave, datac + + +def writethconfig(pdata, icomments, icoupe, thlang, dictcave, + thcfile, pdata2 = None): + """ + Function to write a .thconfig file for a cave + + INPUTS: + pdata : path and name of the .thconfig file + icomments : True if comments in the file + False if no comments in the file + icoupe : True for a layout to print an extended elevation map + False if not + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + dictcave : list with [sourcefile, xviscale, xvigrid, cavefnme, coord, scale] + thcfile : set to True to build a config file, + or False if not + pdata2 : path and name of the config file + + OUTPUTS: + thconfig file + + USAGE: + writethconfig(pdata, icomments, icoupe, thlang, dictcave, thcfile, [pdata2]): + + """ + + f2w = open(pdata, 'w') + + f2w.write(u'encoding utf-8 \n\n') + f2w.write(u'# File written by pytro2th (Xavier Robert) \n') + f2w.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + f2w.write(u'# This work is under the licence Creatice Commonc CC-by-nc-sa v.4 \n\n') + + + if icomments: + f2w.write(u'# 1-SOURCES \n') + if thlang == u'fr': + f2w.write(u'# La ligne source specifie le fichier où sont les données topo \n') + f2w.write(u'# (Au fichier "nomcavite.th" il faudra avoir une ligne \n') + f2w.write(u'# "input "nomcavite.th2" pour spécifier le fichier où se trouvent \n') + f2w.write(u'# les données du dessin, comme ça, ce fichier thconfig appelera \n') + f2w.write(u'# nomcavite.th" et a son tour, "nomcavite.th" appelera \n') + f2w.write(u'# "nomcavite.th2") \n') + elif thlang == u'en': + f2w.write(u'# Source\'s line specify the files with the surveyed data \n') + f2w.write(u'# (With the file "mycave.th" we need to add a line \n') + f2w.write(u'# "input "nomcavite.th2" to specify the file with the drawing data\n') + f2w.write(u'# This file thconfig will call "mycave.th" and then, "mycave.th"\n' ) + f2w.write(u'# will call mycave.th2") \n') + + # Do a loop on the input files + # To move in the cave-tot.th and only call that last file? + #for cfile in dictcave[0]: + # f2w.write(u'source ' + cfile + u'\n') + #file.write(u'input Data/%s.th\n\n' %(cavename.replace(u' ', u'_'))) + f2w.write(u'input %s-tot.th\n\n' %(dictcave[0][0][-3:])) # Maybe to change for cavename + f2w.write(u'\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Appeller le fichier de définition des maps\n') + elif thlang == u'en': f2w.write(u'# Call maps definition file\n') + f2w.write(u'input %s-maps.th\n\n' %(dictcave[0][0][-3:])) # Maybe to change for cavename + f2w.write(u'\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Appeller le fichier de coordonnées de la cavité\n') + elif thlang == u'en': f2w.write(u'# Call Coordinates definition file\n') + f2w.write(u'#input legends/entrances_coordinates.th\n\n') + + + if icomments: + if thlang == u'fr': + f2w.write(u'# Ajoute un fichier de configuration\n') + f2w.write(u'# Voir https://github.com/robertxa/Th-Config-Xav pour un exemple\n') + elif thlang == u'en': + f2w.write(u'# Add config file \n') + f2w.write(u'# See https://github.com/robertxa/Th-Config-Xav for an example\n') + if thcfile: + f2w.write(u'input ' + pdata2 + u' \n\n\n') + else: + f2w.write(u'#input config.thc \n\n\n') + + + if icomments: f2w.write(u'# 2-LAYOUT \n') + if icomments: + if thlang == u'fr': f2w.write(u'# Debut de la définition du Layout "xviexport" \n') + elif thlang == u'en': f2w.write(u'# Begin the definition of the Layout "xviexport" \n') + f2w.write(u'layout xviexport \n') + if icomments: + if thlang == u'fr': f2w.write(u'\t# Echelle a laquelle on veut dessiner la topo \n') + elif thlang == u'en': f2w.write(u'\t# Scale to draw the survey \n') + f2w.write(u'\tscale 1 ' + str(dictcave[1]) + u' \n') + if icomments: + if thlang == u'fr': f2w.write(u'\t# Taille de la grille \n') + elif thlang == u'en': f2w.write(u'\t# Size of the grid \n') + f2w.write(u'\tgrid-size ' + str(dictcave[2]) + u' ' + str(dictcave[2]) + u' ' + str(dictcave[2]) + u' m \n') + if icomments: + if thlang == u'fr': f2w.write(u'\t# Mettre la grille en arrière plan \n') + elif thlang == u'en': f2w.write(u'\t# Set the grid to the background \n') + f2w.write(u'\tgrid bottom \n') + f2w.write(u'endlayout \n') + if icomments: + if thlang == u'fr': f2w.write(u'# Fin de la définition du layout "xviexport" \n') + elif thlang == u'en': f2w.write(u'# End of the definition of the layout "xviexport" \n') + f2w.write(u'\n\n') + + writelayout(f2w, dictcave, icomments, thlang) + if icoupe: + f2w.write(u'\n\n') + writelayout(f2w, dictcave, icomments, thlang, icoupe) + + f2w.write(u'\n\n') + f2w.write(u'# 3-EXPORTS \n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export des xvi pour le dessin \n') + elif thlang == u'en': f2w.write(u'# xvi exports for drawing purpose \n') + f2w.write(u'export map -fmt xvi -layout xviexport -o '+ dictcave[3] + u'-map.xvi\n') + if icoupe: f2w.write(u'export map -projection extended -fmt xvi -layout xviexport -o '+ dictcave[3] + u'-coupe.xvi\n\n') + + # select maps + if icomments: + if thlang == u'fr': f2w.write(u'# Séléction des maps à exporter \n') + elif thlang == u'en': f2w.write(u'# Select maps to export \n') + f2w.write(u'select MP-'+ dictcave[3] + u'#@' + dictcave[3] +' \n') + if icoupe: f2w.write(u'select MC-'+ dictcave[3] + u'#@' + dictcave[3] +' \n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export des pdfs \n') + elif thlang == u'en': f2w.write(u'# Pdfs export \n') + if icoupe: f2w.write(u'export map -projection extended -layout my_layout-coupe -o '+ dictcave[3] + u'-coupe.pdf\n') + f2w.write(u'export map -o Outputs/' + dictcave[3] + u'-plan.pdf -layout my_layout\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export du modèle 3D \n') + elif thlang == u'en': f2w.write(u'# 3D export \n') + f2w.write(u'export model -o Outputs/' + dictcave[3] + u'.lox\n\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export des fichier ESRI \n') + elif thlang == u'en': f2w.write(u"# ESRI's files export \n") + f2w.write(u'export map -proj plan -fmt esri -o Outputs/' + dictcave[3] + u' -layout my_layout\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export du fichier kml \n') + elif thlang == u'en': f2w.write(u'# kml export \n') + f2w.write(u'export map -proj plan -fmt kml -o Outputs/' + dictcave[3] + u'.kml -layout my_layout\n\n') + + if icomments: + if thlang == u'fr': f2w.write(u'# Export des listes \n') + elif thlang == u'en': f2w.write(u'# Lists export \n') + f2w.write(u'export continuation-list -o Outputs/Continuations' + dictcave[3] + '.html \n') + f2w.write(u'export survey-list -location on -o Outputs/Surveys' + dictcave[3] + '.html \n') + f2w.write(u'export cave-list -location on -o Outputs/Caves2020' + dictcave[3] + '.html \n') + + + f2w.closed + + print(u'\tFile ' + pdata + u' written...') + + return + + +def writelayout(fw, dictcave, icomments, thlang, icoupe = None): + """ + Function to write a layout in a .thconfig file + + INPUTS: + fw: variable that define the file to write in + dictcave : list [sourcefile, xviscale, xvigrid, cavefnme, coord, scale] + icomments : True if comments in the file + False if no comments in the file + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + icoupe : True to tell there is an elevation map + if None no layout for extended elevation map + OUTPUTS: + None + USAGE: + writelayout(fw, dictcave, icomments, thlang, [icoupe]) + + Author: Xavier Robert, Lima 2016/06/27 + + """ + + if not icoupe: + fw.write(u'layout my_layout\n\n') + else: + fw.write(u'layout my_layout-coupe\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Appelle le(s) fichier(s) de configuration (Layout config dans le fichier config.thc file)\n') + elif thlang == u'en': + fw.write(u'\n\t# Call the config settings (Layout config inside the config.thc file)\n') + fw.write(u'\tcopy drawingconfig \n') + fw.write(u'\t#copy Coords_Header_%s\n' %(dictcave[3])) + fw.write(u'\tcopy drawingconfig\n') + if not icoupe: fw.write(u'\tcopy headerl\n') + else: fw.write(u'\tcopy header_coupe \n') + fw.write(u'\tcopy langue-fr\n\n') + + if icomments: + if thlang == u'fr': fw.write(u'\n\t# Titre du pdf \n') + elif thlang == u'en': fw.write(u'\n\t# pdf Title \n') + fw.write(u'\tdoc-title "' + str(dictcave[3]) + '"\n') + if icomments: + if thlang == u'fr': fw.write(u'\n\t# Auteur du pdf \n') + elif thlang == u'en': fw.write(u'\n\t# pdf Author \n') + fw.write(u'\tdoc-author "Xavier Robert"\n\n') + + if not icoupe: + # print this lines for cs systems only for the plan view, not for the extended elevation view + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Pour faire la topo dans le système UTM \n') + fw.write(u'\t# Décommenter la ligne, et remplacer xx par la zone UTM\n') + elif thlang == u'en': + fw.write(u'\n\t# To draw the map survey in the UTM system \n') + fw.write(u'\t# Uncomment the line, and remplace xx by the UTM zone used\n') + if dictcave[4] == None: + fw.write(u'\t#cs UTMxx\n\n') + else: + fw.write(u'\tcs ' + dictcave[4] + ' \n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# "base-scale" specifie l\'échelle à laquelle nous avons\n') + fw.write(u'\t# dessiné nos croquis. Par defaut, c\'est 1/200.\n') + fw.write(u'\t# Si on a utilise une autre échelle, \n') + fw.write(u'\t# il faut enlever le "#" et spécifier l échelle vraiment\n') + fw.write(u'\t# employée, c\'est le cas apres avoir dessiné la topo\n') + fw.write(u'\t# sur un cheminement exporté avec le layout "xviexport"\n') + fw.write(u'\t# (voir en bas)\n') + elif thlang == u'en': + fw.write(u'\n\t# "base-scale" is the scale we use to draw the survey\n') + fw.write(u'\t# (see xviexport layout). Defaut is 1/200.\n') + fw.write(u'\t# If we use an other scale,, we have to uncomment this \n') + fw.write(u'\t# line and specify the drwing scale\n') + fw.write(u'\tbase-scale 1 ' + str(dictcave[1]) + '\n\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# "scale" : specification de l\'échelle,\n') + fw.write(u'\t# pour imprimer la topo. La combination entre scale et base-scale\n') + fw.write(u'\t# controlle le gros des lignes, rotation, etc, convenable\n') + fw.write(u'\t# pour faire l\'amplification-reduction entre dessin(s) et\n') + fw.write(u'\t# le resultat de l imprimante\n') + fw.write(u'\t# C\'est tres important de s\'assurer que la configuration de\n') + fw.write(u'\t# l\'imprimante ne spécifie pas l\'option "Fit in page"\n') + fw.write(u'\t# ou similaire, sinon, l\'échelle sera changée pendant\n') + fw.write(u'\t# l\'impression\n') + elif thlang == u'en': + fw.write(u'\n\t# "scale" : Scale we want for the final output \n') + fw.write(u'\t# to print the topography') + fw.write(u'\t# Be careful with the printer configuration\n') + fw.write(u'\t# The option "Fit in page" or similar\n') + fw.write(u'\t# will change the scale of the printed topography\n') + fw.write(u'\t#scale 1 1000\n') + fw.write(u'\tscale 1 ' + str(dictcave[5]) + u'\n\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Echelle graphique de %s m d\'ampleur\n' %(str(dictcave[5]/10))) + elif thlang == u'en': + fw.write(u'\n\t# Length of the scale bar (Here, %s m)\n' %(str(dictcave[5]/10))) + fw.write(u'\tscale-bar %s m\n\n' %(str(dictcave[5]/10))) + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Pour faire une rotation\n') + elif thlang == u'en': + fw.write(u'\n\t# To rotate the map\n') + fw.write(u'\t#rotate 2.25\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Une couleur de fond, 85% blanc = 15% noir\n') + elif thlang == u'en': + fw.write(u'\n\t# Background color, 85% white = 15% black\n') + fw.write(u'\t#color map-bg 85\n\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Une couleur de topo (RVB entre 0 et 100)\n') + elif thlang == u'en': + fw.write(u'\n\t# Map color (RVB between 0-100)\n') + fw.write(u'\tcolor map-fg [100 100 80]\n\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# la topo est transparente (on peut voir les galeries sousjacentes)\n') + fw.write(u'\t# Par défaut, donc, pas vraiment besoin de specifier\n') + elif thlang == u'en': + fw.write(u'\n\t# To impose transparency for the topography\n' ) + fw.write(u'\t(# We can thus see the lower tunnels)\n') + fw.write(u'\t# Option on by default, so not necessary\n') + fw.write(u'\ttransparency on\n\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Pourcentage de transparence, marche seulement si transparency est "on"\n') + elif thlang == u'en': + fw.write(u'\n\t# Pourcentage of transparency, only if transparency is "on"\n') + fw.write(u'\topacity 75\n\n') + + if thlang == u'fr': + if icomments: + if thlang == u'fr': fw.write(u'\n\t# Un commentaire à ajouter au titule,\n') + elif thlang == u'en': fw.write(u'\n\t# A comment to add to the header,\n') + if not icoupe: + if thlang == u'fr': fw.write(u'\tmap-comment "Plan - Samoëns, 74, France"\n\n') + elif thlang == u'en': fw.write(u'\tmap-comment "Map - Samoëns, 74, France"\n\n') + else: + if thlang == u'fr': fw.write(u'\tmap-comment "Coupe développée - Samoëns, 74, France"\n\n') + if thlang == u'en': fw.write(u'\tmap-comment "Extended elevation - Samoëns, 74, France"\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Afficher les statistiques d\'explo par équipe/nom. C\'est lourd\n') + fw.write(u'\t# si la cavite est importante et qu\'il y a beaucoup d\'explorateurs\n') + elif thlang == u'en': + fw.write(u'\n\t# Print exploration stats (team/name). it is heavy\n') + fw.write(u'\t# if the cave is long with lots of explorers\n') + fw.write(u'\tstatistics explo-length off\n\n') + + if icomments: + if thlang == 'fr': + fw.write('\n\t# Afficher le développement et profondeur de la cavité\n') + elif thlang == 'en': + fw.write('\n\t# Print length and depth\n') + fw.write('\tstatistics topo-length off\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Afficher un copyright\n') + elif thlang == u'en': + fw.write(u'\n\t# print a copyright\n') + fw.write(u'\tstatistics copyright all\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Nous voulons une légende pour expliquer les symboles.\n') + fw.write(u'\n\t#\t"on" imprimera seulement la légende des symboles dessinés sur la topo\n') + fw.write(u'\n\t#\tSi l\'on veut pour tous les symboles, utilisés ou pas, il faut indiquer "all".\n') + fw.write(u'\t# "legend off" = pas de légende\n') + elif thlang == u'en': + fw.write(u'\n\t# Print a Legend for the symbols we use\n') + fw.write(u'\t# It is posible to print only the symbols we use (here),\n') + fw.write(u'\t# or all of them, used or not with "legend all".\n') + fw.write(u'\t# "legend off" = no legende\n') + fw.write(u'\tlegend off\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Par defaut, la légende est de 14 cm de largeur\n') + elif thlang == u'en': + fw.write(u'\n\t# Default width legend is 14 cm\n') + fw.write(u'\t#legend-width 14 cm\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Spécification de la position de la manchette : interieur\n') + fw.write(u'\t# occuppée par le titule, auteurs, etc. Nous pouvons indiquer\n') + fw.write(u'\t# les cordonnées du point de la topo ou l\'on veut la manchette :\n') + fw.write(u'\t# 0 0, c\'est en bas, à gauche\n') + fw.write(u'\t# 100 100, c\'est en haut, à droite\n') + fw.write(u'\t# La manchette a des "points cardinaux" : n, s, ne, sw, etc.\n') + fw.write(u'\t# Il faut spécifier un de ces points \n') + elif thlang == u'en': + fw.write(u'\n\t# Position of the Header (title, authors,...) \n') + fw.write(u'\t# We indicate the coordinates of the point where we want it \n') + fw.write(u'\t# 0 0, is bottom left \n') + fw.write(u'\t# 100 100, is top right \n') + fw.write(u'\t# The header has cardinal points: n, s, ne, sw, etc. \n') + fw.write(u'\t# We have to specify one of these points \n') + fw.write(u'\tmap-header 0 30 nw\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Arrière plan de la manchette\n') + elif thlang == u'en': + fw.write(u'\n\t# header\'s background\n') + fw.write(u'\tmap-header-bg off\n') + fw.write(u'\n\tlayers on\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Options pour afficher le squelette topo,\n') + fw.write(u'\t# les points et le nom des stations topos\n') + elif thlang == u'en': + fw.write(u'\n\t# Options to print the legs of the survey,\n') + fw.write(u'\t# stations points and stations names\n') + fw.write(u'\tsymbol-hide line survey\n') + fw.write(u'\t#debug station-names\n') + fw.write(u'\tdebug off\n\n') + + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Spécifier le pas de la grille, ici 100x100x100 metres\n') + fw.write(u'\t# (Trois dimensions, oui, ça sert pour la coupe aussi) \n') + elif thlang == u'en': + fw.write(u'\n\t# Step of the grid in 3-D \n') + fw.write(u'\t#grid-size 100 100 100 m\n') + if icomments: + if thlang == u'fr': + fw.write(u'\n\t# Spécifier qu\'il faut imprimer une grille\n') + fw.write(u'\t# au dessous de la topo \n') + elif thlang == u'en': + fw.write (u'\n\t# If we want a grid in background \n') + fw.write(u'\t#grid bottom\n\n') + fw.write(u'\tgrid off\n\n') + + #fw.write(u'\n\t# Titre \n') + #fw.write(u'\tcode tex-map\n') + #if icomments: + # if thlang == u'en': + # fw.write(u'\t\t% Output map title as determined by Therion is stored in \\cavename. \n') + # fw.write(u'\t\t% It will be empty if there are multiple maps selected for any one projection\n') + # fw.write(u'\t\t% AND there are multiple source surveys identified in the thconfig file \n') + # fw.write(u'\t\t% i.e. Therion can not infer a unique title from the input data given.\n') + # fw.write(u'\t\t% This code allows you to define an output map title {cavename} if it happens to be empty\n') + # elif thlang == u'fr': + # fw.write(u'\t\t% Le titre de la carte determiné par Therion est enregistré dans la variable \\cavename. \n') + # fw.write(u'\t\t% Elle est vide lorsque plusieurs maps sont sélectionnées\n') + # fw.write(u'\t\t% et s\'il y a différentes données topograhiques dans le thconfig \n') + # fw.write(u'\t\t% i.e. Therion ne peut donner un titre unique à partir des inputs.\n') + # fw.write(u'\t\t% Ce code permet alors de définir un titre {cavename} dans le cas où il est vide\n') + #fw.write(u'\t\t\edef\temp{\\the\cavename} ') + #if thlang == u'fr': fw.write(u'% cavename pour Therion\n') + #elif thlang == u'en': fw.write(u'% cavename from Therion\n') + #fw.write(u'\t\t\edef\\nostring{} ') + #if thlang == u'fr': fw.write(u' % string vide\n') + #elif thlang == u'en': fw.write(u' % empty string\n') + #fw.write(u'\t\t\ifx\\temp\\nostring ') + #if thlang == u'fr': fw.write(u' % test si cavename est vide\n') + #elif thlang == u'en': fw.write(u' % test if cavename is empty\n') + #if thlang == u'fr': fw.write(u'\t\t\t% s\'il est vide, réassigne cavename pour décrire les maps sélectionnées comme un groupe\n') + #elif thlang == u'en': fw.write(u'\t\t\t% if empty reassign cavename to describe selected maps as a group\n') + #fw.write(u'\t\t\t\cavename={' + dictcave[3] + u'} \n') + #fw.write(u'\t\t\else ') + #if thlang == u'fr': fw.write(u'% Si non, alors garde la valeur de Therion, ou assigne un cavename ici pour l\'écraser\n') + #elif thlang == u'en': fw.write(u'% if not empty keep the value set by therion, or assign an override cavename here\n') + #fw.write(u'\t\t\\fi\n') + #fw.write(u'\tendcode \n\n') + fw.write(u'endlayout\n') + + return + + +def writethc(pdata, cavename = None, istructure = True): + """ + Function to write the config.thc file + + INPUTS: + pdata : path + name of the config.thc file + + OUTPUTS: + new contig.thc file + + USAGE: + writethc(pdata) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + # Open the file + + if istructure: f1w = open(cavename.replace(u' ', u'_') + '/' + pdata,'w') + else: f1w = open(pdata,'w') + + f1w.write(u'encoding utf-8 \n\n') + f1w.write(u'# File to set up specific settings for Therion drawing outputs \n') + f1w.write(u'# In your *.thconfig file, you need to call this file with: \n') + f1w.write(u'# input config.thc \n') + f1w.write(u'# and then, in each layout, you need to call the corresponding layout: \n') + f1w.write(u'# copy drawingconfig \n\n\n') + f1w.write(u'# change the name for the legend\n') + f1w.write(u'text en "line u:rope" "rope" #text to appear in legend\n') + f1w.write(u'text fr "line u:rope" "corde" #text to appear in legend \n') + f1w.write(u'text en "line u:fault" "fault" #text to appear in legend\n') + f1w.write(u'text fr "line u:fault" "faille" #text to appear in legend \n') + f1w.write(u'text en "line u:strata" "strata" #text to appear in legend\n') + f1w.write(u'text fr "line u:strata" "strate" #text to appear in legend \n\n') + f1w.write(u'layout drawingconfig\n') + f1w.write(u'# Layout to draw the map and extended view.\n\n') + f1w.write(u'\t# Set the language\n') + f1w.write(u'\tlanguage fr\n') + f1w.write(u'\t# Auteur \n') + f1w.write(u'\tdoc-author "Xavier Robert"\n') + f1w.write(u'\t# Set the symology you want to use: UIS, ASF (Australie) CCNP (Etats Units) ou\n') + f1w.write(u'\t# SKB (tchecoslovakia) \n') + f1w.write(u'\t#symbol-set UIS\n') + f1w.write(u'\t# Change the type or colors of symbols:\n') + f1w.write(u'\tsymbol-assign point station:temporary SKBB\n') + f1w.write(u'\tsymbol-color point water-flow [0 0 100]\n') + f1w.write(u'\tsymbol-color line water-flow [0 0 100]\n') + f1w.write(u'\tsymbol-color point ice [0 0 100]\n') + f1w.write(u'\tsymbol-color line wall:ice [0 0 100]\n') + f1w.write(u'\tsymbol-color point ice-pillar [0 0 100]\n') + f1w.write(u'\tsymbol-color area ice [0 0 100]\n') + f1w.write(u'\tsymbol-color point snow [0 0 100]\n') + f1w.write(u'\tsymbol-color point spring [0 0 100]\n') + f1w.write(u'\tsymbol-color point root [0 100 0]\n') + f1w.write(u'\tsymbol-color point vegetable-debris [0 100 0]\n') + f1w.write(u'\tsymbol-color point altitude [100 50 0]\n\n') + f1w.write(u'\tcode metapost\n\n') + f1w.write(u'\t\t# to change blocs size\n') + f1w.write(u'\t\tdef a_blocks (expr p) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpickup PenC;\n') + f1w.write(u'\t\t\tpath q, qq; q = bbox p;\n') + f1w.write(u'\t\t\tpicture tmp_pic; \n') + f1w.write(u'\t\t\tuu := max(u, (xpart urcorner q - xpart llcorner q)/100, (ypart urcorner q - ypart llcorner q)/100);\n') + f1w.write(u'\t\t\ttmp_pic := image(\n') + f1w.write(u'\t\t\tfor i = xpart llcorner q step 1.0uu until xpart urcorner q:\n') + f1w.write(u'\t\t\t\tfor j = ypart llcorner q step 1.0uu until ypart urcorner q:\n') + f1w.write(u'\t\t\t\t\tqq := punked (((-.3uu,-.3uu)--(.3uu,-.3uu)--(.3uu,.3uu)--(-.3uu,.3uu)--cycle) \n') + f1w.write(u'\t\t\t\t\trandomized (uu/2))\n') + f1w.write(u'\t\t\t\t\t\trotated uniformdeviate(360)\n') + f1w.write(u'\t\t\t\t\t\tshifted ((i,j) randomized 1.0uu);\n') + f1w.write(u'\t\t\t\t\tif xpart (p intersectiontimes qq) < 0:\n') + f1w.write(u'\t\t\t\t\t\tthclean qq;\n') + f1w.write(u'\t\t\t\t\t\tthdraw qq;\n') + f1w.write(u'\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\tendfor; \n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t);\n') + f1w.write(u'\t\t\tclip tmp_pic to p;\n') + f1w.write(u'\t\t\tdraw tmp_pic;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# To change sand aspects\n') + f1w.write(u'\t\tdef a_sands (expr p) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpickup PenC;\n') + f1w.write(u'\t\t\tpath q; q = bbox p;\n') + f1w.write(u'\t\t\tpicture tmp_pic;\n') + f1w.write(u'\t\t\ttmp_pic := image(\n') + f1w.write(u'\t\t\tfor i = xpart llcorner q step 0.1u until xpart urcorner q:\n') + f1w.write(u'\t\t\t\tfor j = ypart llcorner q step 0.1u until ypart urcorner q:\n') + f1w.write(u'\t\t\t\t\tdraw origin shifted ((i,j) randomized 0.1u) withpen PenC;\n') + f1w.write(u'\t\t\t\tendfor;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t);\n') + f1w.write(u'\t\t\t#clip tmp_pic to p;\n') + f1w.write(u'\t\t\tdraw tmp_pic;\n') + f1w.write(u'\t\tenddef;\n\n\n\n') + f1w.write(u'\t\t####### Metapost-changes ############\n\n\n') + f1w.write(u'\t\t# To change pebbles aspects\n') + f1w.write(u'\t\tdef a_pebbles_SKBB (expr p) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpickup PenC;\n') + f1w.write(u'\t\t\tpath q, qq; q = bbox p;\n') + f1w.write(u'\t\t\tpicture tmp_pic; \n') + f1w.write(u'\t\t\ttmp_pic := image(\n') + f1w.write(u'\t\t\tfor i = xpart llcorner q step .1u until xpart urcorner q:\n') + f1w.write(u'\t\t\t\tfor j = ypart llcorner q step .5u until ypart urcorner q:\n') + f1w.write(u'\t\t\t\t\tqq := (superellipse((.07u,0),(0,.03u), (-.07u,0),(0,.-.03u),.75))\n') + f1w.write(u'\t\t\t\t\t%randomized (u/25)\n') + f1w.write(u'\t\t\t\t\trotated uniformdeviate(360) \n') + f1w.write(u'\t\t\t\t\tshifted ((i,j) randomized 0.27u);\n') + f1w.write(u'\t\t\t\t\tif xpart (p intersectiontimes qq) < 0:\n') + f1w.write(u'\t\t\t\t\t\tthdraw qq;\n') + f1w.write(u'\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\tendfor; \n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t);\n') + f1w.write(u'\t\t\tclip tmp_pic to p;\n') + f1w.write(u'\t\t\tdraw tmp_pic;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# To change slopes aspects\n') + f1w.write(u'\t\tdef l_slope (expr P,S)(text Q) = \n') + f1w.write(u'\t\t\t%show Q;\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tnumeric dirs[];\n') + f1w.write(u'\t\t\tnumeric lengths[];\n') + f1w.write(u'\t\t\tfor i=Q:\n') + f1w.write(u'\t\t\t\tdirs[redpart i]:=greenpart i;\n') + f1w.write(u'\t\t\t\tlengths[redpart i]:=bluepart i;\n') + f1w.write(u'\t\t\tendfor; \n') + f1w.write(u'\t\t\tli:=length(P); % last\n') + f1w.write(u'\t\t\talw_perpendicular:=true;\n') + f1w.write(u'\t\t\tfor i=0 upto li:\n') + f1w.write(u'\t\t\tif unknown dirs[i]: dirs[i]:=-1; \n') + f1w.write(u'\t\t\telse: \n') + f1w.write(u'\t\t\t\tif dirs[i]>-1:\n') + f1w.write(u'\t\t\t\t\tdirs[i]:=((90-dirs[i]) - angle(thdir(P,i))) mod 360;\n') + f1w.write(u'\t\t\t\t\talw_perpendicular:=false;\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\tfi;\n') + f1w.write(u'\t\t\tif unknown lengths[i]: lengths[i]:=-1; fi;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t%for i=0 upto li: show dirs[i]; endfor;\n') + f1w.write(u'\t\t\tni:=0; % next\n') + f1w.write(u'\t\t\tpi:=0; % previous\n') + f1w.write(u'\t\t\tfor i=0 upto li:\n') + f1w.write(u'\t\t\t\td:=dirs[i];\n') + f1w.write(u'\t\t\t\tif d=-1:\n') + f1w.write(u'\t\t\t\t\tif (i=0) or (i=li):\n') + f1w.write(u'\t\t\t\t\t\tdirs[i] := angle(thdir(P,i) rotated 90) mod 360;\n') + f1w.write(u'\t\t\t\t\t\tpi:=i;\n') + f1w.write(u'\t\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\t\tif ni<=i:\n') + f1w.write(u'\t\t\t\t\t\t\tfor j=i upto li:\n') + f1w.write(u'\t\t\t\t\t\t\t\tni:=j;\n') + f1w.write(u'\t\t\t\t\t\t\t\texitif dirs[j]>-1;\n') + f1w.write(u'\t\t\t\t\t\t\tendfor;\n') + f1w.write(u'\t\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\t\t\tw:=arclength(subpath(pi,i) of P) / \n') + f1w.write(u'\t\t\t\t\t\tarclength(subpath(pi,ni) of P);\n') + f1w.write(u'\t\t\t\t\t\tdirs[i]:=w[dirs[pi],dirs[ni]];\n') + f1w.write(u'\t\t\t\t\t\t%if (dirs[i]-angle(thdir(P,i))) mod 360>180:\n') + f1w.write(u'\t\t\t\t\t\t%dirs[i]:=w[dirs[ni],dirs[pi]];\n') + f1w.write(u'\t\t\t\t\t\t%message("*******");\n') + f1w.write(u'\t\t\t\t\t\t%fi;\n') + f1w.write(u'\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\tpi:=i;\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t%for i=0 upto li: show dirs[i]; endfor;\n') + f1w.write(u'\t\t\tni:=0; % next\n') + f1w.write(u'\t\t\tpi:=0; % previous\n') + f1w.write(u'\t\t\tfor i=0 upto li:\n') + f1w.write(u'\t\t\t\tl:=lengths[i];\n') + f1w.write(u'\t\t\t\tif l=-1:\n') + f1w.write(u'\t\t\t\t\tif (i=0) or (i=li):\n') + f1w.write(u'\t\t\t\t\t\tlengths[i] := 1cm; % should never happen!\n') + f1w.write(u'\t\t\t\t\t\tthwarning("slope width at the end point not specified");\n') + f1w.write(u'\t\t\t\t\t\tpi:=i;\n') + f1w.write(u'\t\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\t\tif ni<=i:\n') + f1w.write(u'\t\t\t\t\t\t\tfor j=i+1 upto li:\n') + f1w.write(u'\t\t\t\t\t\t\t\tni:=j;\n') + f1w.write(u'\t\t\t\t\t\t\t\texitif lengths[j]>-1;\n') + f1w.write(u'\t\t\t\t\t\t\tendfor; \n') + f1w.write(u'\t\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\t\t\tw:=arclength(subpath(pi,i) of P) / \n') + f1w.write(u'\t\t\t\t\t\tarclength(subpath(pi,ni) of P);\n') + f1w.write(u'\t\t\t\t\t\tlengths[i]:=w[lengths[pi],lengths[ni]];\n') + f1w.write(u'\t\t\t\t\t\tpi:=i;\n') + f1w.write(u'\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\tpi:=i;\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\t%for i=0 upto li: show lengths[i]; endfor;\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tboolean par;\n') + f1w.write(u'\t\t\tcas := 0.3u;\n') + f1w.write(u'\t\t\tkrok := 0.7u;\n') + f1w.write(u'\t\t\tdlzka := (arclength P);\n') + f1w.write(u'\t\t\tif dlzka>3u: dlzka:=dlzka-0.6u fi;\n') + f1w.write(u'\t\t\tmojkrok:=adjust_step(dlzka,1.4u) / 5;\n') + f1w.write(u'\t\t\tpickup PenD;\n') + f1w.write(u'\t\t\tpar := false;\n') + f1w.write(u'\t\t\tforever:\n') + f1w.write(u'\t\t\t\tt := arctime cas of P;\n') + f1w.write(u'\t\t\t\tif t mod 1>0: % not a key point\n') + f1w.write(u'\t\t\t\t\tw := (arclength(subpath(floor t,t) of P) / \n') + f1w.write(u'\t\t\t\t\tarclength(subpath(floor t,ceiling t) of P));\n') + f1w.write(u'\t\t\t\t\tif alw_perpendicular:\n') + f1w.write(u'\t\t\t\t\t\ta := 90;\n') + f1w.write(u'\t\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\t\ta := w[dirs[floor t],dirs[ceiling t]];\n') + f1w.write(u'\t\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\t\tl := w[lengths[floor t],lengths[ceiling t]];\n') + f1w.write(u'\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\tif alw_perpendicular:\n') + f1w.write(u'\t\t\t\t\t\ta := 90;\n') + f1w.write(u'\t\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\t\ta:= dirs[t];\n') + f1w.write(u'\t\t\t\t\tfi; \n') + f1w.write(u'\t\t\t\t\tl:=lengths[t];\n') + f1w.write(u'\t\t\t\tfi; \n') + f1w.write(u'\t\t\t\ta := a + angle(thdir(P,t)); \n') + f1w.write(u'\t\t\t\tthdraw (point t of P) -- \n') + f1w.write(u'\t\t\t\t((point t of P) + if par: 0.333 * fi l * unitvector(dir(a)));\n') + f1w.write(u'\t\t\t\tcas := cas + mojkrok;\n') + f1w.write(u'\t\t\t\tpar := not par;\n') + f1w.write(u'\t\t\t\texitif cas > dlzka + .3u + (krok / 3); % for rounding errors\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\tif S = 1: pickup PenC; draw P fi;\n') + f1w.write(u'\t\t\t\t%pickup pencircle scaled 3pt;\n') + f1w.write(u'\t\t\t\t%for i=0 upto li: draw point i of P; endfor;\n') + f1w.write(u'\t\tenddef; \n\n') + f1w.write(u'\t\t# To change color of Sump\n') + f1w.write(u'\t\tdef a_sump (expr p) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tthfill p withcolor (0.0, 0.0, 0.3);\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# To change color of Water area \n') + f1w.write(u'\t\tdef a_water (expr p) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tthfill p withcolor (0.0, 0.0, 0.1);\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# Northarrow more funnier !\n') + f1w.write(u'\t\tdef s_northarrow (expr rot) =\n') + f1w.write(u'\t\t\tbegingroup\n') + f1w.write(u'\t\t\t\tinterim defaultscale:=0.7; % scale your north arrow here\n') + f1w.write(u'\t\t\t\tT:=identity scaled defaultscale rotated -rot;\n') + f1w.write(u'\t\t\t\tinterim linecap:=squared;\n') + f1w.write(u'\t\t\t\tinterim linejoin:=rounded;\n') + f1w.write(u'\t\t\t\tthfill (-.5cm,-.1cm)--(0,2.5cm)--(.5cm,-.1cm)--cycle;\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled (0.08cm * defaultscale);\n') + f1w.write(u'\t\t\t\tthdraw (0,0)--(0,-2.5cm);\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled (0.16cm * defaultscale);\n') + f1w.write(u'\t\t\t\tp:=(0.4cm,0.6cm);\n') + f1w.write(u'\t\t\t\tthdraw ((p--(p yscaled -1)--(p xscaled -1)--(p scaled -1)) shifted (0,-1.0cm));\n') + f1w.write(u'\t\t\t\tlabel.rt(thTEX("mg") scaled 1.6, (.6cm,-1.6cm)) transformed T;\n') + f1w.write(u'\t\t\tendgroup;\n') + f1w.write(u'\t\tenddef; \n\n') + f1w.write(u'\t\t# Change Scale bar type\n') + f1w.write(u'\t\tdef s_scalebar (expr l, units, txt) =\n') + f1w.write(u'\t\t\tbegingroup\n') + f1w.write(u'\t\t\t\tinterim warningcheck:=0;\n') + f1w.write(u'\t\t\t\ttmpl:=l / Scale * cm * units / 2;\n') + f1w.write(u'\t\t\t\ttmpx:=l / Scale * cm * units / 5;\n') + f1w.write(u'\t\t\t\ttmph:=5bp; % bar height\n') + f1w.write(u'\t\t\tendgroup;\n') + f1w.write(u'\t\t\tpickup PenC;\n') + f1w.write(u'\t\t\tdraw (-tmpl,0)--(tmpl,0)--(tmpl,-tmph)--(-tmpl,-tmph)--cycle;\n') + f1w.write(u'\t\t\tp:=(0,0)--(tmpx,0)--(tmpx,-tmph)--(0,-tmph)--cycle;\n') + f1w.write(u'\t\t\tfor i:=-2.5 step 2 until 2:\n') + f1w.write(u'\t\t\t\tfill p shifted (i * tmpx,0);\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\t\tbegingroup\n') + f1w.write(u'\t\t\t\tinterim labeloffset:=3.5bp;\n') + f1w.write(u'\t\t\t\tfor i:=0 step (l/5) until (l-1):\n') + f1w.write(u'\t\t\t\t\ttmpx:=tmpl * (i * 2 / l - 1);\n') + f1w.write(u'\t\t\t\t\tlabel.bot(thTEX(decimal (i)),(tmpx,-tmph));\n') + f1w.write(u'\t\t\t\tendfor;\n') + f1w.write(u'\t\t\t\tlabel.bot(thTEX(decimal (l) & "\thinspace" & txt),(tmpl,-tmph));\n') + f1w.write(u'\t\t\t\t% To write the scale "1:scale"; Comment it ?\n') + f1w.write(u'\t\t\t\t%label.top(thTEX("Echelle 1 : " & decimal (Scale*100)),(0,0));\n') + f1w.write(u'\t\t\tendgroup;\n') + f1w.write(u'\t\tenddef; \n\n') + f1w.write(u'\t\t# Change the altitude definition\n') + f1w.write(u'\t\t# This label requires to specify the position of text relative to point with \n') + f1w.write(u'\t\t# help of -align in the options box. \n') + f1w.write(u'\t\t# ex: -align bottom-right/top-left/top-right/bottom-left/top/bottom/left/right...\n') + f1w.write(u'\t\tdef p_altitude (expr pos) =\n') + f1w.write(u'\t\t\tT:=identity shifted pos;\n') + f1w.write(u'\t\t\tpickup PenD;\n') + f1w.write(u'\t\t\tp:=(-.3u,0)--(.3u,0);\n') + f1w.write(u'\t\t\tthdraw p; thdraw p rotated 90;\n') + f1w.write(u'\t\t\tp:=fullcircle scaled .2u;\n') + f1w.write(u'\t\t\tthclean p; thdraw p;\n') + f1w.write(u'\t\tenddef;\n') + f1w.write(u'\t\tvardef p_label@#(expr txt,pos,rot,mode) =\n') + f1w.write(u'\t\t\tif mode=1:\n') + f1w.write(u'\t\t\t\tthdrawoptions(withcolor .8red + .4blue);\n') + f1w.write(u'\t\t\t\tp_altitude(pos);\n') + f1w.write(u'\t\t\t\t% append "m" to label\n') + f1w.write(u'\t\t\t\tpicture txtm;\n') + f1w.write(u'\t\t\t\ttxtm:=image(\n') + f1w.write(u'\t\t\t\t\tdraw txt;\n') + f1w.write(u'\t\t\t\t\tinterim labeloffset:=0;\n') + f1w.write(u'\t\t\t\t\tlabel.urt(btex \thaltitude m etex, lrcorner txt);\n') + f1w.write(u'\t\t\t\t);\n') + f1w.write(u'\t\t\t\t% give extra offset in case of l/r/t/b alignment\n') + f1w.write(u'\t\t\t\tpair ctmp;\n') + f1w.write(u'\t\t\t\tctmp:=center thelabel@#("x", (0,0));\n') + f1w.write(u'\t\t\t\tif (xpart ctmp * ypart ctmp)=0:\n') + f1w.write(u'\t\t\t\t\tinterim labeloffset:=(.4u);\n') + f1w.write(u'\t\t\t\telse: % diagonal alignment\n') + f1w.write(u'\t\t\t\t\tinterim labeloffset:=(.2u);\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\t\t% draw label\n') + f1w.write(u'\t\t\t\tlab:=thelabel@#(txtm, pos);\n') + f1w.write(u'\t\t\t\tdraw lab _thop_; % use color\n') + f1w.write(u'\t\t\t\tthdrawoptions();\n') + f1w.write(u'\t\t\t\tbboxmargin:=0.8bp;\n') + f1w.write(u'\t\t\t\twrite_circ_bbox((bbox lab) smoothed 2);\n') + f1w.write(u'\t\t\telse:\n') + f1w.write(u'\t\t\t\tif mode=7: interim labeloffset:=(u/8) fi;\n') + f1w.write(u'\t\t\t\tlab:=thelabel@#(txt, pos);\n') + f1w.write(u'\t\t\t\tif mode>1: pickup PenD fi;\n') + f1w.write(u'\t\t\t\tif mode=2: process_uplabel;\n') + f1w.write(u'\t\t\t\telseif mode=3: process_downlabel;\n') + f1w.write(u'\t\t\t\telseif mode=4: process_updownlabel;\n') + f1w.write(u'\t\t\t\telseif mode=5: process_circledlabel;\n') + f1w.write(u'\t\t\t\telseif mode=6: process_boxedlabel;\n') + f1w.write(u'\t\t\t\telseif mode=7: process_label(pos,rot); % station name\n') + f1w.write(u'\t\t\t\telseif mode=8: process_filledlabel(pos, rot);\n') + f1w.write(u'\t\t\t\telse: process_label(pos,rot); fi;\n') + f1w.write(u'\t\t\tfi;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# definition of new lines/symbols\n\n') + f1w.write(u'\t\t# Line symbol for strata for cross sections. It works exactly as line section \n') + f1w.write(u'\t\t# symbol but you should use -clip off option:\n') + f1w.write(u'\t\tdef l_u_strata (expr P) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpath Q; Q = punked P;\n') + f1w.write(u'\t\t\tfor t = 0 upto length P - 1:\n') + f1w.write(u'\t\t\t\tpair zz[];\n') + f1w.write(u'\t\t\t\tzz1 := point t of P;\n') + f1w.write(u'\t\t\t\tzz2 := point t+1 of P;\n') + f1w.write(u'\t\t\t\tzz3 := postcontrol t of P;\n') + f1w.write(u'\t\t\t\tzz4 := precontrol t+1 of P;\n') + f1w.write(u'\t\t\t\tlinecap:=0;\n') + f1w.write(u'\t\t\t\tif (length(zz3-1/3[zz1,zz2]) > 0.1pt) or (length(zz4-2/3[zz1,zz2]) > 0.1pt):\n') + f1w.write(u'\t\t\t\t\tzz5 = whatever[zz1,zz2];\n') + f1w.write(u'\t\t\t\t\t(zz3-zz5) = whatever * (zz1-zz2) rotated 90;\n') + f1w.write(u'\t\t\t\t\tpickup pencircle scaled 1 mm;\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz5 dashed evenly;\n') + f1w.write(u'\t\t\t\t\tpickup PenA;\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz5 withcolor background;\n') + f1w.write(u'\t\t\t\t\tzz6 = whatever[zz1,zz2];\n') + f1w.write(u'\t\t\t\t\t(zz4-zz6) = whatever * (zz1-zz2) rotated 90;\n') + f1w.write(u'\t\t\t\t\tpickup pencircle scaled 1 mm;\n') + f1w.write(u'\t\t\t\t\tdraw zz2--zz6 dashed evenly;\n') + f1w.write(u'\t\t\t\t\tpickup PenA;\n') + f1w.write(u'\t\t\t\t\tdraw zz2--zz6 withcolor background;\n') + f1w.write(u'\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\tpickup pencircle scaled 1 mm;\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz2 dashed evenly;\n') + f1w.write(u'\t\t\t\t\tpickup PenA;\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz2 withcolor background;\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# Line symbol for fault. It works exactly as line section symbol but you should use -clip off option:\n') + f1w.write(u'\t\tdef l_u_fault (expr P) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpath Q; Q = punked P;\n') + f1w.write(u'\t\t\tpickup PenA;\n') + f1w.write(u'\t\t\tfor t = 0 upto length P - 1:\n') + f1w.write(u'\t\t\t\tpair zz[];\n') + f1w.write(u'\t\t\t\tzz1 := point t of P;\n') + f1w.write(u'\t\t\t\tzz2 := point t+1 of P;\n') + f1w.write(u'\t\t\t\tzz3 := postcontrol t of P;\n') + f1w.write(u'\t\t\t\tzz4 := precontrol t+1 of P;\n') + f1w.write(u'\t\t\t\tif (length(zz3-1/3[zz1,zz2]) > 0.1pt) or (length(zz4-2/3[zz1,zz2]) > 0.1pt):\n') + f1w.write(u'\t\t\t\t\tzz5 = whatever[zz1,zz2];\n') + f1w.write(u'\t\t\t\t\t(zz3-zz5) = whatever * (zz1-zz2) rotated 90;\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz5 dashed evenly;\n') + f1w.write(u'\t\t\t\t\tzz6 = whatever[zz1,zz2];\n') + f1w.write(u'\t\t\t\t\t(zz4-zz6) = whatever * (zz1-zz2) rotated 90;\n') + f1w.write(u'\t\t\t\t\tdraw zz2--zz6 dashed evenly;\n') + f1w.write(u'\t\t\t\telse:\n') + f1w.write(u'\t\t\t\t\tdraw zz1--zz2 dashed evenly;\n') + f1w.write(u'\t\t\t\tfi;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'\t\t# code to define a doline\n') + f1w.write(u'\t\tdef l_u_doline (expr P) =\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tlaenge:= arclength P;\n') + f1w.write(u'\t\t\tsymsize:=adjust_step(laenge,2u);\n') + f1w.write(u'\t\t\ttriangle_width:=symsize/10;\n') + f1w.write(u'\t\t\tcur:=(symsize-triangle_width)/2;\n') + f1w.write(u'\t\t\tpickup PenC;\n') + f1w.write(u'\t\t\tforever:\n') + f1w.write(u'\t\t\t\tt1 := arctime (cur) of P;\n') + f1w.write(u'\t\t\t\tt := arctime (cur + triangle_width/2) of P;\n') + f1w.write(u'\t\t\t\tt2 := arctime (cur + triangle_width) of P;\n') + f1w.write(u'\t\t\t\tthfill (subpath (t1,t2) of P) -- \n') + f1w.write(u'\t\t\t\t((point t of P) + symsize/2 * unitvector(thdir(P,t) rotated 90)) -- \n') + f1w.write(u'\t\t\t\tcycle;\n') + f1w.write(u'\t\t\t\tthdraw (point t2 of P) --((point t of P) + symsize/2 * unitvector(thdir(P,t) rotated 90)) -- \n') + f1w.write(u'\t\t\t\t(point t1 of P) withcolor (0.5, 0, 0);\n') + f1w.write(u'\t\t\t\tcur := cur + symsize;\n') + f1w.write(u'\t\t\t\texitif cur > laenge - (1*symsize/3); % for rounding errors\n') + f1w.write(u'\t\t\t\tt1:=arctime (cur) of P;\n') + f1w.write(u'\t\t\tendfor;\n') + f1w.write(u'\t\tenddef;\n\n') + f1w.write(u'endlayout \n\n\n') + + f1w.write(u'#------------------------------\n') + f1w.write(u'layout layoutmapborder \n') + f1w.write(u'# If you want to draw a frame around the map\n') + f1w.write(u'\tcode tex-map\n') + f1w.write(u'\t\t\\framethickness=0.5mm\n') + f1w.write(u'endlayout\n\n\n') + + f1w.write(u'#------------------------------\n') + f1w.write(u'layout layoutcontinuation \n') + f1w.write(u'\t# If you want to write all the continuations\n') + f1w.write(u'\tcode metapost\n') + f1w.write(u'\t\tdef p_continuation(expr pos,theta,sc,al) =\n') + f1w.write(u'\t\t\t% draw default continuation symbol\n') + f1w.write(u'\t\t\tp_continuation_UIS(pos,theta,sc,al);\n') + f1w.write(u'\t\t\t% if text attribute is set\n') + f1w.write(u'\t\t\tif known(ATTR__text) and picture(ATTR__text):\n') + f1w.write(u'\t\t\t\t% set labeling color to light orange\n') + f1w.write(u'\t\t\t\tpush_label_fill_color(1.0, 0.9, 0.8);\n') + f1w.write(u'\t\t\t\t% draw filled label with text next to ?\n') + f1w.write(u'\t\t\t\tp_label.urt(ATTR__text,(.5u,-.25u) transformed T,0.0,8);\n') + f1w.write(u'\t\t\t\t% restore original labeling color\n') + f1w.write(u'\t\t\t\tpop_label_fill_color;\n') + f1w.write(u'\t\t\tfi;\n') + f1w.write(u'\t\tenddef;\n') + f1w.write(u'\tendcode\n') + f1w.write(u'endlayout layoutcontinuation\n\n\n') + + f1w.write(u'#------------------------------\n') + f1w.write(u'layout northarrowMG\n\n') + f1w.write(u'\tcode metapost\n') + f1w.write(u'\t\t# If you want to get both, magnetic and geographic north,\n') + #f1w.write(u'\t\t# with \cartodate ?\n') + f1w.write(u'\t\tdef s_northarrow (expr rot) =\n') + f1w.write(u'\t\t\t%valscal=1.2; % scale your north arrow here\n') + f1w.write(u'\t\t\tvalscal=0.7; % scale your north arrow here\n') + f1w.write(u'\t\t\tdecl:=MagDecl; % set the magnetic declination\n') + f1w.write(u'\t\t\tT:=identity;\n') + f1w.write(u'\t\t\tpicture tmp_pic;\n') + f1w.write(u'\t\t\ttmp_pic = image (\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .3;\n') + f1w.write(u'\t\t\t\tthfill fullcircle scaled 4cm withcolor 1white;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 3.1cm;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 4.05cm;\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .1;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 3cm;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 4cm;\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .2;\n') + f1w.write(u'\t\t\t\tthdraw (dir(45)*2.025cm)--(dir(45)*3.7cm);\n') + f1w.write(u'\t\t\t\tthdraw (dir(135)*2.025cm)--(dir(135)*3.7cm);\n') + f1w.write(u'\t\t\t\tthdraw (dir(225)*2.025cm)--(dir(225)*3.7cm);\n') + f1w.write(u'\t\t\t\tthdraw (dir(315)*2.025cm)--(dir(315)*3.7cm);\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .1;\n') + f1w.write(u'\t\t\t\tfor whereto=0 step 15 until 345:\n') + f1w.write(u'\t\t\t\t\tthdraw dir(whereto)*.65cm--dir(whereto)*.9cm;\n') + f1w.write(u'\t\t\t\t\tthdraw dir(whereto)*1.4cm--dir(whereto)*1.5cm;\n') + f1w.write(u'\t\t\t\tendfor;\n') + f1w.write(u'\t\t\t\tfor whereto=0 step 5 until 355:\n') + f1w.write(u'\t\t\t\t\tthdraw dir(whereto)*.65cm--dir(whereto)*.8cm;\n') + f1w.write(u'\t\t\t\t\tthdraw dir(whereto)*1.45cm--dir(whereto)*1.5cm;\n') + f1w.write(u'\t\t\t\tendfor; \n') + f1w.write(u'\t\t\t\tfor whereto=0 step 1 until 359:\n') + f1w.write(u'\t\t\t\t\tthdraw dir(whereto)*1.94cm--dir(whereto)*2cm;\n') + f1w.write(u'\t\t\t\tendfor; \n') + f1w.write(u'\t\t\t\tpickup pencircle scaled 1;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 1cm;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 1.1cm;\n') + f1w.write(u'\t\t\t\tthdraw fullcircle scaled 1.3cm withpen pencircle scaled .3;\n') + f1w.write(u'\t\t\t\tvald=90-decl;\n') + f1w.write(u'\t\t\t\ttexrot=0-decl;\n') + f1w.write(u'\t\t\t\tdrawarrow(dir(vald)*-2cm--dir(vald)*2cm) withpen pencircle scaled .2;\n') + f1w.write(u'\t\t\t\t% Add the date of the last drawing\n') + f1w.write(u'\t\t\t\tthdraw image(label.top(btex $mg$ etex, (0,0)) scaled .5 rotated texrot;) shifted (dir(vald)*2.04cm); \n') + f1w.write(u'\t\t\t\tthfill (1.06cm,1.06cm)--(0,.2cm)--(-1.06cm,1.06cm)--(-.2cm,0)--(-1.06cm,-1.06cm)--(0,-.2cm)--(1.06cm,-1.06cm)--(.2cm,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill (-.2cm,.2cm)--(0,2cm)--(0,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill (.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill (.2cm,.2cm)--(2cm,0)--(0,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill (-.2cm,-.2cm)--(-2cm,0)--(0,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill (.2cm,.2cm)--(-0,2cm)--(0,0)--cycle withcolor 1white;\n') + f1w.write(u'\t\t\t\tthfill (.2cm,-.2cm)--(2cm,0)--(0,0)--cycle withcolor 1white;\n') + f1w.write(u'\t\t\t\tthfill (-.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle withcolor 1white;\n') + f1w.write(u'\t\t\t\tthfill (-.2cm,.2cm)--(-2cm,0)--(0,0)--cycle withcolor 1white; \n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .2;\n') + f1w.write(u'\t\t\t\tthdraw (-.2cm,.2cm)--(0,2cm)--(.2cm,.2cm)--(2cm,0cm)--(.2cm,-.2cm)--(0,-2cm)--(-.2cm,-.2cm)--(-2cm,0)--cycle;\n') + f1w.write(u'\t\t\t\tthfill fullcircle scaled .56cm withcolor 1white;\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .1;\n') + f1w.write(u'\t\t\t\tthdraw (.28cm,0)..(0,.28cm)..(-.28cm,0)..(0,-.28cm)..cycle;\n') + f1w.write(u'\t\t\t\tpickup pencircle scaled .4;\n') + f1w.write(u'\t\t\t\tthdraw (.2cm,0)..(0,.2cm)..(-.2cm,0)..(0,-.2cm)..cycle;\n') + f1w.write(u'\t\t\t\tlabel.bot(btex $N$ etex, (0,2.6cm));\n') + f1w.write(u'\t\t\t\tlabel.lft(btex $E$ etex, (2.6cm,0));\n') + f1w.write(u'\t\t\t\tlabel.rt(btex $W$ etex, (-2.6cm,0));\n') + f1w.write(u'\t\t\t\tlabel.top(btex $S$ etex, (0,-2.6cm));\n') + f1w.write(u'\t\t\t);\n') + f1w.write(u'\t\t\tthdraw tmp_pic scaled valscal rotatedaround(origin, -rot);\n') + f1w.write(u'\t\tenddef;\n') + f1w.write(u'\tendcode\n') + f1w.write(u'endlayout northarrowMG\n') + + # add your piece of code here and before the closing + # . + # . + # . + + # close the config.thc file + f1w.closed + + print(u'\tFile ' + pdata + u' written...') + + return + + +def checkfiles(pdata, Errorfiles = True): + """ + Function to check if the file exists + Raise error if file exists + + INPUTS: + pdata : variable that sets the file to check + Errorfiles : boolean; if True (default), if pdata already exists, the program stops; + if False, the programme erase the old pdata + + OUTPUTS: + None + + USAGE: + checkfiles(pdata, Errorfiles = False) + checkfiles(pdata) + + Author: Xavier Robert, Lima 2016/06/27 + """ + # Check if file exists, if not, raise an error + if os.path.isfile(pdata) == True : + if Errorfiles: + raise NameError(u'ERROR : File {FileNa} does exist'.format(FileNa=str(pdata))) + #sys.exit('ERROR : File {FileNa} does exist'.format(FileNa=str(pdata))) + else: + print(u'WARNING: I have erased file %s' % pdata) + + +####### +if __name__ == "__main__": + + # build dictionnaries + dictcave, datac = builddictcave() + thlang = datac[0] + thcfile = datac[1] + thcfnme = datac[2] + thcpath = datac[3] + thconfigfile = datac[4] + thconfigpath = datac[5] + thconfigfnme = datac[6] + icomments = datac[7] + icoupe = datac[8] + Errfiles = datac[9] + + # check if the files exists + if thcfnme[-4:] != u'.thc': + thcfnme = thcfile + u'.thc' + if thcpath is not None : + if thcpath[-1] != u'/': + thcpath = thcpath + u'/' + if not Errfiles : + checkfiles(thcpath + thcfnme) + else: + print(u'WARNING: I will erase previous ' + thcpath + thcfnme + u' files !') + else: + if not Errfiles : + checkfiles(thcfnme) + else: + print(u'WARNING: I will erase previous ' + thcfnme + u' files !') + + if thconfigfnme[-9:] != u'.thconfig': + thconfigfnme = thconfigfnme + u'.thconfig' + if thconfigpath is not None : + if thconfigpath[-1] != u'/': + thconfigpath = thcpath + u'/' + if not Errfiles: + checkfiles(thconfigpath + thconfigfnme) + else: + print(u'WARNING: I will erase previous ' + thconfigpath + thconfigfnme + u' files !') + else: + if not Errfiles : + checkfiles(thconfigfnme) + else: + print(u'WARNING: I will erase previous ' + thconfigfnme + u' files !') + + # build thc file + if thcfile : + if thcpath is not None : + writethc(thcpath + thcfnme) + else: + writethc(thcfnme) + + # build thconfig file + if thconfigfile : + # write the file + if thconfigpath is not None: + if thcpath is not None: + writethconfig(thconfigpath + thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcpath + thcfnme) + else: + writethconfig(thconfigpath + thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcfnme) + else: + if thcpath is not None: + writethconfig(thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcpath + thcfnme) + else: + writethconfig(thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcfnme) + + + +# END diff --git a/Scripts/pyCreateTh/Lib/pytro2th/command_line.py b/Scripts/pyCreateTh/Lib/pytro2th/command_line.py new file mode 100644 index 0000000..c5895d9 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/command_line.py @@ -0,0 +1,100 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later + +import argparse + +from ._version import __version__ +from .tro2th import tro2th + + +def main(**kwargs): + ap = argparse.ArgumentParser() + ap.add_argument("--version", action="version", version=f"%(prog)s {__version__}") + ap.add_argument( + "--fle-tro-fnme", + default=None, + help="Path and name of the .tro file to convert", + ) + ap.add_argument( + "--fle-tro-encoding", + default=None, + help="Force encoding of the .tro file to convert, for instance iso-8859-1. Default is utf-8", + ) + ap.add_argument( + "--fle-th-fnme", + default=None, + help="Path and name of the .th file to create from the .tro file.", + ) + ap.add_argument( + "--thlang", default="fr", help="String that set the language. 'fr' by default" + ) + ap.add_argument("--cavename", default=None, help="Name of the cave") + ap.add_argument( + "--no-icomments", + default=True, + action="store_const", + const=False, + dest="icomments", + help="Disable comments in the produced files", + ) + ap.add_argument( + "--no-icoupe", + default=True, + action="store_const", + const=False, + dest="icoupe", + help="Disable the extended-elevation layout in the .thconfig file", + ) + ap.add_argument( + "--ithconfig", + default=True, + action="store_const", + const=False, + dest="ithconfig", + help="Disable creation of the thconfig file", + ) + ap.add_argument( + "--thconfigfnme", default=None, help="Path and name of the thconfig file" + ) + ap.add_argument( + "--no-ithc", + default=True, + action="store_const", + const="False", + dest="ithc", + help="Disable creation of a config file config.thc", + ) + ap.add_argument( + "--thcpath", + default=None, + help="Path to the directory that contains the config file called in the cave.thconfig file", + ) + ap.add_argument("--thcfnme", default="config.thc", help="Name of the config.thc") + ap.add_argument( + "--sourcefile", + nargs="*", + help="Define the source files declared in the cave.thconfig", + ) + ap.add_argument( + "--xviscale", default=1000, type=float, help="Scale of the xvi file" + ) + ap.add_argument( + "--xvigrid", + default=10.0, + type=float, + help="Spacing of the grid for the xvi, in meters", + ) + ap.add_argument("--scale", default=500, type=float, help="Scale of the map") + ap.add_argument( + "--no-error-files", + default=True, + action="store_const", + const=False, + dest="Errorfiles", + help="Do not raise en error if output files exists in the folder", + ) + args = ap.parse_args(**kwargs) + tro2th(**vars(args)) diff --git a/Scripts/pyCreateTh/Lib/pytro2th/datathwritetools.py b/Scripts/pyCreateTh/Lib/pytro2th/datathwritetools.py new file mode 100644 index 0000000..d1f43ad --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/datathwritetools.py @@ -0,0 +1,569 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- +# coding: utf8 + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later +# Modifié Alex 2025 07 01 + +""" +Script to build Therion files +By Xavier Robert +Lima, 2016.06.21 + +USAGE : + 1- Run in the terminal: $ python buildthconfig.py + + +INPUTS: +The inputs are in the script file, in the "# Define data to analysis" section. +The different arguments are described. + +""" + +###### To DO : ####### +# - Test the MTL pdfs (I have not tested it, even if it should be OK) +# - Add error bars on data graphs ? +# For that we should read the input data file given in topo_parameters.txt +# (paragraphe N°12 of topo_parameters.txt) +# +###### End To DO ####### + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer +#from __future__ import unicode_literals + +# Import modules +from Lib.general_fonctions import sanitize_filename +import sys, os, copy, datetime +from pyproj import Proj, transform + +################################################################################################# +def writeheader_th(file, cavename, entrance): + """ + Function to write the header of the file.th + + INPUTS: + file : variable that sets the file.th + cavename : name of the cave + entrance : name of the entrance station + + OUTPUTS: + None + + USAGE: + writeheader_th(file, cavename, entrance) + + Author: Xavier Robert, Lima 2016/06/27 + + """ + + file.write(u'encoding utf-8 \n\nsurvey %s -title "%s" -entrance "%s" \n' + %(sanitize_filename(cavename), cavename, entrance)) + + return + + +################################################################################################# +def writecenterlineheader(file, entrance, settings, comments, data, coordsyst, coordinates, club, + icomments, thlang): + """ + Function to write the centerline header + + + INPUTS: + file : variable that sets the file.th + entrance : name of the entrance station + settings : List of the settings of this survey section + comments : String that correspond to the end of the string "Line" + that do not correspond to the settings + data : data from this survey section + coordsyst : Coordinates system to set the entrance coordinates + coordinates : Entrance coordinates + club : Name of the group that explored the cave + icomments : True if comments in the file + False if not + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + + OUTPUTS: + None + + USAGE: + writeheader_th(file, cavename, entrance) + + Author: Xavier Robert, Lima 2016/06/27 + + """ + # First, define dictionaries to help the coding + # angleU: define the angle unit + angleU = {u'Deg' : u'degrees', + u'Degd' :u'degrees', + u'Gra' : u'grad'} + # compassdir: + dir = {u'Dir' : u'', + u'Inv' : u'back'} + # lruddir: Set the LRUD + lruddir = {u'Dir' : u'left right up down', + u'Inv' : u'right left up down', + u'Nod' : u''} + # unitcounter: set the unit of the counter (for the length) + unitcounter = {u'Vulc' : u'centi', + u'Prof' : u'', + u'Deniv': u''} + # unitclino: used to correct the clino if topoVulcain + unitclino = {u'Deg' : u'90', + u'Degd' : u'90', + u'Gra' : u'100'} + # typelen: type of length measures + #typelem = {u'Deca' : u'normal', + # u'Topof' : u'topofil', + # u'Vulc' : u'topofil', + # u'Prof' : u'diving', + # u'Deniv' : u'deniv'} + # style: data style + style = {u'Deca' : u'normal', + u'Topof' : u'topofil', + u'Diving' : u'diving', + u'Prof' : u'diving', + u'Carth' : u'carthesian', + u'Cylp' : u'cylpolar', + u'Dim' : u'dimensions', + u'Nosy' : u'nosurvey'} + # station: type of stations + station = {u'station' : u'station', + u'from' : u'from', + u'to' : u'to', + u'vtopo' : u'from to'} + # lensurv: how are set the length measurements + lensurv = {u'Deca' : u'length', + u'Topof' : u'fromcount tocount', + u'Diving' : u'length', + u'Prof' : u'length'} + # slopesurv: how are set the slope measurements + slopesurv = {u'Clino' : u'clino', + u'Vulc' : u'clino', + u'Deniv' : u'depthchange', + u'Prof' : u'depth'} + + # Begin the centerline + file.write(u'\n\tcenterline \n') + + # if entrance in the data, write the entrance coordinates + if [datal for datal in data if entrance in datal] != []: + if icomments: + if thlang == u'fr': + file.write(u'\t\t# Si le systeme de coordonnées n\'est pas le système' + u' Lambert français, voir le Thbook et le fichier' + u' extern/proj4/nad/epsg dans le dossier source de Therion \n') + file.write(u'\t\t# Si les coordonnées de l\'entrée sont connues,' + u' copier dans la centerline correspondante et décommenter' + u' les 2 lignes suivantes : \n') + elif thlang == u'en': + file.write(u'\t\t# If your are not in the french Lambert system, ' + u' To find number of your system, see' + u' extern/proj4/nad/epsg file in the Therion' + u' source distribution \n') + file.write(u'\t\t# If the entrance coordinates are known, uncomment and' + u' copy in the corresponding centerline the next 2 lines: \n') + if coordsyst != None: + file.write(u'\t\tcs %s \n' + u'\t\tfix %s %s %s %s \n\n' % (coordsyst, entrance, coordinates[0], coordinates[0], coordinates[0])) + else: + file.write(u'\t\t#cs %s \n' + u'\t\t#fix %s %s %s %s \n\n' % (coordsyst, entrance, coordinates[0], coordinates[0], coordinates[0])) + typem = u'Deca' + if u'Topof' not in settings: + settings [1:1]= u' ' + typem = u'Topof' + if u'Prof' in settings or u'Deniv' in settings: + settings[4:4] = u' ' + # next line used to debug + #file.write(u'\t' + str(settings) + u'\n') + # write the survey caracteristics + file.write(u'\t\tdate %s\n'% str(settings[9])) + if icomments: + if thlang == u'fr': + file.write(u'\t\t# Si date est utilisé, commenter la ligne "declination", ' + u'la date sera utilisée pour la calculer\n') + elif thlang == u'en': + file.write(u'\t\t# If date is used, comment the ligne "declination", ' + u'the date will be use to compute it\n') + file.write(u'\t\tdeclination %s %s \n'% (str(settings[5]), angleU[settings[2]])) + # file.write(u'\t\t\tteam "G.S. Vulcain" \n') + file.write(u'\t\t# team "%s" \n' % club) + file.write(u'\t\t#explo-date %s\n'% str(settings[9])) + # file.write(u'\t\t\texplo-team "G.S. Vulcain" \n') + file.write(u'\t\t# explo-team "%s" \n' % club) + if icomments: + if thlang == u'en': file.write(u'\t\t# (to be completed, add many lines as you need) \n') + elif thlang == u'fr': file.write(u'\t\t# (peut être complété en ajoutant le nombre de lignes nécessaires) \n') + + dirs = settings[6].rstrip(u'\n\r').split(u',') + + file.write(u'\n\t\tunits length meters \n') + if u'Topof' in settings: + file.write(u'\t\tunits counter %smeters \n' % unitcounter[settings[3]]) + file.write(u'\t\tcalibrate counter 0 %s \n' % settings[1]) + # To set the slope + if u'Vulc' in settings: + file.write(u'\t\tcalibrate clino 1 %s -1\n' % unitclino[settings[4]]) + if u'Prof' in settings: + file.write(u'\t\tunits depth meters \n') + typem = u'Prof' + elif u'Deniv' in settings: + file.write(u'\t\tunits depth meters \n') + typem = u'Diving' + + file.write(u'\t\tunits compass %s \n' % (angleU[settings[2]])) + if u'Vulc' in settings or 'Clino' in settings: + file.write(u'\t\tunits clino %s \n' % (angleU[settings[4]])) + + file.write(u'\n\t\tdata %s %s %s %scompass %s%s %s\n' + % (style[typem], station[u'vtopo'], lensurv[settings[0]], + dir[dirs[0]], dir[dirs[1]], slopesurv[settings[3]], + lruddir[dirs[2]])) + if comments != u'': + file.write(u'\t\t\t#' + comments + u'\n') + + return + + +################################################################################################# +def writedata(file, settings, data, dataold): + """ + function to write the data in the .th file + + INPUTS: + file : variable that sets the file.th + settings : List of the settings of this survey section + data : data from this survey section + dataold : data from the previous survey section + + OUTPUTS: + None + + USAGE: + writeheader_th(file, cavename, entrance) + + Author: Xavier Robert, Lima 2016/06/27 + + """ + + # dictl = length of the data line + dictl = {u'Deca' : 9, + u'Topof' : 10} + + i=0 + for elems in data: + for k in [0,2]: + if elems[k] == u'*': + # remove the '*', and replace them with the right data ! + if i == 0: elems[k] = dataold[len(dataold)-1][k+1] + else: elems[k] = data[i-1][k+1] + if elems[0] == elems[1]: elems[1] = elems[1] + u'd' + for k in range (dictl[settings[0]]-4, dictl[settings[0]]): + # Check that LRUD != '*'; If yes, change them to 0 + if elems[k] == u'*': elems[k] = u'0' + + # Check if option 'E' + if u'E' in elems: + file.write(u'\t\t\tflags duplicate \n') + # We write the data + # if elems[0:1] == "*": + # elems[0:1] = "-" + file.write(u'\t\t\t' + u'\t'.join( + "-" if i == 1 and x == "*" else x + for i, x in enumerate(elems[0:dictl[settings[0]]]) + )) + + # file.write(u'\t\t\t' + u'\t'.join(x for x in elems[0:dictl[settings[0]]])) + + if len(elems) > (dictl[settings[0]] + 2): + if elems[dictl[settings[0]] + 1] != u'N' and elems[dictl[settings[0]] + 1] != u'I': + # we add the comment if there is one + file.write(u'\t# ' + ' '.join(x for x in elems[(dictl[settings[0]]+1) : len(elems)])[1:-1] + u'\n') + elif len(elems) > (dictl[settings[0]] + 3): + file.write(u'\t# ' + ' '.join(x for x in elems[(dictl[settings[0]]+2) : len(elems)])[1:-1] + u'\n') + else: + file.write(u'\n') + else: + file.write(u'\n') + if elems[(dictl[settings[0]])] == u'I': + file.write(u'\t\t\textend reverse \n') + if u'E' in elems: + file.write(u'\t\t\tflags not duplicate \n') + i+=1 + + return + + +################################################################################################# +def write_thtot(file, cavename = u'cave', icomments = True, thlang = 'en'): + """ + Function to write the file cavename-tot.th + + INPUTS: + file : variable that sets the file.th + cavename : name of the cave + icomments : True if comments in the file + False if not + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + + OUTPUTS: + None + + USAGE: + write_thtot(file, cavename, icomments, thlang) + + Author: Xavier Robert, Grenoble 2021/01/03 + + """ + + file.write(u'encoding utf-8 \n\n') + + #file.write(u'encoding utf-8' \n\nsurvey %s -title "%s" -entrance "%s" \n' + # %(cavename.replace(u' ', u'_'), cavename, entrance)) + + if icomments: + if thlang == u'fr': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# Ce travaille est sous la licence Creative Commons Attribution-ShareAlike-NonCommecial :\n') + file.write(u'# \n\n') + elif thlang == u'en': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# This work is under the Creative Commons Attribution-ShareAlike-NonCommecial License:\n') + file.write(u'# \n\n') + + file.write(u'survey %s -title "%s"\n\n' %(sanitize_filename(cavename), cavename.replace(u' ', u'_'))) + #file.write(u'survey %s -title "%s"\n\n' %(cavename.replace(u' ', u'_'), cavename.replace(u' ', u'_'))) + + if icomments: + if thlang == u'fr': + file.write(u'\t# Pour importer les différentes données de différents fichiers topos :\n') + if thlang == u'en': + file.write(u'\t# To import data from different data files:\n') + file.write(u'\tinput Data/%s.th\n\n' %(cavename.replace(u' ', u'_'))) + + file.write(u'#\tcenterline\n') + if icomments: + if thlang == u'fr': file.write(u'\t\t##Rajout des longueurs explorées, non topo, ou topos perdues\n') + elif thlang == u'en': file.write(u'\t\t##Add length explored, but not surveyed, or with lost surveys\n') + + file.write(u'#\t\tstation Ca.31@%s "+78 m explorés " continuation explored 78m\n' %(cavename.replace(u' ', u'_'))) + if icomments: + if thlang == u'fr': file.write(u'\t\t## Pour assembler plusieurs fichiers topos\n') + elif thlang == u'en': file.write(u'\t\t## To join different surveys\n') + + file.write(u'#\t\tequate 6@%s 0@%s\n\n'%(cavename.replace(u' ', u'_'), cavename.replace(u' ', u'_') + u'2')) + + file.write(u'#\tendcenterline)\n\n') + + if icomments: + file.write(u'#\t##########################################################################################\n') + if thlang == u'fr': + file.write(u'#\t## Pour importer les différents fichiers de dessins en plan\n') + file.write(u'#\t## Et Pour assembler plusieurs scraps entre eux, il faut utiliser la commande\n') + file.write(u"#\t## join scrap1 scrap2 -count n (où n = nombre de galerie à connecter, par défaut n = 1). C'est tout simple !\n") + elif thlang == u'en': + file.write(u'#\t## To import different th2 files\n') + file.write(u'#\t## And to join different scraps together, you need to use the command\n') + file.write(u"#\t## join scrap1 scrap2 -count n (wher n = number of connections, by default n = 1). This is simple!\n") + + file.write(u'#\tjoin scrap1 scrap2 #-count n\n\n') + + if icomments: + if thlang == u'fr': file.write(u'## Pour le plan\n') + elif thlang == u'en': file.write(u'## For plan view\n') + + file.write(u'input Data/%s.th2\n\n' %(cavename.replace(u' ', u'_'))) + + if icomments: + if thlang == u'fr': file.write(u'## Pour la coupe développée\n') + elif thlang == u'en': file.write(u'## For extended elevation\n') + + file.write(u'input Data/%s-coupe.th2\n\n' %(cavename.replace(u' ', u'_'))) + + if icomments: + if thlang == u'fr': file.write(u'## Appel des maps\n') + elif thlang == u'en': file.write(u'## Call the maps file\n') + + file.write(u'input %s-maps.th\n\n' %(cavename.replace(u' ', u'_'))) + file.write(u'endsurvey\n') + + return + + +################################################################################################# +def write_thmaps(file, cavename = u'cave', icomments = True, thlang = 'en'): + """ + Function to write the file cavename-maps.th + + INPUTS: + file : variable that sets the file.th + cavename : name of the cave + icomments : True if comments in the file + False if not + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + + OUTPUTS: + None + + USAGE: + write_thmaps(file, cavename, icomments, thlang) + + Author: Xavier Robert, Grenoble 2021/01/03 + + """ + + file.write(u'encoding utf-8 \n\n') + + #file.write(u'encoding utf-8' \n\nsurvey %s -title "%s" -entrance "%s" \n' + # %(cavename.replace(u' ', u'_'), cavename, entrance)) + + if icomments: + if thlang == u'fr': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# Ce travail est sous la licence Creative Commons Attribution-ShareAlike-NonCommecial :\n') + file.write(u'# \n\n') + elif thlang == u'en': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# This work is under the Creative Commons Attribution-ShareAlike-NonCommecial License:\n') + file.write(u'# \n\n') + + file.write(u'map MP-%s-plan-tot -title "%s"\n' %(cavename.replace(u' ', u'_'), cavename.replace(u' ', u'_'))) + file.write(u'\tSP-%s-1\n' %(cavename.replace(u' ', u'_'))) + file.write(u'\t#break\n') + file.write(u'\t#SP-%s-2\n' %(cavename.replace(u' ', u'_'))) + file.write(u'endmap\n') + + file.write(u'map MC-%s-coupe-tot -title "%s"\n' %(cavename.replace(u' ', u'_'), cavename.replace(u' ', u'_'))) + file.write(u'\tSC-%s-1\n' %(cavename.replace(u' ', u'_'))) + file.write(u'\t#break\n') + file.write(u'\t#SC-%s-2\n' %(cavename.replace(u' ', u'_'))) + file.write(u'endmap\n') + + return + + +################################################################################################# +def write_thcoords(file, cavename = u'cave', coordinates = None, coordsyst = None, icomments = True, thlang = u'en'): + """ + Function to write the file Legends/entrances_coordinates.th + + INPUTS: + file : variable that sets the file.th + cavename : name of the cave + cordinates : Coordinates of the Cave + coordsyst : Coordinates system and projection + icomments : True if comments in the file + False if not + thlang : 'fr' for french + 'en' for english + ... other languages not implemented + + OUTPUTS: + None + + USAGE: + write_thcoords(file, cavename, coordinates, coordsyst, icomments, thlang) + + Author: Xavier Robert, Grenoble 2021/01/03 + + """ + + # Coordinates definition + if coordinates: + if coordsyst: + # Transform Lambert coordinates into Lat Long coordinates + inProj = Proj(coordsyst) + outProj = Proj('epsg:4326') + latc, longc = transform(inProj, outProj, float(coordinates[0]), float(coordinates[1])) + else: + latc = coordinates[1] + u'(Check coord. syst.)' + longc = coordinates[0] + u'(Check coord. syst.)' + altc = coordinates[2] + else: + latc = u'None' + longc = u'None' + altc = u'None' + + file.write(u'encoding utf-8 \n\n') + + if icomments: + if thlang == u'fr': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# Ce travail est sous la licence Creative Commons Attribution-ShareAlike-NonCommecial :\n') + file.write(u'# \n\n') + elif thlang == u'en': + file.write(u'# Copyright (C) %s Xavier Robert \n' %(str(datetime.datetime.now().year))) + file.write(u'# This work is under the Creative Commons Attribution-ShareAlike-NonCommecial License:\n') + file.write(u'# \n\n') + + file.write(u'layout Entrances_coords_%s\n\n' %(cavename.replace(u' ', u'_'))) + + if icomments: + if thlang == u'fr': + file.write(u'\t# Layout qui définit les différentes variables contenant du texte avec \n') + file.write(u"\t# les coordonnées de l'entrée que nous voulons ajouter au header.\n") + file.write(u"\t# Nous avons besoin d'une variable par entrée.\n") + file.write(u'\t# Ce layout est appelé par le layout Coords_Header ci-dessous\n\n') + elif thlang == u'en': + file.write(u'\t# Layout where we define the different variables that contain the text with \n') + file.write(u'\t# the entrance coordinates we want to print in the header.\n') + file.write(u'\t# We need one variable per entrance.\n') + file.write(u'\t# This layout is called by the layout Coords_Header below\n\n') + + file.write(u'\tcode tex-map\n') + file.write(u'\t\t\\def\\thjunk{ }\n') + file.write(u'\t\t\\def\\thlocation%s{%s -- Lat. : %s N ; Long. : %s E ; Alt. : %s m}\n' %(cavename.replace(u' ', u'_'), cavename.replace(u' ', u'_'), str(latc), str(longc), str(altc))) + # We probably need in the future to iterate on the number of entrances... + # I do not knwo for the moment if Visual Top take in account different entrences coordinates + file.write(u'\tendcode\n\n') + + file.write(u'\tendlayout\n\n') + + + file.write(u'layout Coords_Header_%s\n\n' %(cavename.replace(u' ', u'_'))) + if icomments: + if thlang == u'fr': file.write(u'\t# Layout that set the presentation for the entrance coordinates.\n\n') + + file.write(u'\tcopy Entrances_coords_%s\n\n' %(cavename.replace(u' ', u'_'))) + if icomments: + if thlang == u'fr': + file.write(u'\t# Appelle le layout ci-dessus Entrances_coords où nous avons défini les différentes \n') + file.write(u'\t# variables qui contiennent le texte avec \n') + file.write(u'\t# les coordonnées des entrées à écrire dans le header.\n\n') + elif thlang == u'en': + file.write(u'\t# it calls the layout above Entrances_coords where we defined the different \n') + file.write(u'\t# variables that contain the text with \n') + file.write(u'\t# the entrance coordinates we want to print in the header.\n\n') + + file.write(u'\tcode tex-map\n') + file.write(u'\t\t\\def\\nostring{}\n') + file.write(u'\t\t\\def\\thsizexl{}\n') + file.write(u'\t\t\\def\\thsizel{}\n') + file.write(u'\t\t\\def\\thsizem{}\n') + file.write(u'\t\t\\ifx\\thsizexl\\nostring\\def\\thsizexl{30}\\else\\fi\n') + file.write(u'\t\t\\ifx\\thsizel\\nostring\\def\\thsizel{24}\\else\\fi\n') + file.write(u'\t\t\\ifx\\thsizem\\nostring\\def\\thsizem{12}\\else\\fi\n\n') + + file.write(u'\t\t\\ECoordinates={\n') + file.write(u'\t\t\t\\edef\\tmp{\\thjunk} \\ifx\\tmp\\empty \\else\n') + file.write(u'\t\t\t\t{\\size[\\thsizem] \\ss\\thjunk\\vss}\n') + file.write(u'\t\t\t\\fi\n') + file.write(u'\t\t\t\\edef\\tmp{\\thlocation%s} \\ifx\\tmp\\empty \\else\n' %(cavename.replace(u' ', u'_'))) + file.write(u'\t\t\t\t# The first one should be without hskip\n') + file.write(u'\t\t\t\t{\\size[\\thsizem]\\hskip2cm \\ss\\thlocation%s\\vss}\n' %(cavename.replace(u' ', u'_'))) + file.write(u'\t\t\t\\fi\n') + file.write(u'\t\t\t}\n') + file.write(u'\tendcode\n\n') + + file.write(u'\tendlayout\n\n') + + return \ No newline at end of file diff --git a/Scripts/pyCreateTh/Lib/pytro2th/tests/Test.py b/Scripts/pyCreateTh/Lib/pytro2th/tests/Test.py new file mode 100644 index 0000000..8e94c73 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/tests/Test.py @@ -0,0 +1,131 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Script to build Therion files +By Xavier Robert +Lima, 2016.06.21 + +USAGE : + 1- Run in the terminal: $ python buildthconfig.py + + +INPUTS: +The inputs are in the script file, in the "# Define data to analysis" section. +The different arguments are described. + +xavier.robert@ujf-grenoble.fr + +(c) licence CCby-nc : http://creativecommons.org/licenses/by-nc/3.0/ 2015 + +""" + +###### To DO : ####### +# - +###### End To DO ####### + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer + +# Import modules +import sys +import os +import copy + + + + +#from unittest import TestCase + +#import funniest + +#class TestJoke(TestCase): +# def test_is_string(self): +# s = funniest.joke() +# self.assertTrue(isinstance(s, basestring)) + + + + + +from utils.buildparam import builddictcave +from utils.buildthconfig import * + +if __name__ == "__main__": + + # build dictionnaries + dictcave, data = builddictcave() + thlang = data[0] + thcfile = data[1] + thcfnme = data[2] + thcpath = data[3] + thconfigfile = data[4] + thconfigpath = data[5] + thconfigfnme = data[6] + icomments = data[7] + icoupe = data[8] + Errfiles = data[9] + + # check if the files exists + if thcfnme[-4:] != '.thc': + thcfnme = thcfile + '.thc' + if thcpath != None : + if thcpath[-1] != '/': + thcpath = thcpath + '/' + if not Errfiles : + checkfiles(thcpath + thcfnme) + else: + print('WARNING: I will erase previous ' + thcpath + thcfnme +' files !') + else: + if not Errfiles : + checkfiles(thcfnme) + else: + print('WARNING: I will erase previous ' + thcfnme +' files !') + + if thconfigfnme[-9:] != '.thconfig': + thconfigfnme = thconfigfnme +'.thconfig' + if thconfigpath != None : + if thconfigpath[-1] != '/': + thconfigpath = thcpath + '/' + if not Errfiles: + checkfiles(thconfigpath + thconfigfnme) + else: + print('WARNING: I will erase previous ' + thconfigpath + thconfigfnme + ' files !') + else: + if not Errfiles : + checkfiles(thconfigfnme) + else: + print('WARNING: I will erase previous ' + thconfigfnme + ' files !') + + # build thc file + if thcfile : + if thcpath != None : + writethc(thcpath + thcfnme) + else: + writethc(thcfnme) + + # build thconfig file + if thconfigfile : + # write the file + if thconfigpath != None: + if thcpath != None: + writethconfig(thconfigpath + thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcpath + thcfnme) + else: + writethconfig(thconfigpath + thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcfnme) + else: + if thcpath != None: + writethconfig(thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcpath + thcfnme) + else: + writethconfig(thconfigfnme, icomments, icoupe, thlang, + dictcave, + thcfile, thcfnme) + + + +# END diff --git a/Scripts/pyCreateTh/Lib/pytro2th/tests/__init__.py b/Scripts/pyCreateTh/Lib/pytro2th/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Scripts/pyCreateTh/Lib/pytro2th/tro2th.py b/Scripts/pyCreateTh/Lib/pytro2th/tro2th.py new file mode 100644 index 0000000..75dbd47 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/tro2th.py @@ -0,0 +1,501 @@ +######!/usr/bin/env python +# -*- coding: utf8 -*- +# coding: utf8 + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later +# Modifié Alex 2025 07 01 + +""" + !---------------------------------------------------------! + ! ! + ! Tro to Therion ! + ! ! + ! Code to transform the .tro files ! + ! Visual Topo into files that can ! + ! be used by Therion ! + ! ! + ! Written by Xavier Robert ! + ! ! + !---------------------------------------------------------! + + ENGLISH : + This code is to transform the .tro file from Visualtopo (http://vtopo.free.fr/) + into files that can be read by Therion (http://therion.speleo.sk/). + It reads .tro file and produce one .th file (file with survey data), + and one thconfig file (file that is used to compile and build the survey with Therion). + + TODOS : - Correct the errors in encodings... This is the most important.... + - Check all the situations possibles... + - Add title to the centerline ! +""" +# Do divisions with Reals, not with integers +# Must be at the beginning of the file +from __future__ import division +#from __future__ import unicode_literals +import sys, os, wget, logging + +from urllib.error import HTTPError + +# Import Python modules +#modulesNames = ['sys', 'warnings'] +#for module in modulesNames: +# try: +# # because we want to import using a variable, do it this way +# module_obj = __import__(module) +# # create a global object containging our module +# globals()[module] = module_obj +# except ImportError: +# sys.exit("ERROR : Module " + module + " not present. \n\n Please, install it \ +# \n\n Edit the source code for more information") + +from .buildparam import * +from .vtopotools import * +from .datathwritetools import * +from .buildthconfig import * + +from Lib.general_fonctions import Colors +import Lib.global_data as global_data + +log = logging.getLogger("Logger") + +################################################################################################# +def tro2th(fle_tro_fnme = None, fle_th_fnme = None, + fle_tro_encoding=None, + thlang = u'fr', + cavename = None, + icomments = True, icoupe = True, + ithconfig = True, istructure = True, thconfigfnme = None, + ithc = True, thcpath = None, thcfnme = u'config.thc', + sourcefile = None, xviscale = 1000, xvigrid = 10, scale = 500, + Errorfiles = True): + + """ + Main function to convert tro to th files. + This is this function that should be called from python. + + INPUTS: + fle_tro_fnme : (string) Path and name of the .tro file to convert. + if None (value by default), the function does not convert anything + but build .thconfig and config.thc files + If the path is not given, the function will look in the folder from where it is launched + fle_th_fnme : (string) Path and name of the .th file to create from the .tro file. + If None (value by default), this file is created from the .tro file name + and in the same folder than that .tro file + thlang : (string) String that set the language. 'fr' by default. + If you need english, change 'fr' to 'en' in the function definition + set 'fr' for french + set 'en' for english + ... other languages are not implemented + cavename : (string) Name of the cave. + If set to None (default value), it is get from the .tro file. + icomments : (Boolean) To add (True, by default) or not (False) comments in the produced files + icoupe : (Boolean) To set (True, by default) or not (False) an extended-elevation layout in the .thconfig file + ithconfig : (Boolean) To set if the thconfig file is created (True, by default) or not + istructure : (Boolean) To set if the structure and the addditional files are created (True, by default) or not + thconfigfnme : (string) Path and name of the thconfig file. + If None (by default), path and name build from the .tro file + ithc : (Boolean) To build (True, by default) or not (False) a config file config.thc + thcpath : (string) Path to the directry that contains the config file called in the cave.thconfig file. + If used with ithc = False, this path is only used for the declaration + in the cave.thconfig + If used with ithc = True, the config file will be written in that directory. + Set to None by default + thcfnme : (string) Name of the config.thc (value by default if set to None or if ommitted) + sourcefile : (list of strings) Define the source files declared in the cave.thconfig + ex :['example.th', 'example.th2', 'example-coupe.th2'] + If None or ommitted, it is build from the .tro file or the cavename + xviscale : (Real) Scale of the xvi file. + Set to 1000 by default that corresponds to 1/1000 + xvigrid : (Real) Spacing of the grid for the xvi, in meters. + Set 10 by default + scale : (Real) scale of the map + Set to 500 by default that corresponds to 1/500 + Errorfiles : (Boolean) If True (by default), an error will be raised if output files exists in the folder + If False, only a warning is raised, and the previous files are erased by the new ones. + Use with caution + + OUTPUTS: + Depending of the parameters inputed, several files can be produced + cavename.th : survey data for Therion + cavename.thconfig : file to build the pdf's maps and others + confgi.thc : config file for the .thconfig file. + + USAGE: + To build everything + tro2th(fle_tro_fnme = 'Test', fle_th_fnme = 'Test', + thlang = 'fr', + cavename = 'Test', + icomments = True, icoupe = True, + ithconfig = True, thconfigfnme = None, + ithc = True, thcpath = None, thcfnme = 'config.thc', + sourcefiles = None, xviscale = 1000, xvigrid = 10, scale = 500, + Errorfiles = True) + + To build only a .th file + tro2th(fle_tro_fnme = 'Test', fle_th_fnme = 'Test', + thlang = 'fr', + cavename = 'Test', + icomments = True, icoupe = True, + ithconfig = False + ithc = False + Errorfiles = True) + + To build only a thonfig file, in english, without any comments and without extended elevation layout + tro2th(thlang = 'en', + cavename = 'Test', + icomments = False, icoupe = False, + ithconfig = False, thconfigfnme = None, + ithc = False, thcpath = my/path/to/my/confg/file, thcfnme = 'config.thc', + sourcefiles = ['Test.th', 'Test.th2'], xviscale = 1000, xvigrid = 10, scale = 500, + Errorfiles = True) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + + if thlang in [u'fr', u'FR', u'Fr', u'fR']: thlang = u'fr' + elif thlang in [u'en',u'EN', u'En', u'eN']: thlang = u'en' + else: raise NameError(u'ERROR: Language %s not implemented\n' + u' Use "en" instead' % thlang ) + print(u'____________________________________________________________\n\n\t\tTRO 2 THERION\n____________________________________________________________\n') + if thlang == u'fr': + print(u'\nEcrit par Xavier Robert, Groupe spéléo Vulcain - Lyon, France\n') + elif thlang == u'en': + print(u'\nWritten by Xavier Robert, Groupe spéléo Vulcain - Lyon, France\n') + print(u'____________________________________________________________\n\n') + + coordsyst = None + coordinates = None + if fle_tro_fnme is not None: + if fle_tro_fnme[-4:] != u'.tro': + fle_tro_fnme = fle_tro_fnme + u'.tro' + # check if file exists + if os.path.isfile(fle_tro_fnme) == False : + if thlang == u'fr': raise NameError(u'ERROR : Le fichier {FileNa} n\'existe pas'.format(FileNa=str(fle_tro_fnme))) + elif thlang == u'en': raise NameError(u'ERROR : File {FileNa} does not exist'.format(FileNa=str(fle_tro_fnme))) + + if fle_th_fnme is None: + # convert tro file to th file + print('1') + cavename, coordinates, coordsyst, fle_th_fnme = convert_tro(fle_tro_fnme, fle_tro_encoding=fle_tro_encoding, + icomments = icomments, icoupe = icoupe, istructure = istructure, + thlang = thlang, Errorfiles = Errorfiles) + else: + print(2) + cavename, coordinates, coordsyst, fle_th_fnme = convert_tro(fle_tro_fnme, fle_th_fnme, cavename, + icomments = icomments, icoupe = icoupe, istructure = istructure, + thlang = thlang, Errorfiles = Errorfiles) + if thlang == u'fr': print(u'\tFichier Therion %s construit à partir des données %s' %(fle_th_fnme, fle_tro_fnme)) + elif thlang == u'en': print(u'\tFile %s built from %s' %(fle_th_fnme, fle_tro_fnme)) + else: + if thlang == u'fr': print(u'\tPas de fichier .tro en entrée, pas de fichier de données .th créé...') + elif thlang == u'en': print(u'\tNo .tro File input, no .th data file created...') + # Build here the new structure: + if istructure: build_structure(u'cave', Errorfiles = True) + + if sourcefile is None: + if fle_th_fnme is None: + if cavename is None: cavename = u'cave' + sourcefile = [cavename.replace(u' ', u'_') + u'.th', + u'#' + cavename.replace(u' ', u'_') + u'.th2', + u'#' + cavename.replace(u' ', u'_') + u'-coupe.th2'] + else: + sourcefile = [fle_th_fnme, u'#' + fle_th_fnme[0:-4] + u'th2', u'#' + fle_th_fnme[0:-4] + u'-coupe.th2' ] + # Build the dictionnary for the thconfig file + dictcave = [sourcefile, xviscale, xvigrid, cavename, coordsyst, scale] + + # build thc file + if ithc : + if thcpath is not None : + # Download the config file from my github page + try: + wget.download('https://raw.githubusercontent.com/robertxa/Th-Config-Xav/master/config.thc', + thcpath) + #thcpath + thcfnme) + except HTTPError: + if thcpath[-1] not in ['/', '\\']: thcpath = thcpath + '/' + writethc(thcpath + thcfnme, istructure) + except FileNotFoundError: + if thcpath[-1] not in ['/', '\\']: thcpath = thcpath + '/' + writethc(thcpath + thcfnme, istructure) + else: + # Download the config file from my github page + try: + if istructure: wget.download('https://raw.githubusercontent.com/robertxa/Th-Config-Xav/master/config.thc', + cavename.replace(u' ', u'_') + '/') + else: wget.download('https://raw.githubusercontent.com/robertxa/Th-Config-Xav/master/config.thc') + except HTTPError: + writethc(thcfnme, cavename, istructure) + except FileNotFoundError: + writethc(thcfnme, cavename, istructure) + + # build thconfig file + # Needs to be change to take in account istructure + if ithconfig : + # write the file + if thconfigfnme is None or thconfigfnme == u'' or thconfigfnme == u' ': + if fle_th_fnme is None: thconfigfnme = cavename.replace(u' ', u'_') + u'.thconfig' + else: thconfigfnme = fle_th_fnme[0:-3] + u'.thconfig' + + if thcpath is not None: + thcfnme = thcpath + thcfnme + writethconfig(cavename.replace(u' ', u'_') + thconfigfnme, icomments, icoupe, thlang, + dictcave, + ithc, thcfnme) + else: + thcfnme = thcfnme + writethconfig(cavename.replace(u' ', u'_') + thconfigfnme, icomments, icoupe, thlang, + dictcave, + ithc, cavename.replace(u' ', u'_') + u'/config.thc') + + if istructure: + # build cavename-tot.th file + f3w = open(cavename.replace(u' ', u'_') + '/' + cavename.replace(u' ', u'_') + '-tot.th', 'w') + write_thtot(f3w, cavename, icomments, thlang) + f3w.closed + print(u'\tFile ' + cavename.replace(u' ', u'_') + u'/' + cavename.replace(u' ', u'_') + u'-tot.th written...\n') + + # build cavename-maps.th file + f4w = open(cavename.replace(u' ', u'_') + u'/' + cavename.replace(u' ', u'_') + '-maps.th', 'w') + write_thmaps(f4w, cavename, icomments, thlang) + f4w.closed + print(u'\tFile ' + cavename.replace(u' ', u'_') + u'/' + cavename.replace(u' ', u'_') + u'-maps.th written...\n\n') + + # build Legends/entrances-coordinates.th file + f5w = open(cavename.replace(u' ', u'_') + '/Legends/entrances_coordinates.th', 'w') + write_thcoords(f5w, cavename, coordinates, coordsyst, icomments, thlang) + f5w.closed + print(u'\tFile ' + cavename.replace(u' ', u'_') + u'/Legends/entrances_coordinates.th written...\n\n') + + print(u'____________________________________________________________') + print(u'') + + return + + +################################################################################################# +def build_structure(cavename, Errorfiles = True): + """ + Check and build if needed the new structure: + -Cave/ + -Data/ + -cavename.th + (-cavename.th2) + -Legends/ + -entrances_coordinates.th + -Outputs/ + -outputs.txt + -Cavename.thconfig + -cavename-tot.th + -cavename-maps.th + -config.thc + + INPUTS: + cavename = name of the cave that is used to build all the folders and file structure + Errorfiles = Boolean; If True (Default), the program stops if the structure already exists + If False or none, if the structure exists, it is erased + + OUTPUTS: + None, except a new structure + + USAGE: + build_structure(cavename, Errorfiles) + + """ + + # check if the folder cavename/ exists + if os.path.exists(cavename.replace(u' ', u'_')): + if Errorfiles: + # Stop + raise NameError(u'ERROR : Folder {FileNa} does exist'.format(FileNa=str(cavename.replace(u' ', u'_')))) + else: + print(u'WARNING: I have erased folder %s' % cavename.replace(u' ', u'_')) + if not os.path.exists(cavename.replace(u' ', u'_') + u'/Data'): os.mkdir(cavename.replace(u' ', u'_') + u'/Data') + if not os.path.exists(cavename.replace(u' ', u'_') + u'/Legends'): os.mkdir(cavename.replace(u' ', u'_') + u'/Legends') + if not os.path.exists(cavename.replace(u' ', u'_') + u'/Outputs'): + os.mkdir(cavename.replace(u' ', u'_') + u'/Outputs') + # Add outputs.txt file + mkfle_output_txt(cavename.replace(u' ', u'_')) + # - if no, create it and create the other files + else: + # Create the subfolders + os.mkdir(cavename.replace(u' ', u'_')) + os.mkdir(cavename.replace(u' ', u'_') + u'/Data') + os.mkdir(cavename.replace(u' ', u'_') + u'/Outputs') + # Add outputs.txt file + mkfle_output_txt(cavename.replace(u' ', u'_')) + os.mkdir(cavename.replace(u' ', u'_') + u'/Legends') + + return + + +################################################################################################# +def mkfle_output_txt(cavename): + """ + Build the file Output.txt in the folder cavename/Outputs/ + + INPUTS: + cavename = name of the cave + + OUTPUTS: + None + + USAGE: + create_output_txt(cavename) + """ + # Open the cavename/Outputs/outputs.txt file + f1w = open(cavename.replace(u' ', u'_') + u'/Outputs/outputs.txt','w') + f1w.write(u'Folder where Therion outputs are exported \n\n') + # close the cavename/Outputs/outputs.txt file + f1w.closed + print(u'\tFile ' + cavename.replace(u' ', u'_') + u'/Outputs/outputs.txt written...') + + return + + +################################################################################################# +def convert_tro(fle_tro_fnme, fle_tro_encoding=None, fle_th_fnme = None, cavename = None, + icomments = True, icoupe = True, istructure = True, thlang = u'fr', Errorfiles = True): + """ + Function that manages the tro 2 th conversion + + INPUTS: + fle_tro_fnme : path and file name of the .tro file to convert + fle_th_fnme : path and file name of the .th file to create. + If ommitted, set to None, and this varaible will be set in function of the fle_tro_fnme or cavename + cavename : Name of the cave. If ommitted, it is set to None, and it is get from the .tro file + icomments : (Boolean) To add (True, by default) or not (False) comments in the produced files + icoupe : (Boolean) To set (True, by default) or not (False) an extended-elevation layout in the .thconfig file + istructure : (Boolean) To set if the structure and the addditional files are created (True, by default) or not + thlang : (string) String that set the language. 'fr' by default. + If you need english, change 'fr' to 'en' in the function definition + set 'fr' for french + set 'en' for english + + Errorfiles : True (by default if ommitted) to get an error if the .th file already exists. + False if only a warning... + OUTPUTS: + new .th file with surveyed data for Therion + cavename : Name of the cave from the .tro file + coordinates : Coordinates of the entrance + coordsyst : Coordinates system used by the .tro file + + USAGE: + cavename, coordsyst = convert_tro(fle_tro_fnme, [fle_th_fnme = fle_th_fnme, cavename = cavename, Errorfiles = Errorfiles]) + fle_th_fnme, cavename and Errorfiles can be ommitted. + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + + #from codecs import open + + # Initialization of some variables... + #xcoord=0. + #ycoord=0. + #alt=0. + + # open the .tro survey + if thlang == u'fr': log.info(f"Travail sur le fichier VisualTopo: {Colors.ENDC}{fle_tro_fnme}") + elif thlang == u'en':log.info(f"Processing VisualTopo file: {Colors.ENDC}{fle_tro_fnme}") + # print(' ') + fle_tro = open(fle_tro_fnme, 'r', encoding=fle_tro_encoding) + # read the .tro file + try: + lines = fle_tro.readlines() + # change the encoding + lines = convert_text(lines) + except UnicodeDecodeError: + # find the line where there is the error + # initiate the line number + lineNumber = 1 + try: + # read the first line + line = fle_tro.redline() + while line: + # update the line number + lineNumber += 1 + # read the next line + line = fle_tro.readline() + except UnicodeDecodeError: + log.error(f"Special or accentuated character not supporter line {Colors.ENDC}{lineNumber}{Colors.ERROR}, correct the input file") + global_data.error_count += 1 + + + + # read the header + coordinates = None + cavename, coordinates, coordsyst, club, entrance, versionfle = read_vtopo_header(lines) + + if cavename is None or cavename == '' or cavename == ' ': + cavename = u'cave' + + if fle_th_fnme is None: + fle_th_fnme = cavename.replace(u' ', u'_') + u'.th' + print (fle_th_fnme) + if fle_th_fnme[-3:] != u'.th': + fle_th_fnme = fle_th_fnme + u'.th' + + + # Build here the new structure: + if istructure: build_structure(cavename, Errorfiles) + + # check if file exists... + checkfiles(fle_th_fnme, Errorfiles) + + # open the .th file + if istructure: fle_th = open (cavename.replace(u' ', u'_') + '/Data/' + fle_th_fnme, 'w') + else: fle_th = open (fle_th_fnme, 'w') + # write the .th header + writeheader_th(fle_th, cavename, entrance) + + # initiate variables + i = 0 + iline = [] + dataold = [] + + # get line numbers of the lines beginning with 'Param' + for line in lines: + if u'Param' in line: iline.append(i) + i+=1 + + for j in iline: + # read the settings of the survey + settings, comments = read_settings(lines[j].replace(u'\n', u'')) + + # read the data from the tro file + data = read_data(lines, settings, j, iline) + + # write centerline header + writecenterlineheader(fle_th, entrance, settings, comments, data, coordsyst, coordinates, club, + icomments, thlang) + + # write the data to the .th file + writedata(fle_th, settings, data, dataold) + + # write the end of the centerline in the .th file + fle_th.write(u'\n\tendcenterline\n\n') + dataold = data + # write the end of the survey in the .th file + fle_th.write(u'\nendsurvey\n') + fle_th.close + + #print (fle_th_fnme) + + if thlang == u'fr': log.info(f"Fichier Therion {Colors.ENDC}{fle_th_fnme}{Colors.INFO} écrit !") + elif thlang == u'en': log.info(f"Therion file {Colors.ENDC}{fle_th_fnme}{Colors.INFO} written!") + + return cavename, coordinates, coordsyst, fle_th_fnme + + +################################################################################################# +if __name__ == u'__main__': + + + # initiate variables + + # run the transformation + tro2th() diff --git a/Scripts/pyCreateTh/Lib/pytro2th/vtopotools.py b/Scripts/pyCreateTh/Lib/pytro2th/vtopotools.py new file mode 100644 index 0000000..af70239 --- /dev/null +++ b/Scripts/pyCreateTh/Lib/pytro2th/vtopotools.py @@ -0,0 +1,304 @@ +######!/usr/bin/env python +# -*- coding: utf-8 -*- +# coding: utf8 + +# Copyright (c) 2020 Xavier Robert +# SPDX-License-Identifier: GPL-3.0-or-later +# Modifié Alex 2025 07 01 + +""" + Functions to work on vtopo data to be able to write them in the Therion format + By Xavier Robert + Lima, 2016.06.21 + + USAGE : + - They are normally used by other scripts + + + INPUTS: + The inputs are in the script file, in the "# Define data to analysis" section. + The different arguments are described. + +""" + +###### To DO : ####### +# - Take in account the 'I' (extended elevation) inverse option in vtopo file --> set extend right/left +###### End To DO ####### + +from __future__ import division +# This to be sure that the result of the division of integers is a real, not an integer +#from __future__ import unicode_literals + +# Import modules +import sys, os + +############################################################################ +def read_vtopo_header(lines): + """ + Function to read header from vtopofile + + INPUTS: + lines: file .tro read by the fonction lines = readlines(file_vtopo) + + OUTPUTS (all are strings): + cavename : Name of the cave + coordinates : Entrance coordinates + coordsyst : Coordinates system to set the entrance coordinates + club : Name of the group that explored the cave + entrance : Entrance of the cave + versionfle : Vtopo version that has been used to produce the vtopofile + + USAGE: + cavename, coordinates, coordsyst, club, entrance, versionfle = read_vtopo_header(lines) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + + # coord_dict: French Lambert system. To find number of your system, see extern/proj4/nad/epsg + # file in the therion source distribution. You can add your own lines/systems + # [Note alex: ajout des systèmes compatibles VTopo] + coord_dict = { + u'SWISS' : u'EPSG:21780', + u'LT72' : u'EPSG:31300', + u'LT93' : u'EPSG:2154', + u'LT1' : u'EPSG:27571', + u'LT2' : u'EPSG:27572', + u'LT2E' : u'EPSG:27572', + u'LT3' : u'EPSG:27573', + u'LT4' : u'EPSG:27574', + u'UTM30' : u'EPSG:32630', + u'UTM31' : u'EPSG:32631', + u'UTM32' : u'EPSG:32632', + u'UTM42' : u'EPSG:32642', + u'UTM30E' : u'EPSG:23030', + u'UTM31E' : u'EPSG:23031', + u'UTM32E' : u'EPSG:23032' + } + + cavename = '' + club = '' + coordtro = '' + coordinates = ["0.0", "0.0", "0.0"] + + for line in lines: + if u"Version" in line: + versionfle = line[1].replace(u'\n', u'').rstrip(u'\n\r').split(' ') + if u'Trou' in line: + # read Trou + (cavename, xcoord, ycoord, alt, coordtro) = line[5:].replace(u'\n', u'').rstrip(u'\n\r').split(u',') + coordinates = [xcoord, ycoord, alt] + # read club + if u'Club' in line: club = line[5:].replace(u'\n', u'') + # read entrance name + if u'Entree' in line : entrance = line[7:].replace(u'\n', u'') + + if coordtro in coord_dict: + # Rewrite the coordinate system to be read by Therion + # French Lambert system. To find number of your system, see extern/proj4/nad/epsg file in the therion source distribution. You can add you own lines/systems + coordsyst = coord_dict[coordtro] + else: + coordsyst = None + + return cavename, coordinates, coordsyst, club, entrance, versionfle + + +############################################################################ +def read_settings(line): + """ + Function to read the line that define the settings of the survey session : + intruments, directions, units, calibrations,... + + INPUTS: + line : string extractd from the .tro file that contains the information on the survey session + + OUTPUTS: + settings : list of strings with all the measurments settings + comments : string that correspond to the end of the string "Line" + that do not correspond to the settings + USAGE: + settings, comments = read_settings(line) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + # Question: Do we have to update the code in function of the vtopo version number? + param = line[6:].rstrip(u'\n\r').split(u' ') + k = 9 + #k = 6 + if 'Topof' in param[:k]: + k = k + 1 + + if 'Prof' in param[:k] or 'Deniv' in param[:k]: + k = k - 1 + + # Transformation de l'avant-dernier champ s'il correspond à une date jj/mm/aaaa + if '/' in param[k-1] : + try: + jj, mm, aaaa = param[k-1].split('/') + param[k-1] = f"{aaaa} {mm} {jj}" + except ValueError: + pass # ne rien faire si la date est mal formée + + settings = param[:k] + #commentst = param[k+2:] + commentst = param[k:] + comments = " ".join(str(elem) for elem in commentst) + + #ucomments=comments.decode('us-ascii', errors = 'replace') + #print ucomments + + return settings, comments#.encode('utf-8', errors = "replace") + + +############################################################################ +def read_data(lines, settings, j, iline): + """ + Function to read the data from the line + + INPUTS: + lines : file .tro read by the fonction lines = readlines(file_vtopo) + settings : list of strings with all the measurments settings; + output of the function read_settings + j : number of the line that corresponds to the settings line in the list "lines" + iline : list of line numbers that correspond to the different settings line in the list "lines" + + OUTPUTS: + data : list of lists of data (string format) + + USAGE: + data = read_data(lines, settings, j, iline) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + + data = [] + # check if we are at the end of the iline file or not ! + if iline.index(j) < len(iline)-1: + for i in range(j+1, iline[iline.index(j)+1]): + datal = [x for x in lines[i].replace(u'\n', u'').rstrip(u'\n\r').split(u' ') if x != u''] + data.append(datal) + else: + i = j+1 + while 1: + if 'Configuration' in lines[i]: + break + else: + datal = [x for x in lines[i].replace(u'\n', u'').rstrip('\n\r').split(u' ') if x != u''] + data.append(datal) + i+=1 + # remove white lines in datao + data = [x for x in data if x != []] + + return data + + +############################################################################ +def convert_text(lines): + """ + Fonction to convert characters encoding... + The problem is that .tro files are encode with strange Windows settings, + and the accentuation is not well understood by other systems + + Bug, that is not working well + + INPUTS: + lines : + OUTPUTS: + + + USAGE: + lines = convert_text(lines) + + Author: Xavier Robert, Lima 2016/06/27 + + Licence: CCby-nc + """ + dictcaract ={'\xe8' : u'è', + '\xe0' : u'à', + '\xe9' : u'é', + '\xe0' : u'à', + '\xf9' : u'ù', + '\xea' : u'ê', + '\xeb' : u'ë', + '\xf1' : u'ñ', + '\xfb' : u'û', + '\xee' : u'î', + '\xef' : u'ï'} + + for line in lines: + #for line in lines.decode('cp1252'): + #line = line.decode('cp1252') + # windows = latin-1 ? cp-1252 ? cp1252 ? mbcs ? + for elem in dictcaract: + #print line + if elem in line: + line = line.replace(elem, dictcaract[elem]) + + return lines + + +############################################################################ +if __name__ == u"__main__": + """ + Function to test sub-functions + """ + from datathwritetools import writeheader_th, writecenterlineheader, writedata + + fle_tro_fnme = u'Test.tro' + fle_th_fnme = u'test.th' + icomments = True + thlang = u'fr' + cavename = u'cave' + + # open tro file + fle_tro = open(fle_tro_fnme, u'rU') + # open new th file + fle_th = open(cavename.replace(u' ', u'_') + '/Data/' + fle_th_fnme, u'w') + + # read the tro file + lines = fle_tro.readlines() + lines = convert_text(lines) + + # read the header + #cavename, coordinates, coordtro, club, entrance = read_vtopo_header(fle_tro) + cavename, coordinates, coordsyst, club, entrance, versionfle = read_vtopo_header(lines) + + writeheader_th(fle_th, cavename, entrance) + + # read line to line and find the Param + i = 0 + iline = [] + dataold = [] + + # get line numbers of the lines beginning with 'Param' + for line in lines: + #print i + #print i, line.replace('\n', '') + if u'Param' in line: iline.append(i) + i+=1 + + for j in iline: + # read the settings of the survey + settings, comments = read_settings(lines[j].replace(u'\n', u'')) + data = read_data(lines, settings, j, iline) + + # write centerline header + writecenterlineheader(fle_th, entrance, settings, comments, data, coordsyst, coordinates, club, + icomments, thlang) + # write the data to the .th file + writedata(fle_th, settings, data, dataold) + + fle_th.write(u'\n\tendcenterline\n') + dataold = data + + + fle_th.write(u'\nendsurvey\n') + + fle_tro.close + fle_th.close + diff --git a/Scripts/pyCreateTh/Lib/therion.py b/Scripts/pyCreateTh/Lib/therion.py index 3936a19..ba4a50b 100644 --- a/Scripts/pyCreateTh/Lib/therion.py +++ b/Scripts/pyCreateTh/Lib/therion.py @@ -7,7 +7,7 @@ therion.py for pyCreateTh.py import tempfile, shutil, os, re, logging, threading, subprocess from os.path import join import Lib.global_data as global_data -from Lib.general_fonctions import Colors, safe_relpath +from Lib.general_fonctions import Colors log = logging.getLogger("Logger") diff --git a/Scripts/pyCreateTh/README.md b/Scripts/pyCreateTh/README.md deleted file mode 100644 index c00ddca..0000000 --- a/Scripts/pyCreateTh/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Scripts pour Therion -==================== - -pyMaktoTh ---------- - - -En Java : https://github.com/rogerschuster/compass2therion -Format des fichiers compass : https://fountainware.com/compass/Documents/FileFormats/FileFormats.htm diff --git a/Scripts/pyCreateTh/__pycache__/pyCreateTh.cpython-313.pyc b/Scripts/pyCreateTh/__pycache__/pyCreateTh.cpython-313.pyc index 48391b0bc9e2afe405ff901eeeb0f96b85a58be5..1e51bba0a69db3ad421189da22538d32b2bb8140 100644 GIT binary patch literal 146918 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%0DlTuPX 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 literal 89991 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 diff --git a/Scripts/pyCreateTh/pyCreateTh.py b/Scripts/pyCreateTh/pyCreateTh.py index af22f4c..389a4ff 100644 --- a/Scripts/pyCreateTh/pyCreateTh.py +++ b/Scripts/pyCreateTh/pyCreateTh.py @@ -2,7 +2,11 @@ """ ############################################################################################# # # -# Script pour convertir des données topographiques des formats .th .mak ou .dat de compass # +# Script pour convertir des données topographiques des formats # +# .th de Therion (brut, sans les dossiers) # +# .mak ou .dat de compass # +# .tro de visual topo # +# # # au format th et th2 de Therion # # by Alexandre PONT (alexandre_pont@yahoo.fr) # # # @@ -13,30 +17,36 @@ # # ############################################################################################# -Création Alex le 2025 06 09 : - -Version 2025 06 16 : Création fonction create_th_folders - Ajout des fonctions pour mak et dat - +Merci à : + - Tanguy Racine pour les scripts https://github.com/tr1813 + - Xavier Robert pour les principes de base https://github.com/robertxa + - Xavier Robert pour les scripts de conversion .tro https://github.com/robertxa/pytherion + - Benoit Urruty https://github.com/BenoitURRUTY + +Sources documentaires : + - Format des fichiers compass : https://fountainware.com/compass/Documents/FileFormats/FileFormats.htm + + +Création Alex le 2025 06 09 + En cours : - - trouver une solution pour les teams et les clubs manquants - - tester la nouvelle version de DAT (CORRECTION2 et suivants) + - 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....) - - intégrer .tro files d'après XRo - ajouter codes pour lat/long - créer fonction wall shot pour faire habillage des th2 files, les jointures... - traiter les series avec 1 ou 2 stations - - fiabiliser ! - PB des cartouches et des échelles pour faire des pdf automatiquement - - gérer les différentes options --proj (All, Plan, ....) adapter + - gérer les différentes options --proj (All, Plan, ....) + - tester différentes version pour les fichiers .tro """ -Version = "2025.06.26" +Version = "2025.07.01" ################################################################################################# ################################################################################################# -import os, re, unicodedata, argparse, shutil, sys, time, math +import os, re, argparse, shutil, sys, time, math from os.path import isfile, join, abspath, splitext import numpy as np import networkx as nx @@ -50,8 +60,10 @@ from contextlib import redirect_stdout from Lib.survey import SurveyLoader, NoSurveysFoundException from Lib.therion import compile_template, compile_file, get_stats_from_log -from Lib.general_fonctions import setup_logger, Colors, safe_relpath, colored_help, read_config, select_file_tk_window, release_log_file +from Lib.general_fonctions import setup_logger, Colors, safe_relpath, colored_help +from Lib.general_fonctions import read_config, select_file_tk_window, release_log_file, sanitize_filename import Lib.global_data as globalData +from Lib.pytro2th.tro2th import convert_tro #Version local modifiée ################################################################################################# @@ -78,43 +90,6 @@ class StationNameAccessor: ) -################################################################################################# -# Mise au format des noms # -################################################################################################# -def sanitize_filename(th_name): - """ - Cleans a string to make it compatible with filenames on Windows, Linux, and macOS. - Replaces special and accented characters with compatible characters. - Replaces parentheses with underscores and enforces proper casing. - - Args: - th_name (str): The filename to clean. - - Returns: - str: The cleaned and compatible string. - - """ - # Unicode normalization to replace accented characters with their non-accented equivalents - th_name = unicodedata.normalize('NFKD', th_name).encode('ASCII', 'ignore').decode('ASCII') - - # Replace parentheses with underscores - th_name = th_name.replace('(', '_').replace(')', '_') - - # Replace illegal characters with an underscore - th_name = re.sub(r'[<>:"/\\|?*\']', '_', th_name) # Illegal on Windows - th_name = re.sub(r'\s+', '_', th_name) # Spaces to underscores - th_name = re.sub(r'[^a-zA-Z0-9._-]', '_', th_name) # Keep only allowed chars - - # Convert to lowercase, then capitalize the first letter - # th_name = th_name.lower().capitalize() - # th_name = th_name.capitalize() - - # Suppression des underscores en début et fin - th_name = th_name.strip('_') - - return th_name or "default_filename" # Avoid empty result - - ################################################################################################# def copy_template_if_not_exists(template_path, destination_path): # Check if the destination folder exists @@ -122,7 +97,7 @@ def copy_template_if_not_exists(template_path, destination_path): if not os.path.exists(destination_path): # If the destination folder does not exist, copy the template shutil.copytree(template_path, destination_path) - log.info(f"The folder '{Colors.ENDC}{template_path}{Colors.GREEN}' has been copied to '{Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN}'") + log.info(f"The folder {Colors.ENDC}{template_path}{Colors.GREEN} has been copied to {Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN}") else: log.warning(f"The folder '{Colors.ENDC}{safe_relpath(destination_path)}{Colors.WARNING}' already exists. No files were copied.") except Exception as e: @@ -154,14 +129,15 @@ def copy_file_with_copyright(th_file, destination_path, copyright_text): # Créer le dossier de destination s'il n'existe pas os.makedirs(destination_path, exist_ok=True) + _destFile = sanitize_filename(os.path.basename(th_file)[:-3]) + ".th" # Copier le fichier vers le dossier de destination - dest_file = os.path.join(destination_path, os.path.basename(th_file)) + dest_file = os.path.join(destination_path, _destFile) shutil.copy(th_file, dest_file) # Ajouter le copyright dans l'en-tête si nécessaire add_copyright_header(dest_file, copyright_text) - log.debug(f"File '{Colors.ENDC}{safe_relpath(th_file)}{Colors.GREEN}' has been copied to '{Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN}' with the copyright header added.{Colors.ENDC}") + log.debug(f"File {Colors.ENDC}{safe_relpath(th_file)}{Colors.GREEN} has been copied to {Colors.ENDC}{safe_relpath(destination_path)}{Colors.GREEN} with the copyright header added.{Colors.ENDC}") else: log.error(f"The file .th does not exist {Colors.ENDC}{safe_relpath(th_file)}") globalData.error_count += 1 @@ -218,7 +194,7 @@ def update_template_files(template_path, variables, output_path): ################################################################################################# -def parse_therion_surveys(file_path): +def parse_therion_surveysOld(file_path): """ Reads a Therion file and extracts survey names. @@ -259,9 +235,52 @@ def parse_therion_surveys(file_path): log.error(f"An error occurred (parse_therion_surveys): {Colors.ENDC}{e}{Colors.ERROR}, file: {Colors.ENDC}{safe_relpath(file_path)}") globalData.error_count += 1 - return survey_names +def parse_therion_surveys(file_path): + """ + Reads a Therion file and extracts survey names. + + Args: + file_path (str): Path to the Therion file to parse + + Returns: + list: List of survey names + + """ + + survey_names = [] + + try: + file, val, encodage = load_text_file_utf8(file_path, os.path.basename(file_path)) + # lines = file.readlines() + lines = file.splitlines() + # with open(filepath, 'r', encoding=enc) as f: + # content = f.read() + + for line in lines: + # Look for lines starting with survey + line = line.strip() + if line.startswith('survey ') and ' -title ' in line: + # Split the line and extract the survey name + start_index = line.find('survey ') + len('survey ') + end_index = line.find(' -title ') + survey_name = line[start_index:end_index].strip() + survey_names.append(survey_name) + + except FileNotFoundError: + log.error(f"File {Colors.ENDC}{safe_relpath(file_path)}{Colors.ERROR} not found.{Colors.ENDC}") + globalData.error_count += 1 + + except PermissionError: + log.error(f"Insufficient permissions to read {Colors.ENDC}{safe_relpath(file_path)}") + globalData.error_count += 1 + + except Exception as e: + log.error(f"An error occurred (parse_therion_surveys): {Colors.ENDC}{e}{Colors.ERROR}, file: {Colors.ENDC}{safe_relpath(file_path)}") + globalData.error_count += 1 + + return survey_names ################################################################################################# def str_to_bool(value): @@ -1202,7 +1221,7 @@ def create_th_folders(ENTRY_FILE, else : th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi" - log.info(f"Parsing extended XVI file:\t{Colors.ENDC}{safe_relpath(th_name_xvi)}") + log.info(f"Parsing extended XVI file: {Colors.ENDC}{safe_relpath(th_name_xvi)}") # Parse the Extended XVI file stations = {} @@ -2360,9 +2379,9 @@ def load_text_file_utf8(filepath, short_filename): try: with open(filepath, 'r', encoding=enc) as f: content = f.read() - log.info(f"Source file: {Colors.ENDC}{short_filename}{Colors.GREEN}, encoding: {Colors.ENDC}{enc}{Colors.GREEN}, conversion to UTF-8") - message = f"* Source file: {short_filename}, encoding: {enc}, conversion to UTF-8\n" - return content, message + log.info(f"Source file: {Colors.ENDC}{short_filename}{Colors.GREEN}, encoding: {Colors.ENDC}{enc}{Colors.GREEN}, conversion to {Colors.ENDC}utf-8") + message = f"* Source file: {short_filename}, encoding: {enc}, conversion to utf-8\n" + return content, message, enc except UnicodeDecodeError as e: log.debug(f"Failed {Colors.ENDC}{enc}{Colors.DEBUG} for {Colors.ENDC}{short_filename}{Colors.DEBUG}: {Colors.ENDC}{e}") @@ -2371,7 +2390,7 @@ def load_text_file_utf8(filepath, short_filename): except Exception as e: log.critical(f"Unexpected error while reading {Colors.ENDC}{short_filename}{Colors.CRITICAL}: {e}") exit(0) - return None, "" + return None, "", None # Dernier recours : lecture binaire + forçage try: @@ -2380,12 +2399,12 @@ def load_text_file_utf8(filepath, short_filename): content = raw.decode('windows-1252', errors='replace') log.warning(f"Force-reading {Colors.ENDC}{short_filename}{Colors.WARNING} with character replacement (windows-1252)") message = f"* Force-reading source file: {short_filename} with character replacement (windows-1252)\n" - return content, message + return content, message, 'windows-1252' except Exception as e: log.critical(f"Failed to read file {Colors.ENDC}{short_filename}{Colors.CRITICAL}: {Colors.ENDC}{e}") exit(0) - return None, "" + return None, "", None ################################################################################################# @@ -2416,7 +2435,7 @@ def dat_to_th_files (ENTRY_FILE, fixPoints = [], crs_wkt = "", CONFIG_PATH = "", # 1 : Lecture du fichier dat # ################################################################################################# - content, totReadMe = load_text_file_utf8(ENTRY_FILE, shortCurentFile) + content, totReadMe, enc = load_text_file_utf8(ENTRY_FILE, shortCurentFile) ################################################################################################# # Séparer les sections # @@ -2916,10 +2935,10 @@ if __name__ == u'__main__': # Parse arguments # ################################################################################################# parser = argparse.ArgumentParser( - description=f"{Colors.BLUE}Create a skeleton folder and th, th2 files with scraps from *.mak, *.dat, *.th Therion files, version: {Colors.ENDC}{Version}\n", + description=f"{Colors.BLUE}Create a skeleton folder and th, th2 files with scraps from *.tro, *.mak, *.dat, *.th Therion files, version: {Colors.ENDC}{Version}\n", formatter_class=argparse.RawDescriptionHelpFormatter) parser.print_help = colored_help.__get__(parser) - parser.add_argument("--file", help="the file (*.th, *.mak, *.dat,) to perform e.g. './Therion_file.th'", default="") + 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") @@ -2977,7 +2996,7 @@ if __name__ == u'__main__': # titre # ################################################################################################# _titre =[f'********************************************************************************************************************************************\033[0m', - f'* Conversion Th, Dat, Mak files to Therion files and folders', + f'* Conversion Th, Dat, Mak, Tro, files to Therion files and folders', f'* Script pyCreateTh by : {Colors.ENDC}alexandre.pont@yahoo.fr', f'* Version : {Colors.ENDC}{Version}', f'* Input file : {Colors.ENDC}{safe_relpath(args.file)}', @@ -2990,8 +3009,6 @@ if __name__ == u'__main__': for i in range(11): log.info(_titre[i]) - - ################################################################################################# # Fichier TH # @@ -3034,7 +3051,7 @@ if __name__ == u'__main__': ABS_file = abspath(args.file) - content, val = load_text_file_utf8(ABS_file, os.path.basename(ABS_file)) + content, val, enc = load_text_file_utf8(ABS_file, os.path.basename(ABS_file)) section = content.split('\x0c') QtySections += len(section) @@ -3071,11 +3088,61 @@ if __name__ == u'__main__': threads += thread2 bar() + ################################################################################################# + # Fichier TRO # + ################################################################################################# + elif args.file[-3:].lower() == "tro" : + + SrcFile = abspath(args.file) + DestFile = SrcFile[:-4] # + "Th" + + source_content, val, encodage = load_text_file_utf8(SrcFile, os.path.basename(SrcFile)) + + fileTitle, coordinates, coordsyst, fle_th_fnme = convert_tro( + fle_tro_fnme = SrcFile, + fle_tro_encoding= encodage, + fle_th_fnme = DestFile, + cavename = None, + icomments = True, + icoupe = False, + istructure = False, + thlang = None, + Errorfiles = False + ) + + # print(f"cavename: {fileTitle}") + # print(f"coordinates: {coordinates}") + # print(f"coordsyst: {coordsyst}") + # print(f"fle_th_fnme: {fle_th_fnme}") + + content, val, encodage = load_text_file_utf8(fle_th_fnme, os.path.basename(fle_th_fnme)) + + if encodage != "utf-8": + with open(str(fle_th_fnme), "w+", encoding="utf-8") as f: + f.write(content) + + with open(fle_th_fnme, 'a', encoding='utf-8') as file: + file.write("\n\n") + for line in source_content.splitlines(): + file.write(f"# {line}\n") + + + flagErrorCompile, stat, totReadMeError, thread2 = create_th_folders( + ENTRY_FILE = fle_th_fnme, + TARGET = None, + PROJECTION= args.proj, + SCALE = args.scale, + UPDATE = args.update, + CONFIG_PATH = "") + threads += thread2 + fileTitle = sanitize_filename(os.path.basename(fle_th_fnme)[:-3]) + + if os.path.isfile(fle_th_fnme): + os.remove(fle_th_fnme) + else : log.error(f"file {Colors.ENDC}{safe_relpath(args.file)}{Colors.ERROR} not yet supported") globalData.error_count += 1 - - duration = (datetime.now() - start_time).total_seconds() for t in threads: t.join() @@ -3086,6 +3153,8 @@ if __name__ == u'__main__': wait_until_file_is_released(output_log) + duration = (datetime.now() - start_time).total_seconds() + if globalData.error_count == 0 : log.info(f"All files processed successfully in {Colors.ENDC}{duration:.2f}{Colors.INFO} secondes, without errors") else : @@ -3101,5 +3170,8 @@ if __name__ == u'__main__': shutil.move(output_log, destination_path) + print(output_log) + print(destination_path) + \ No newline at end of file diff --git a/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace b/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace index 1fc21c2..f2e7e5c 100644 --- a/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace +++ b/Scripts/pyCreateTh/pyCreateTh_VSCode.code-workspace @@ -9,28 +9,38 @@ "australiangeodetic", "australiangeodeticdatum", "backclino", + "buildparam", + "buildthconfig", "cavename", "clarke", "clino", "colwidth", "datat", + "datathwritetools", "ecart", "ENDC", "endlayout", "endscrap", "etrs", "european", + "fnme", "geocentricdatumofaustralia", "geocentricofaustralia", + "icomments", "Makto", "northamerican", "northamericandatum", "nouvelletriangulationfrançaise", + "pytro", "roth", "thanksto", "thconfig", "therion", + "vtopo", + "vtopofile", + "vtopotools", "wpage", + "writecenterlineheader", "XTHERION" ] }