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 0db41ef..22e7d38 100644 Binary files a/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc and b/Scripts/pyCreateTh/Lib/__pycache__/general_fonctions.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc index d056df6..acda215 100644 Binary files a/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc and b/Scripts/pyCreateTh/Lib/__pycache__/therion.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/general_fonctions.py b/Scripts/pyCreateTh/Lib/general_fonctions.py index b98f7b3..c292747 100644 --- a/Scripts/pyCreateTh/Lib/general_fonctions.py +++ b/Scripts/pyCreateTh/Lib/general_fonctions.py @@ -3,11 +3,13 @@ general_fonctions.py for pyCreateTh.py ############################################################################################# """ -import os, logging, sys, re, configparser +import os, logging, sys, re, configparser, unicodedata import Lib.global_data as global_data import tkinter as tk from tkinter import filedialog + + ################################################################################################# # Couleurs ANSI par niveau de log ################################################################################################# @@ -114,6 +116,43 @@ def colored_help(parser): sys.exit(1) +################################################################################################# +# 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 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 0000000..4aa8fc4 Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/__init__.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/_version.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/_version.cpython-313.pyc new file mode 100644 index 0000000..909b344 Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/_version.cpython-313.pyc differ 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 0000000..6949845 Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildparam.cpython-313.pyc differ diff --git a/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildthconfig.cpython-313.pyc b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildthconfig.cpython-313.pyc new file mode 100644 index 0000000..c6a7cfd Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/buildthconfig.cpython-313.pyc differ 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 0000000..6d0353d Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/datathwritetools.cpython-313.pyc differ 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 0000000..35eae6b Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/tro2th.cpython-313.pyc differ 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 0000000..ef1a773 Binary files /dev/null and b/Scripts/pyCreateTh/Lib/pytro2th/__pycache__/vtopotools.cpython-313.pyc differ 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 48391b0..1e51bba 100644 Binary files a/Scripts/pyCreateTh/__pycache__/pyCreateTh.cpython-313.pyc and b/Scripts/pyCreateTh/__pycache__/pyCreateTh.cpython-313.pyc differ 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" ] }