mirror of
https://github.com/Alex38Lyon/Synthese-PSM_LARRA.git
synced 2026-06-01 13:59:13 +00:00
pyCreateTh
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7412
-7412
File diff suppressed because one or more lines are too long
Binary file not shown.
+7412
-7412
File diff suppressed because one or more lines are too long
+140
-140
File diff suppressed because one or more lines are too long
Binary file not shown.
+19629
-19629
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
set xth(ctrl,cp,datlist) {}
|
||||||
|
xth_cp_data_tree_insert 1 {} 0 "" "" "length: 0.00m (surface 0.00m, duplicated 0.00m)"
|
||||||
|
xth_cp_data_tree_create
|
||||||
|
set xth(ctrl,cp,maplist) {}
|
||||||
|
xth_cp_map_tree_insert projection 0 p1 {} 0 plan {} {} {}
|
||||||
|
xth_cp_map_tree_create
|
||||||
|
xth_cp_comp_stat 0 0
|
||||||
|
set xth(th_exit_state) 2
|
||||||
|
set xth(th_exit_number) 1749133569
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 8.4 MiB |
@@ -0,0 +1,76 @@
|
|||||||
|
encoding utf-8
|
||||||
|
# Fichier thCongig poour créer un fichier lox de la en UTM30ED50
|
||||||
|
|
||||||
|
|
||||||
|
# Copyright (C) ARSIP 2025 https://www.arsip.fr/
|
||||||
|
# Auteur : Alexandre Pont <alexandre.pont***@***yahoo.fr>
|
||||||
|
# Fichiers / Organisation dossiers, d'après Xavier Robert
|
||||||
|
# This work is under the Creative Commons Attribution-NonCommercial-NoDerivatives License:
|
||||||
|
# <http://creativecommons.org/licenses/by-nc-nd/4.0/>
|
||||||
|
|
||||||
|
# INTRO
|
||||||
|
|
||||||
|
# le signe "#" en début de ligne signifie que la ligne est commentée. Elle ne
|
||||||
|
# sera donc pas lue lors de la compilation.
|
||||||
|
|
||||||
|
# Dans ce fichier on met les specifications generales, à savoir
|
||||||
|
# dans quel fichier sont les donnees topo, l'aspect que l'on veut
|
||||||
|
# donner aux topos imprimées (layout) et ce que l'on
|
||||||
|
# veut comme résultat : map, ou atlas ou 3D ou donnees en format SQL
|
||||||
|
|
||||||
|
# Alors, on peut fractionner ce fichier en trois parts:
|
||||||
|
# - source, pour specifier les fichiers ou sont les données topo/dessin
|
||||||
|
# - layout, pour specifier la composition du document à imprimer
|
||||||
|
# - export: map, atlas, etc
|
||||||
|
|
||||||
|
|
||||||
|
# 1-SOURCES
|
||||||
|
# La ligne source spécifie le fichier ou sont les donnees topo
|
||||||
|
# jb.th". (Au fichier "jb.th" il faudra avoir une ligne
|
||||||
|
# "input "nomducavite.th2" pour specifier le fichier ou se trouvent
|
||||||
|
# les donnees du dessin, comme ça, ce fichier thconfig appellera
|
||||||
|
# "jb.th" et a leur tour, "jb.th" appellera
|
||||||
|
# "jb-dessin.th2")
|
||||||
|
# source Synthese-PSM_LARRA-tot.th
|
||||||
|
|
||||||
|
# pour le MNT avec une résolution spaciale de 1" STRM10
|
||||||
|
source DEM_SRTM30_UTM30_PSM.th
|
||||||
|
|
||||||
|
# Add Coordinates
|
||||||
|
#input Legendes/entrances_coordinates.th
|
||||||
|
|
||||||
|
# Add config file
|
||||||
|
|
||||||
|
# 2-LAYOUT
|
||||||
|
# Ici, on peut specifier des choses comme les symboles à utiliser (UIS, etc)
|
||||||
|
# ou imprimer des explications des symboles
|
||||||
|
|
||||||
|
|
||||||
|
# 3-EXPORT
|
||||||
|
|
||||||
|
# Export des xvi pour le dessin si besoin
|
||||||
|
#export map -fmt xvi -layout xviexport -o Data/Complexe_Lonne_Peyret-Bourrugues-map.xvi
|
||||||
|
#export map -proj extended -layout xviexport -fmt xvi -o Data/Complexe_Lonne_Peyret-Bourrugues-coupe.xvi
|
||||||
|
|
||||||
|
|
||||||
|
# Export des fichiers pdf, plan et coupe.
|
||||||
|
# ATTENTION, la topo étant énorme, il faut mettre l'option ne traçant pas la centerline !
|
||||||
|
# export map -projection plan -fmt pdf -layout my_layout -o Outputs/Synthese-PSM_LARRA-Plan.pdf
|
||||||
|
# export map -projection extended -fmt pdf -layout layout-coupe -o Outputs/GL102_Puits-Coupe.pdf
|
||||||
|
|
||||||
|
|
||||||
|
# Export du fichier 3d pour Loch
|
||||||
|
|
||||||
|
cs EPSG:23030 # UTTM30 ED50
|
||||||
|
export model -enable all -o Surface_PSM_LARRA_UTM30ED50.lox
|
||||||
|
|
||||||
|
# Export de la database sql
|
||||||
|
# export des statistiques de l'ensemble de la cavité
|
||||||
|
# Attention, les points de départ et d'arrivée de chaque centreline correspondent
|
||||||
|
# au second point et à l'avant dernier point de la série.
|
||||||
|
|
||||||
|
|
||||||
|
# Export des fichiers ESRI
|
||||||
|
|
||||||
|
|
||||||
|
# Export des fichiers kml
|
||||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
|||||||
|
therion 6.3.3 (2025-01-06)
|
||||||
|
- using Proj 9.4.1, compiled against 9.4.1
|
||||||
|
initialization file: C:\Program Files\Therion/therion.ini
|
||||||
|
reading ... done
|
||||||
|
configuration file: Surface_PSM_LARRA.thconfig
|
||||||
|
reading ... done
|
||||||
|
reading source files ... done
|
||||||
|
preprocessing database ... done
|
||||||
|
output coordinate system: EPSG:23030
|
||||||
|
meridian convergence (deg): -1.5117
|
||||||
|
scanning centreline tree ... done
|
||||||
|
searching for centerline loops ... done
|
||||||
|
calculating station coordinates ... done
|
||||||
|
processing survey data ... no data.
|
||||||
|
calculating basic statistics ... done
|
||||||
|
processing extended elevation ... done
|
||||||
|
processing references ... done
|
||||||
|
selecting export objects ... done
|
||||||
|
writing Surface_PSM_LARRA_UTM30ED50.lox ...
|
||||||
|
processing projection plan ... done
|
||||||
|
done
|
||||||
|
writing xtherion file ... done
|
||||||
|
compilation time: 1 sec
|
||||||
|
|
||||||
|
############# CRS transformations chosen by PROJ ###############
|
||||||
|
Area of Use (AoU): (-0.902, 42.840) (-0.601, 43.050)
|
||||||
|
[UTM30 → LAT-LONG] AoU: [no] transformation: [Inverse of UTM zone 30N + axis order change (2D)] definition: [proj=pipeline step inv proj=utm zone=30 ellps=WGS84 step proj=unitconvert xy_in=rad xy_out=deg] accuracy: [0.000 m]
|
||||||
|
[UTM30 → EPSG:23030] AoU: [yes] transformation: [Inverse of UTM zone 30N + Inverse of ED50 to WGS 84 (41) + UTM zone 30N] definition: [proj=pipeline step inv proj=utm zone=30 ellps=WGS84 step inv proj=hgridshift grids=es_ign_SPED2ETV2.tif step proj=utm zone=30 ellps=intl] accuracy: [1.000 m]
|
||||||
|
[EPSG:4326 → EPSG:23030] AoU: [yes] transformation: [axis order change (2D) + Inverse of ED50 to WGS 84 (41) + UTM zone 30N] definition: [proj=pipeline step proj=unitconvert xy_in=deg xy_out=rad step inv proj=hgridshift grids=es_ign_SPED2ETV2.tif step proj=utm zone=30 ellps=intl] accuracy: [1.000 m]
|
||||||
|
[EPSG:23030 → EPSG:4326] AoU: [yes] transformation: [Inverse of UTM zone 30N + ED50 to WGS 84 (41) + axis order change (2D)] definition: [proj=pipeline step inv proj=utm zone=30 ellps=intl step proj=hgridshift grids=es_ign_SPED2ETV2.tif step proj=unitconvert xy_in=rad xy_out=deg] accuracy: [1.000 m]
|
||||||
|
########## end of CRS transformations chosen by PROJ ###########
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"annee",
|
||||||
|
"ansi",
|
||||||
|
"australiangeodetic",
|
||||||
|
"australiangeodeticdatum",
|
||||||
|
"backclino",
|
||||||
|
"backcompass",
|
||||||
|
"beijing",
|
||||||
|
"cavename",
|
||||||
|
"clarke",
|
||||||
|
"clino",
|
||||||
|
"CLINO",
|
||||||
|
"cumcount",
|
||||||
|
"datat",
|
||||||
|
"depmatch",
|
||||||
|
"depthre",
|
||||||
|
"downcasting",
|
||||||
|
"drawnexemptextendedre",
|
||||||
|
"drawnexemptplanre",
|
||||||
|
"drawnexemptre",
|
||||||
|
"drawnre",
|
||||||
|
"ecart",
|
||||||
|
"ENDC",
|
||||||
|
"endlayout",
|
||||||
|
"endscrap",
|
||||||
|
"endsurvey",
|
||||||
|
"equats",
|
||||||
|
"etrs",
|
||||||
|
"ETRS",
|
||||||
|
"european",
|
||||||
|
"explo",
|
||||||
|
"formated",
|
||||||
|
"geocentricdatumofaustralia",
|
||||||
|
"geocentricofaustralia",
|
||||||
|
"Geophysicaya",
|
||||||
|
"isin",
|
||||||
|
"Koef",
|
||||||
|
"lengthre",
|
||||||
|
"lenmatch",
|
||||||
|
"levelname",
|
||||||
|
"levelno",
|
||||||
|
"migovec",
|
||||||
|
"NODRAW",
|
||||||
|
"northamerican",
|
||||||
|
"northamericandatum",
|
||||||
|
"nouvelletriangulationfrançaise",
|
||||||
|
"pulkovo",
|
||||||
|
"sinfo",
|
||||||
|
"sirgas",
|
||||||
|
"southamerican",
|
||||||
|
"southamericandatum",
|
||||||
|
"syscoord",
|
||||||
|
"tendcenterline",
|
||||||
|
"thanksto",
|
||||||
|
"thconfig",
|
||||||
|
"therion",
|
||||||
|
"totdata",
|
||||||
|
"wpage",
|
||||||
|
"XTHERION"
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,67 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Couleurs ANSI par niveau de log
|
||||||
|
COLOR_CODES = {
|
||||||
|
logging.DEBUG: "\033[94m", # Bleu
|
||||||
|
logging.INFO: "\033[92m", # Vert
|
||||||
|
logging.WARNING: "\033[95m",
|
||||||
|
logging.ERROR: "\033[91m", # Rouge
|
||||||
|
logging.CRITICAL: "\033[1;91m", # Rouge vif
|
||||||
|
}
|
||||||
|
RESET = "\033[0m"
|
||||||
|
|
||||||
|
# Supprime les codes ANSI (pour l'écriture dans les fichiers)
|
||||||
|
def strip_ansi_codes(text):
|
||||||
|
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
||||||
|
return ansi_escape.sub('', text)
|
||||||
|
|
||||||
|
# Formatter pour la console avec couleurs
|
||||||
|
class ConsoleFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
color = COLOR_CODES.get(record.levelno, "")
|
||||||
|
message = super().format(record)
|
||||||
|
return f"{color}{message}{RESET}"
|
||||||
|
|
||||||
|
# Formatter pour le fichier avec "!!!" sur les erreurs
|
||||||
|
class FileFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
clean_msg = strip_ansi_codes(record.getMessage())
|
||||||
|
prefix = "!!! " if record.levelno >= logging.ERROR else ""
|
||||||
|
record_copy = logging.LogRecord(
|
||||||
|
name=record.name,
|
||||||
|
level=record.levelno,
|
||||||
|
pathname=record.pathname,
|
||||||
|
lineno=record.lineno,
|
||||||
|
msg=f"{prefix}{clean_msg}",
|
||||||
|
args=(),
|
||||||
|
exc_info=record.exc_info,
|
||||||
|
func=record.funcName,
|
||||||
|
sinfo=record.stack_info
|
||||||
|
)
|
||||||
|
return super().format(record_copy)
|
||||||
|
|
||||||
|
# Fonction de configuration du logger
|
||||||
|
def setup_logger(logfile="app.log", debug_log=False):
|
||||||
|
logger = logging.getLogger("Logger")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
logger.handlers.clear()
|
||||||
|
|
||||||
|
min_level = logging.DEBUG if debug_log else logging.INFO
|
||||||
|
|
||||||
|
# Console handler
|
||||||
|
console_handler = logging.StreamHandler(sys.stdout)
|
||||||
|
console_handler.setLevel(min_level)
|
||||||
|
console_formatter = ConsoleFormatter("%(levelname)s: %(message)s")
|
||||||
|
console_handler.setFormatter(console_formatter)
|
||||||
|
logger.addHandler(console_handler)
|
||||||
|
|
||||||
|
# File handler
|
||||||
|
file_handler = logging.FileHandler(logfile, encoding="utf-8")
|
||||||
|
file_handler.setLevel(min_level)
|
||||||
|
file_formatter = FileFormatter("%(asctime)s - %(levelname)s - %(message)s")
|
||||||
|
file_handler.setFormatter(file_formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
return logger
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
import re
|
||||||
|
from os.path import dirname, abspath, join
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
file_path_reg = r"(?:\n|^)\s*###filepath:(.*)"
|
||||||
|
input_reg = r"(?:\n|^)\s*(?:input|source)\s+\"?([^\s\"]+)?"
|
||||||
|
survey_reg = r"(?:\n|^)\s*survey\s+(\S+)"
|
||||||
|
end_survey_reg = r"(?:\n|^)\s*endsurvey"
|
||||||
|
scrap_reg = r"(?:\n|^)\s*scrap\s+(\S+)"
|
||||||
|
end_scrap_reg = r"(?:\n|^)\s*endscrap"
|
||||||
|
projection_reg = r"(?:\n|^).*-projection\s+(\S+)"
|
||||||
|
drawnre = re.compile(r".*line wall")
|
||||||
|
drawnexemptre = re.compile(r".*NODRAW")
|
||||||
|
drawnexemptplanre = re.compile(r".*NODRAW PLAN")
|
||||||
|
drawnexemptextendedre = re.compile(r".*NODRAW EE")
|
||||||
|
|
||||||
|
|
||||||
|
class NoSurveysFoundException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleSurveyFoundException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Scrap:
|
||||||
|
id = None
|
||||||
|
projection = None
|
||||||
|
data = None
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
def __init__(self, id, parent, projection):
|
||||||
|
self.id = id
|
||||||
|
self.projection = projection
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
def is_drawn(self):
|
||||||
|
if not self.data:
|
||||||
|
return False
|
||||||
|
for line in self.data:
|
||||||
|
match = drawnre.match(line)
|
||||||
|
if match:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Survey:
|
||||||
|
parent = None
|
||||||
|
file_path = None
|
||||||
|
id = None
|
||||||
|
children = []
|
||||||
|
data = None
|
||||||
|
scraps = []
|
||||||
|
plan_drawn_override = False
|
||||||
|
extended_drawn_override = False
|
||||||
|
|
||||||
|
def __init__(self, id, parent, file_path):
|
||||||
|
self.id = id
|
||||||
|
self.parent = parent
|
||||||
|
self.file_path = file_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def therion_id(self):
|
||||||
|
if len(self.id) == 1:
|
||||||
|
return self.id[0]
|
||||||
|
return "{}@{}".format(self.name, self.namespace)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.id[-1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def namespace(self):
|
||||||
|
return ".".join(list(reversed(self.id[0:-1])))
|
||||||
|
|
||||||
|
def data(self, data):
|
||||||
|
self._data = data
|
||||||
|
self.scraps = Survey.parse(self)
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
scraps = []
|
||||||
|
scrap = None
|
||||||
|
data = []
|
||||||
|
for index, line in enumerate(self.data):
|
||||||
|
match = re.match(scrap_reg, line)
|
||||||
|
if match:
|
||||||
|
id = self.id + [match.group(1)]
|
||||||
|
projection = "plan"
|
||||||
|
match = re.match(projection_reg, line)
|
||||||
|
if match:
|
||||||
|
projection = match.group(1)
|
||||||
|
scrap = Scrap(id[:], self, projection)
|
||||||
|
scraps = scraps + [scrap]
|
||||||
|
|
||||||
|
data = [line]
|
||||||
|
continue
|
||||||
|
match = re.match(end_scrap_reg, line)
|
||||||
|
if match:
|
||||||
|
id = self.id
|
||||||
|
data = data + [line]
|
||||||
|
scrap.data = data[:]
|
||||||
|
data = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Exempt drawing
|
||||||
|
match = drawnexemptplanre.match(line)
|
||||||
|
if match:
|
||||||
|
self.plan_drawn_override = True
|
||||||
|
match = drawnexemptextendedre.match(line)
|
||||||
|
if match:
|
||||||
|
self.extended_drawn_override = True
|
||||||
|
match = drawnexemptre.match(line)
|
||||||
|
if match:
|
||||||
|
self.plan_drawn_override = True
|
||||||
|
self.extended_drawn_override = True
|
||||||
|
|
||||||
|
data = data + [line]
|
||||||
|
self.scraps = scraps
|
||||||
|
|
||||||
|
|
||||||
|
class SurveyLoader:
|
||||||
|
_data = None
|
||||||
|
survey = None
|
||||||
|
surveys = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def surveys_list(self):
|
||||||
|
return list(self.surveys.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def base_surveys(self):
|
||||||
|
return [s for s in self.surveys_list if len(s.children) == 0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load(file_path):
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
data = f.read()
|
||||||
|
lines = []
|
||||||
|
for line in data.splitlines():
|
||||||
|
if not line.strip():
|
||||||
|
continue
|
||||||
|
# if line.lstrip().startswith("#"):
|
||||||
|
# continue
|
||||||
|
match = re.match(input_reg, line)
|
||||||
|
if match:
|
||||||
|
new_file_path = abspath(join(dirname(file_path), match.group(1)))
|
||||||
|
lines = lines + ["###filepath:{}".format(new_file_path)]
|
||||||
|
lines = lines + ["\t{}".format(l) for l in SurveyLoader.load(new_file_path)]
|
||||||
|
lines = lines + ["###filepath:{}".format(file_path)]
|
||||||
|
else:
|
||||||
|
lines.append(line.strip())
|
||||||
|
return lines
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse(lines, orig_file_path=None):
|
||||||
|
surveys = {}
|
||||||
|
id = []
|
||||||
|
file_path = orig_file_path
|
||||||
|
parent = None
|
||||||
|
survey = None
|
||||||
|
data = []
|
||||||
|
|
||||||
|
for index, line in enumerate(lines):
|
||||||
|
match = re.match(file_path_reg, line)
|
||||||
|
if match:
|
||||||
|
file_path = match.group(1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = re.match(survey_reg, line)
|
||||||
|
if match:
|
||||||
|
id = id + [match.group(1)]
|
||||||
|
parent = survey
|
||||||
|
survey = Survey(id[:], parent, file_path)
|
||||||
|
surveys[".".join(id[:])] = survey
|
||||||
|
if parent:
|
||||||
|
parent.data = data[:]
|
||||||
|
parent.children = parent.children + [survey]
|
||||||
|
data = [line]
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = re.match(end_survey_reg, line)
|
||||||
|
if match:
|
||||||
|
popped = id.pop()
|
||||||
|
data = data + [line]
|
||||||
|
survey.data = data[:]
|
||||||
|
if len(survey.children) == 0:
|
||||||
|
survey.parse()
|
||||||
|
if not survey.parent:
|
||||||
|
return survey, surveys
|
||||||
|
parent.data = parent.data + data
|
||||||
|
data = parent.data[:]
|
||||||
|
parent = survey.parent
|
||||||
|
survey = parent
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
data = data + [line]
|
||||||
|
return parent, surveys
|
||||||
|
|
||||||
|
def __init__(self, file_path):
|
||||||
|
# print(f"\033[32mDebug SurveyLoader.load : \033[0m {file_path}")
|
||||||
|
self._data = SurveyLoader.load(file_path)
|
||||||
|
survey, surveys = SurveyLoader.parse(self._data, file_path)
|
||||||
|
self.survey = survey
|
||||||
|
self.surveys = surveys
|
||||||
|
|
||||||
|
def get_survey_by_id(self, therion_id):
|
||||||
|
id = []
|
||||||
|
if "@" in therion_id:
|
||||||
|
parts = therion_id.split("@")
|
||||||
|
id = list(reversed(parts[1].split("."))) + [parts[0]]
|
||||||
|
else:
|
||||||
|
id = list(reversed(therion_id.split(".")))
|
||||||
|
key = ".".join(id)
|
||||||
|
if key in self.surveys:
|
||||||
|
return self.surveys[key]
|
||||||
|
else:
|
||||||
|
potential_key = [k for k in self.surveys.keys() if k.endswith(".{}".format(key))]
|
||||||
|
if len(potential_key) == 1:
|
||||||
|
return self.surveys[potential_key[0]]
|
||||||
|
potential_keys = [k for k in self.surveys.keys() if key in k]
|
||||||
|
if len(potential_keys) == 1:
|
||||||
|
return self.surveys[potential_keys[0]]
|
||||||
|
elif len(potential_keys) > 1:
|
||||||
|
raise MultipleSurveyFoundException("Multiple surveys were found with that key:\n\t{}".format("\n\t".join(potential_keys)))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Parse a survey")
|
||||||
|
parser.add_argument(
|
||||||
|
"survey_file",
|
||||||
|
help='The survey file (*.th) to work from. e.g. "data/system_migovec.th"',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"survey_selector",
|
||||||
|
help='The selector for the survey to produce a scrap for. e.g. "roundpond@vrtnarija.vrtnarija_vilinska.system_migovec"',
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
entrypoint = abspath(args.survey_file)
|
||||||
|
loader = SurveyLoader(entrypoint)
|
||||||
|
print(loader.get_survey_by_id(args.survey_selector))
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
from os.path import join
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
|
||||||
|
log = logging.getLogger("Logger")
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Codes de couleur ANSI
|
||||||
|
class Colors:
|
||||||
|
BLACK = '\033[90m'
|
||||||
|
RED = '\033[91m'
|
||||||
|
GREEN = '\033[92m'
|
||||||
|
YELLOW = '\033[93m'
|
||||||
|
BLUE = '\033[94m'
|
||||||
|
MAGENTA = '\033[95m'
|
||||||
|
CYAN = '\033[96m'
|
||||||
|
WHITE = '\033[97m'
|
||||||
|
|
||||||
|
ERROR = '\033[91m'
|
||||||
|
WARNING = '\033[95m'
|
||||||
|
HEADER = '\033[96m'
|
||||||
|
DEBUG = '\033[94m' # Bleu
|
||||||
|
INFO = '\033[92m' # Vert
|
||||||
|
CRITICAL = '\033[1;91m', # Rouge vif
|
||||||
|
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def compile_template(template, template_args, **kwargs):
|
||||||
|
global error_count
|
||||||
|
|
||||||
|
try :
|
||||||
|
logfile = ""
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
config = template.format(**template_args, tmpdir=tmpdir.replace("\\", "/"))
|
||||||
|
|
||||||
|
log.debug(f"{config}\n")
|
||||||
|
|
||||||
|
config_file = join(tmpdir, "config.thconfig")
|
||||||
|
log_file = join(tmpdir, "log.log")
|
||||||
|
therion_path = kwargs["therion_path"] if "therion_path" in kwargs else "therion"
|
||||||
|
with open(config_file, mode="w+", encoding="utf-8") as tmp:
|
||||||
|
with open(log_file, mode="w+") as tmp2:
|
||||||
|
tmp.write(config)
|
||||||
|
tmp.flush()
|
||||||
|
subprocess.check_output('''"{}" "{}" -l "{}"'''.format(therion_path, config_file, log_file), shell=True, )
|
||||||
|
tmp2.flush()
|
||||||
|
logfile = tmp2.read()
|
||||||
|
if kwargs["cleanup"]:
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
log.debug("\n" )
|
||||||
|
return logfile, tmpdir
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Therion template compilation error: {Colors.ENDC}{e}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
def compile_template2(template, template_args, **kwargs):
|
||||||
|
global error_count
|
||||||
|
|
||||||
|
logfile = ""
|
||||||
|
tmpdir = None
|
||||||
|
try:
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
config = template.format(**template_args, tmpdir=tmpdir.replace("\\", "/"))
|
||||||
|
|
||||||
|
log.debug(f"{config}\n")
|
||||||
|
|
||||||
|
config_file = join(tmpdir, "config.thconfig")
|
||||||
|
log_file = join(tmpdir, "log.log")
|
||||||
|
|
||||||
|
therion_path = kwargs.get("therion_path", "therion")
|
||||||
|
|
||||||
|
# Écriture des fichiers config + log
|
||||||
|
with open(config_file, "w", encoding="utf-8") as tmp:
|
||||||
|
tmp.write(config)
|
||||||
|
tmp.flush()
|
||||||
|
|
||||||
|
# Exécution de Therion
|
||||||
|
result = subprocess.run(
|
||||||
|
[therion_path, config_file, "-l", log_file],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True, # Décode automatiquement en UTF-8 (avec fallback ci-dessous)
|
||||||
|
timeout=kwargs.get("timeout", 60),
|
||||||
|
errors="replace" # Remplace caractères invalides (évite UnicodeDecodeError)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Lecture du log (en mode tolérant)
|
||||||
|
try:
|
||||||
|
with open(log_file, "r", encoding="cp1252", errors="replace") as f:
|
||||||
|
logfile = f.read()
|
||||||
|
except Exception as log_err:
|
||||||
|
log.warning(f"Could not read Therion log: {Colors.ENDC}{log_err}")
|
||||||
|
|
||||||
|
# Analyse du code retour
|
||||||
|
if result.returncode != 0:
|
||||||
|
log.error(f"Therion compilation failed with return code {Colors.ENDC}{result.returncode} {Colors.ERROR}{result.stdout}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
log.info(f"Therion compilation successful")
|
||||||
|
|
||||||
|
return logfile, tmpdir
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
log.error(f"Therion process timed out and was terminated")
|
||||||
|
error_count += 1
|
||||||
|
return "Therion timeout", tmpdir
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Therion template compilation error: {Colors.ENDC}{e}")
|
||||||
|
error_count += 1
|
||||||
|
return str(e), tmpdir
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if kwargs.get("cleanup", True) and tmpdir:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
except Exception as cleanup_err:
|
||||||
|
log.warning(f"Could not delete temp directory: {Colors.ENDC}{cleanup_err}")
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def compile_file(filename, **kwargs):
|
||||||
|
global error_count
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmpdir = os.path.dirname(filename)
|
||||||
|
log_file = join(tmpdir, "therion.log").replace("\\", "/")
|
||||||
|
therion_path = kwargs["therion_path"] if "therion_path" in kwargs else "therion"
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[therion_path, filename, "-l", log_file],
|
||||||
|
cwd=tmpdir,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT, # fusion stdout + stderr
|
||||||
|
universal_newlines=True, # décodage automatique en texte
|
||||||
|
bufsize=1 # ligne par ligne
|
||||||
|
)
|
||||||
|
|
||||||
|
log.info(f"Start therion compilation file : {Colors.ENDC}~\\{os.path.relpath(filename)}")
|
||||||
|
# Lecture en temps réel
|
||||||
|
for line in process.stdout:
|
||||||
|
line = line.rstrip()
|
||||||
|
lower_line = line.lower()
|
||||||
|
if "error" in lower_line:
|
||||||
|
log.error(f" [Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
elif "warning" in lower_line:
|
||||||
|
log.warning(f" [Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
else:
|
||||||
|
log.debug(f" [Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
# Si la commande échoue, result.returncode sera non nul
|
||||||
|
if process.returncode != 0:
|
||||||
|
# Affichage des erreurs et de la sortie standard
|
||||||
|
log.error(f"Error during Therion compilation, stderr : \n{Colors.ENDC}{process.stderr.decode()}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
log.info(f"Therion file : {Colors.ENDC}~\\{os.path.relpath(filename)}{Colors.GREEN} succeeded")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Therion file {Colors.ENDC}~\\{os.path.relpath(filename, os.path.expanduser('~'))}{Colors.ERROR} compilation error: {Colors.ENDC}{e}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def compile_file2(filename, **kwargs):
|
||||||
|
global error_count
|
||||||
|
|
||||||
|
tmpdir = os.path.dirname(filename)
|
||||||
|
log_file = join(tmpdir, "therion.log").replace("\\", "/")
|
||||||
|
therion_path = kwargs.get("therion_path", "therion")
|
||||||
|
timeout = kwargs.get("timeout", 60) # seconds
|
||||||
|
|
||||||
|
log.info(f"Start therion compilation file : {Colors.WHITE}{filename}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Lancement du processus Therion
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[therion_path, filename, "-l", log_file],
|
||||||
|
cwd=tmpdir,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
universal_newlines=True,
|
||||||
|
bufsize=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fonction de lecture en temps réel (dans un thread séparé)
|
||||||
|
def read_output(proc):
|
||||||
|
try:
|
||||||
|
for line in proc.stdout:
|
||||||
|
line = line.rstrip()
|
||||||
|
lower_line = line.lower()
|
||||||
|
if "error" in lower_line:
|
||||||
|
log.error(f"[Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
elif "warning" in lower_line:
|
||||||
|
log.warning(f" [Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
else:
|
||||||
|
log.debug(f" [Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(f"Reading Therion output: {Colors.ENDC}{e}")
|
||||||
|
|
||||||
|
# Démarrage du thread de lecture
|
||||||
|
output_thread = threading.Thread(target=read_output, args=(process,))
|
||||||
|
output_thread.start()
|
||||||
|
|
||||||
|
# Attente avec timeout
|
||||||
|
output_thread.join(timeout)
|
||||||
|
if output_thread.is_alive():
|
||||||
|
log.error(f"Therion compilation timed out after {Colors.ENDC}{timeout}{Colors.ERROR} seconds. Killing process...")
|
||||||
|
error_count += 1
|
||||||
|
process.kill()
|
||||||
|
output_thread.join()
|
||||||
|
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
# Vérification du code de retour
|
||||||
|
if process.returncode != 0:
|
||||||
|
log.error(f"Therion returned error code {Colors.ENDC}{process.returncode}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
log.info(f"Therion file : {Colors.ENDC}~\\{os.path.relpath(filename)}{Colors.GREEN} compilation succeeded")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Therion file {Colors.ENDC}~\\{os.path.relpath(filename)}{Colors.ERROR} compilation error: {Colors.ENDC}{e}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def compile_file_th(filepath, **kwargs):
|
||||||
|
template = """source {filepath}
|
||||||
|
layout test
|
||||||
|
scale 1 500
|
||||||
|
endlayout
|
||||||
|
"""
|
||||||
|
template_args = {"filepath": filepath}
|
||||||
|
logs, _ = compile_template(template, template_args, cleanup=True, **kwargs)
|
||||||
|
return logs
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Attention fonctionne pour la version therion en français ! à voir pour les autres langues
|
||||||
|
lengthre = re.compile(r".*Longueur totale de la topographie = \s*(\S+)m")
|
||||||
|
depthre = re.compile(r".*Longueur totale verticale =\s*(\S+)m")
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def get_stats_from_log(log):
|
||||||
|
lenmatch = lengthre.findall(log)
|
||||||
|
depmatch = depthre.findall(log)
|
||||||
|
if len(lenmatch) == 1 and len(depmatch) == 1:
|
||||||
|
return {"length": lenmatch[0], "depth": depmatch[0]}
|
||||||
|
return {"length": 0, "depth": 0}
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
syscoord = re.compile(r".*output coordinate system: \s*(\S+)")
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def get_syscoord_from_log(log):
|
||||||
|
lenmatch = syscoord.findall(log)
|
||||||
|
|
||||||
|
if len(lenmatch) == 1:
|
||||||
|
return {"syscoord": lenmatch[0]}
|
||||||
|
return {"syscoord": 0}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Scripts pour Therion
|
||||||
|
====================
|
||||||
|
|
||||||
|
pyMaktoTh
|
||||||
|
---------
|
||||||
|
|
||||||
|
|
||||||
|
En Java : https://github.com/rogerschuster/compass2therion
|
||||||
|
Format des fichiers compass : https://fountainware.com/compass/Documents/FileFormats/FileFormats.htm
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Folder where Therion outputs are exported
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
|||||||
|
encoding utf-8
|
||||||
|
{file_info}
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
|
||||||
|
map MP-{fileName}-Plan-tot -title "{fileName}"
|
||||||
|
{other_scraps_plan}
|
||||||
|
endmap
|
||||||
|
|
||||||
|
map MC-{fileName}-Extended-tot -title "{fileName}"
|
||||||
|
{other_scraps_extended}
|
||||||
|
endmap
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
encoding utf-8
|
||||||
|
{file_info}
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
|
||||||
|
to add this survey in a main survey add in your -tot.th file:
|
||||||
|
|
||||||
|
input Data/{fileName}/{fileName}-tot.th
|
||||||
|
equate
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
encoding utf-8
|
||||||
|
{file_info}
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
|
||||||
|
survey {fileName} -title "{fileName}"
|
||||||
|
{totData}
|
||||||
|
endsurvey
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
encoding utf-8
|
||||||
|
{file_info}
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
|
||||||
|
## INTRO
|
||||||
|
|
||||||
|
## Le signe "#" en début de ligne signifie que la ligne est commentée. Elle ne
|
||||||
|
## sera donc pas lue lors de la compilation.
|
||||||
|
|
||||||
|
## Dans ce fichier on met les specifications generales, à savoir
|
||||||
|
## dans quel fichier sont les donnees topo, l'aspect que l'on veut
|
||||||
|
## donner aux topos imprimées (layout) et ce que l'on
|
||||||
|
## veut comme résultat : map, ou atlas ou 3D ou donnees en format SQL
|
||||||
|
|
||||||
|
## Alors, on peut fractionner ce fichier en trois parts:
|
||||||
|
## - source, pour specifier les fichiers ou sont les données topo/dessin
|
||||||
|
## - layout, pour specifier la composition du document à imprimer
|
||||||
|
## - export: map, atlas, etc
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
## 1-SOURCES
|
||||||
|
###############################################################################################
|
||||||
|
## La ligne source spécifie le fichier ou sont les donnees topo
|
||||||
|
## jb.th". (Au fichier "jb.th" il faudra avoir une ligne
|
||||||
|
## "input "nomducavite.th2" pour specifier le fichier ou se trouvent
|
||||||
|
## les donnees du dessin, comme ça, ce fichier thconfig appellera
|
||||||
|
## "jb.th" et a leur tour, "jb.th" appellera
|
||||||
|
## "jb-dessin.th2")
|
||||||
|
|
||||||
|
source {fileName}-tot.th
|
||||||
|
|
||||||
|
## Add config file
|
||||||
|
input config.thc
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
## 2-LAYOUT
|
||||||
|
###############################################################################################
|
||||||
|
## Ici, on peut specifier des choses comme les symboles à utiliser (UIS, etc)
|
||||||
|
## ou imprimer des explications des symboles
|
||||||
|
|
||||||
|
## Début de la définition du Layout "xviexport"
|
||||||
|
layout xviexport
|
||||||
|
#cs UTM32
|
||||||
|
## echelle à laquelle on veut dessiner la topo
|
||||||
|
scale 1 {Scale}
|
||||||
|
#scale 1 1000
|
||||||
|
## taille de la grille
|
||||||
|
grid-size 2 2 2 m
|
||||||
|
## mettre la grille en arrière plan
|
||||||
|
grid bottom
|
||||||
|
endlayout
|
||||||
|
## fin de la définition du layout "xviexport"
|
||||||
|
|
||||||
|
## Début de la définition du layout "Layout-Plan"
|
||||||
|
layout layout-Plan
|
||||||
|
## Call the config settings (Layout config inside the config.thc file)
|
||||||
|
copy fonts_1000
|
||||||
|
copy drawingconfig
|
||||||
|
#copy layoutcontinuation # Pour afficher le label des continuations
|
||||||
|
copy headerl
|
||||||
|
copy langue-fr
|
||||||
|
|
||||||
|
## Définition du système de projection du plan
|
||||||
|
cs {cs}
|
||||||
|
|
||||||
|
## La ligne base-scale spécifie l'échelle auquel nous avons dessiné nos croquis.
|
||||||
|
## Par défaut, Therion pense que c'est une échelle 1:200. Si on a utilisé une autre échelle,
|
||||||
|
## il faut enlever le "#" et spécifier l'échelle vraiment employée, comme c'est le cas
|
||||||
|
## après avoir dessiné la topo sur un cheminement exporté avec le layout "xviexport".
|
||||||
|
## Jouer avec le ration base-scale/scale permet de jouer globalement sur les tailles
|
||||||
|
## des caractères et des traits.
|
||||||
|
base-scale 1 {Scale}
|
||||||
|
|
||||||
|
## Maintenant on va mettre une ligne "scale" pour specifier l'échelle pour imprimer la topo.
|
||||||
|
## La combination entre scale et base-scale contrôle l'épaisseur des lignes, rotation, etc, convenable
|
||||||
|
## pour faire l'ampliation-réduction entre dessin et le résultat de l'imprimante
|
||||||
|
## C'est tres important s'assurer que la configuration de l'imprimante ne spécifie pas l'option "Fit in page"
|
||||||
|
## ou similaire, sinon, l'échelle sera changée pendant l'impression!
|
||||||
|
scale 1 {Scale}
|
||||||
|
|
||||||
|
## Echelle graphique 100 m ampleur (Généralement, le choix scale/10 est plutôt pas mal)
|
||||||
|
scale-bar 100 m
|
||||||
|
|
||||||
|
## Voici une ligne pour specifier qu'il faut imprimer une grille au dessous de la topo
|
||||||
|
grid bottom
|
||||||
|
|
||||||
|
## Défini la rotation de la topographie
|
||||||
|
#rotate -65
|
||||||
|
|
||||||
|
## Une ligne pour specifier que la grille est 1000x1000x1000 m
|
||||||
|
## (Trois dimensions, oui, ça sert pour la coupe aussi)
|
||||||
|
grid-size 50 50 50 m
|
||||||
|
|
||||||
|
## la topo est transparente (on peut voir les galeries en dessous)
|
||||||
|
## C'est on par défaut, donc, pas vraiment besoin de specifier
|
||||||
|
transparency on
|
||||||
|
|
||||||
|
## Couleurs de la topographie
|
||||||
|
#colour map-bg [70 90 70]
|
||||||
|
#colour map-fg [100 100 80]
|
||||||
|
#colour map-fg altitude
|
||||||
|
#colour map-fg explo-date
|
||||||
|
#colour map-fg topo-date
|
||||||
|
#colour map-fg map
|
||||||
|
#colour map-fg scrap
|
||||||
|
#colour-legend off
|
||||||
|
colour map-fg 90
|
||||||
|
|
||||||
|
## ça marche seulement si transparency est "on" 90% blanc= 10% noir
|
||||||
|
opacity 75
|
||||||
|
#surface bottom
|
||||||
|
#surface-opacity 100
|
||||||
|
|
||||||
|
## Auteur
|
||||||
|
doc-author "{Author}"
|
||||||
|
## Titre
|
||||||
|
doc-title "{cavename} Plan - 1:{Scale}"
|
||||||
|
doc-subject "{cavename}, topographie en plan"
|
||||||
|
doc-keywords "Cave, Survey, {cavename}, Pierre saint Martin - Larra, {map_comment}"
|
||||||
|
|
||||||
|
## Maintenant on spécifie la position de la manchette, dont l'intérieur est occupé par le titre, auteurs, etc.
|
||||||
|
## Nous pouvons indiquer les cordonnées du point de la topo ou l'on veut la manchette :
|
||||||
|
## 0 0, c'est en bas, à gauche, 100 100, c'est en haut, à droite
|
||||||
|
## La manchette a des "points cardinaux" autour : n, s, ne, sw, etc.
|
||||||
|
## Il faut specifier un de ces points comme ce que sera placé sur les cordonnées.
|
||||||
|
## Alors nous pouvons specifier que le sud-ouest de la manchette soit placé en bas, a gauche,
|
||||||
|
## ou une autre combination...
|
||||||
|
map-header 2 98 nw
|
||||||
|
|
||||||
|
## arrière plan de la manchette
|
||||||
|
map-header-bg on
|
||||||
|
## Légende pour expliciter les symboles. "on" imprimera seulement la légende des symboles dessinés
|
||||||
|
## sur la topo. Si l'on veut pour tous les symboles, utilisés ou pas, il faut indiquer "all".
|
||||||
|
## "legend off" = pas de légende
|
||||||
|
legend on
|
||||||
|
## Par défaut, la légende est de 14 cm de largeur
|
||||||
|
legend-width 15 cm
|
||||||
|
legend-columns 2
|
||||||
|
## Un commentaire à ajouter au titre, on pourrait indiquer ici la mairie où est placée la cavité
|
||||||
|
## dont le nom est probablement le titre de la topo.
|
||||||
|
map-comment "{map_comment}"
|
||||||
|
#map-comment "{map_comment}<br>Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m"
|
||||||
|
|
||||||
|
## Afficher les statistiques d'explo/topo par équipe/nom. C'est lourd
|
||||||
|
## si la cavité est importante et qu'il y a beaucoup d'explorateurs/topographes.
|
||||||
|
statistics explo-length off
|
||||||
|
statistics topo-length off
|
||||||
|
|
||||||
|
## Afficher un copyright
|
||||||
|
statistics copyright 2
|
||||||
|
|
||||||
|
## Dessin ou pas du cheminement topo
|
||||||
|
# symbol-hide point station
|
||||||
|
# symbol-hide line survey
|
||||||
|
# symbol-hide group
|
||||||
|
# symbol-show line wall
|
||||||
|
# symbol-hide point station-name
|
||||||
|
# symbol-hide point u:symbol_plan
|
||||||
|
# symbol-hide point u:symbol_extend
|
||||||
|
# debug scrap-names
|
||||||
|
# debug station-names
|
||||||
|
|
||||||
|
layers on
|
||||||
|
|
||||||
|
overlap 2 cm
|
||||||
|
|
||||||
|
code tex-map
|
||||||
|
\legendwidth=15cm
|
||||||
|
\legendtextsize={\size[12]}
|
||||||
|
\legendtextheadersize={\size[28]} %%% Taille du titre
|
||||||
|
\legendtextsectionsize={\size[14]} %%% Taille du titre
|
||||||
|
%\legendtextcolor={\color[0 0 110]} %# RGB values 0--100
|
||||||
|
% Output map title as determined by Therion is stored in cavename, défini par la une Map.
|
||||||
|
% It will be empty if there are multiple maps selected for any one projection
|
||||||
|
% AND there are multiple source surveys identified in the thconfig file
|
||||||
|
% ie Therion can not infer a unique title from the input data given.
|
||||||
|
% This code allows you to define an output map title {cavename} if it happens to be empty
|
||||||
|
\edef\temp{\the\cavename} % cavename from Therion
|
||||||
|
\edef\nostring{} % empty string
|
||||||
|
\ifx\temp\nostring % test if cavename is empty
|
||||||
|
% if empty
|
||||||
|
reassign cavename to describe selected maps as a group
|
||||||
|
\else % if not empty keep the value set by therion, or assign an override cavename here
|
||||||
|
\fi
|
||||||
|
\cavename={{cavename}, Plan 1:{Scale}} % Note Alex : Bug avec certains fichiers ?
|
||||||
|
\newtoks\club \club={{club}}
|
||||||
|
%\newtoks\thanksto \thanksto={{thanksto}}
|
||||||
|
\newtoks\wpage \wpage={{wpage}}
|
||||||
|
\newtoks\datat \datat={{datat}}
|
||||||
|
\newtoks\synth \synth={{Author}}
|
||||||
|
\framethickness=0.5mm
|
||||||
|
endcode
|
||||||
|
|
||||||
|
endlayout
|
||||||
|
|
||||||
|
##debut de la definition du layout "layout-Extended"
|
||||||
|
layout layout-Extended
|
||||||
|
## Call the config settings (Layout config inside the config.thc file)
|
||||||
|
copy drawingconfig
|
||||||
|
#copy layoutcontinuation # Pour afficher le label des continuations
|
||||||
|
copy header_coupe
|
||||||
|
#copy headerl
|
||||||
|
#copy header_coupe_vert-auto
|
||||||
|
#copy header_coupe_vert-to-place
|
||||||
|
copy langue-fr
|
||||||
|
|
||||||
|
## Définition du système de projection du plan
|
||||||
|
cs {cs}
|
||||||
|
|
||||||
|
## La ligne base-scale spécifie l'échelle auquel nous avons dessiné nos croquis.
|
||||||
|
## Par défaut, Therion pense que c'est une échelle 1:200. Si on a utilisé une autre échelle,
|
||||||
|
## il faut enlever le "#" et spécifier l'échelle vraiment employée, comme c'est le cas
|
||||||
|
## après avoir dessiné la topo sur un cheminement exporté avec le layout "xviexport".
|
||||||
|
## Jouer avec le ration base-scale/scale permet de jouer globalement sur les tailles
|
||||||
|
## des caractères et des traits.
|
||||||
|
base-scale 1 {Scale}
|
||||||
|
|
||||||
|
## Maintenant on va mettre une ligne "scale" pour specifier l'échelle pour imprimer la topo.
|
||||||
|
## La combination entre scale et base-scale contrôle l'épaisseur des lignes, rotation, etc, convenable
|
||||||
|
## pour faire l'ampliation-réduction entre dessin et le résultat de l'imprimante
|
||||||
|
## C'est tres important s'assurer que la configuration de l'imprimante ne spécifie pas l'option "Fit in page"
|
||||||
|
## ou similaire, sinon, l'échelle sera changée pendant l'impression!
|
||||||
|
scale 1 {Scale}
|
||||||
|
|
||||||
|
## Echelle graphique 100 m ampleur (Généralement, le choix scale/10 est plutôt pas mal)
|
||||||
|
scale-bar 40 m
|
||||||
|
|
||||||
|
## Voici une ligne pour specifier qu'il faut imprimer une grille au dessous de la topo
|
||||||
|
#grid bottom
|
||||||
|
grid off
|
||||||
|
## Une ligne pour specifier que la grille est 1000x1000x1000 m
|
||||||
|
## (Trois dimensions, oui, ça sert pour la coupe aussi)
|
||||||
|
#grid-size 250 250 250 m
|
||||||
|
|
||||||
|
## la topo est transparente (on peut voir les galeries inférieurs)
|
||||||
|
## C'est on par défaut, donc, pas vraiment besoin de specifier
|
||||||
|
transparency on
|
||||||
|
|
||||||
|
## Couleurs de la topographie
|
||||||
|
#colour map-bg [70 90 70]
|
||||||
|
#colour map-fg [100 100 80]
|
||||||
|
#colour map-fg altitude
|
||||||
|
#colour map-fg explo-date
|
||||||
|
#colour map-fg topo-date
|
||||||
|
#colour map-fg map
|
||||||
|
#colour map-fg scrap
|
||||||
|
#colour-legend off
|
||||||
|
colour map-fg 90
|
||||||
|
|
||||||
|
## ça marche seulement si transparency est "on" 90% blanc= 10% noir
|
||||||
|
opacity 75
|
||||||
|
#surface bottom
|
||||||
|
#surface-opacity 100
|
||||||
|
|
||||||
|
## Auteur
|
||||||
|
doc-author "{Author}"
|
||||||
|
## Titre
|
||||||
|
doc-title "{cavename} Coupe développée - 1:{Scale}"
|
||||||
|
|
||||||
|
doc-subject "{cavename}, topographie en coupe développée"
|
||||||
|
doc-keywords "Cave, Survey, {cavename}, Pierre saint Martin - Larra, Coupe développée, {map_comment}"
|
||||||
|
|
||||||
|
## Maintenant on spécifie la position de la manchette, dont l'intérieur est occupé par le titre, auteurs, etc.
|
||||||
|
## Nous pouvons indiquer les cordonnées du point de la topo ou l'on veut la manchette :
|
||||||
|
## 0 0, c'est en bas, à gauche, 100 100, c'est en haut, à droite
|
||||||
|
## La manchette a des "points cardinaux" autour : n, s, ne, sw, etc.
|
||||||
|
## Il faut specifier un de ces points comme ce que sera placé sur les cordonnées.
|
||||||
|
## Alors nous pouvons specifier que le sud-ouest de la manchette soit placé en bas, a gauche,
|
||||||
|
## ou une autre combination...
|
||||||
|
map-header 98 98 ne
|
||||||
|
## arrière plan de la manchette
|
||||||
|
map-header-bg on
|
||||||
|
## Légende pour expliciter les symboles. "on" imprimera seulement la légende des symboles dessinés
|
||||||
|
## sur la topo. Si l'on veut pour tous les symboles, utilisés ou pas, il faut indiquer "all".
|
||||||
|
## "legend off" = pas de légende
|
||||||
|
legend on
|
||||||
|
## Par défaut, la légende est de 14 cm de largeur
|
||||||
|
legend-width 15 cm
|
||||||
|
legend-columns 2
|
||||||
|
## Un commentaire à ajouter au titre, on pourrait indiquer ici la mairie où est placée la cavité
|
||||||
|
## dont le nom est probablement le titre de la topo.
|
||||||
|
map-comment "{map_comment}"
|
||||||
|
#map-comment "{map_comment}<br>Coordonnées : ({cs}/WGS84) xxx.xxx xxxx.xxx, Alt.: xxxx m"
|
||||||
|
|
||||||
|
## Afficher les statistiques d'explo/topo par équipe/nom. C'est lourd
|
||||||
|
## si la cavité est importante et qu'il y a beaucoup d'explorateurs/topographes.
|
||||||
|
statistics explo-length off
|
||||||
|
statistics topo-length off
|
||||||
|
|
||||||
|
## Afficher un copyright
|
||||||
|
statistics copyright 2
|
||||||
|
|
||||||
|
## Dessin ou pas du cheminement topo
|
||||||
|
# symbol-hide point station
|
||||||
|
# symbol-hide line survey
|
||||||
|
# symbol-hide group
|
||||||
|
# symbol-show line wall
|
||||||
|
# symbol-hide point u:symbol_plan
|
||||||
|
# symbol-hide point u:symbol_extend
|
||||||
|
# debug scrap-names
|
||||||
|
# debug station-names
|
||||||
|
|
||||||
|
layers on
|
||||||
|
|
||||||
|
overlap 2 cm
|
||||||
|
|
||||||
|
## Modification du Titre de la topo
|
||||||
|
code tex-map
|
||||||
|
\legendwidth=15cm
|
||||||
|
\legendtextsize={\size[12]}
|
||||||
|
\legendtextheadersize={\size[28]} %%% Taille du titre
|
||||||
|
\legendtextsectionsize={\size[14]} %%% Taille du titre
|
||||||
|
%\legendtextcolor={\color[0 0 110]} %# RGB values 0--100
|
||||||
|
% Output map title as determined by Therion is stored in cavename, défini par la une Map.
|
||||||
|
% It will be empty if there are multiple maps selected for any one projection
|
||||||
|
% AND there are multiple source surveys identified in the thconfig file
|
||||||
|
% ie Therion can not infer a unique title from the input data given.
|
||||||
|
% This code allows you to define an output map title {cavename} if it happens to be empty
|
||||||
|
\edef\temp{\the\cavename} % cavename from Therion
|
||||||
|
\edef\nostring{} % empty string
|
||||||
|
\ifx\temp\nostring % test if cavename is empty
|
||||||
|
% if empty
|
||||||
|
reassign cavename to describe selected maps as a group
|
||||||
|
\else % if not empty keep the value set by therion, or assign an override cavename here
|
||||||
|
\fi
|
||||||
|
\cavename={{cavename}, Coupe développée 1:{Scale}} % Note Alex : Bug avec certains fichiers ?
|
||||||
|
\newtoks\club \club={{club}}
|
||||||
|
%\newtoks\thanksto \thanksto={{thanksto}}
|
||||||
|
\newtoks\wpage \wpage={{wpage}}
|
||||||
|
\newtoks\datat \datat={{datat}}
|
||||||
|
\newtoks\synth \synth={{Author}}
|
||||||
|
\framethickness=0.5mm
|
||||||
|
endcode
|
||||||
|
|
||||||
|
endlayout
|
||||||
|
## Fin de la definition du Layout "normal"
|
||||||
|
|
||||||
|
layout layout-kml
|
||||||
|
## Définition du système de projection du plan
|
||||||
|
cs EPSG:2154
|
||||||
|
## Couleur de la topographie
|
||||||
|
## Rouge-Orange = 255,69,0 -->
|
||||||
|
## Orange = 255,165,0 -->
|
||||||
|
## Orange Sombre = 255,140,0 -->
|
||||||
|
## Bleu --> 0, 0 255
|
||||||
|
color map-fg [0 0 100]
|
||||||
|
endlayout
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
# 3-EXPORT
|
||||||
|
###############################################################################################
|
||||||
|
|
||||||
|
## Export des xvi pour le dessin si besoin
|
||||||
|
# export map -proj plan -layout xviexport -fmt xvi -o Data/{fileName}-Plan.xvi
|
||||||
|
# export map -proj extended -layout xviexport -fmt xvi -o Data/{fileName}-Extended.xvi
|
||||||
|
|
||||||
|
## Selection des Maps à exporter
|
||||||
|
# select MP-{fileName}-Plan-tot@{fileName}
|
||||||
|
# select MC-{fileName}-Extended-tot@{fileName}
|
||||||
|
|
||||||
|
## Export des fichiers pdf, plan et coupe.
|
||||||
|
## ATTENTION, la topo étant énorme, il faut mettre l'option ne traçant pas la centerline !
|
||||||
|
|
||||||
|
# export map -projection plan -fmt pdf -layout layout-Plan -o Outputs/{fileName}-Plan.pdf
|
||||||
|
# export map -projection extended -fmt pdf -layout layout-Extended -o Outputs/{fileName}-Extended.pdf
|
||||||
|
|
||||||
|
## Export du fichier 3d pour Loch
|
||||||
|
export model -enable all -o Outputs/{fileName}.lox
|
||||||
|
export model -enable all -o Outputs/{fileName}.kml
|
||||||
|
|
||||||
|
## Export des fichiers ESRI
|
||||||
|
# export map -proj plan -fmt esri -o Outputs/{fileName}
|
||||||
|
|
||||||
|
## Export des fichiers kml
|
||||||
|
# export map -proj plan -fmt kml -o Outputs/{fileName}.kml -layout layout-kml
|
||||||
|
# export model -fmt kml -o Outputs/{fileName}-model.kml -enable all
|
||||||
|
# export model -enable all -o Outputs/{fileName}-3D.kml
|
||||||
|
# export cave-list -location on -o Outputs/{fileName}-Cave-list.html
|
||||||
|
# export survey-list -location on -o Outputs/{fileName}-Surveys.html
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
|
## END
|
||||||
|
###############################################################################################
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Configuration values for pyCreate_th2.ph
|
||||||
|
[Survey_Data]
|
||||||
|
Author = Alexandre Pont
|
||||||
|
Copyright1 = # Copyright (C) ARSIP 2025
|
||||||
|
Copyright2 = # This work is under the Creative Commons Attribution-NonCommercial-NoDerivatives License:
|
||||||
|
Copyright3 = # <http://creativecommons.org/licenses/by-nc-nd/4.0/>
|
||||||
|
Copyright_Short = Licence CC by-nc-nd : http://creativecommons.org/licenses/by-nc-nd/4.0/
|
||||||
|
map_comment = Massif de la Pierre Saint Martin - Larra
|
||||||
|
club = ARSIP
|
||||||
|
thanksto = Merçi à tout le monde
|
||||||
|
datat = https://github.com/Alex38Lyon/Synthese-PSM_LARRA
|
||||||
|
wpage = https://www.arsip.fr/
|
||||||
|
cs = UTM30
|
||||||
|
|
||||||
|
|
||||||
|
[Application_Data]
|
||||||
|
template_path = ./template
|
||||||
|
station_by_scrap = 30
|
||||||
|
final_therion_exe = True
|
||||||
|
therion_path = C:\Program Files\Therion\therion.exe
|
||||||
|
shot_lines_in_th2_files = False
|
||||||
|
station_name_in_th2_files = False
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"cSpell.words": [
|
||||||
|
"australiangeodetic",
|
||||||
|
"australiangeodeticdatum",
|
||||||
|
"backclino",
|
||||||
|
"cavename",
|
||||||
|
"clarke",
|
||||||
|
"clino",
|
||||||
|
"datat",
|
||||||
|
"ecart",
|
||||||
|
"ENDC",
|
||||||
|
"endlayout",
|
||||||
|
"endscrap",
|
||||||
|
"etrs",
|
||||||
|
"european",
|
||||||
|
"geocentricdatumofaustralia",
|
||||||
|
"geocentricofaustralia",
|
||||||
|
"Makto",
|
||||||
|
"northamerican",
|
||||||
|
"northamericandatum",
|
||||||
|
"nouvelletriangulationfrançaise",
|
||||||
|
"thanksto",
|
||||||
|
"thconfig",
|
||||||
|
"therion",
|
||||||
|
"wpage",
|
||||||
|
"XTHERION"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,993 @@
|
|||||||
|
|
||||||
|
"""
|
||||||
|
#############################################################################################
|
||||||
|
# #
|
||||||
|
# Script pour automatiser la création des dossiers et fichiers pour un fichier .th #
|
||||||
|
# #
|
||||||
|
# By Alexandre PONT (alexandre_pont@yahoo.fr) #
|
||||||
|
# #
|
||||||
|
# Définir les différentes variables dans fichier config.ini #
|
||||||
|
# Création des dossiers nécessaires d'après dossier 'template' #
|
||||||
|
# Création des fichiers nécessaires : th, th2, -tot.th #
|
||||||
|
# Création des scrap avec stations topo #
|
||||||
|
# #
|
||||||
|
# usage : python pyCreate_th2.py #
|
||||||
|
# #
|
||||||
|
#############################################################################################
|
||||||
|
|
||||||
|
Création Alex the 2024 12 16 :
|
||||||
|
Thank's too
|
||||||
|
- Tanguy Racine for the script https://github.com/tr1813
|
||||||
|
- Xavier Robert for the main principes https://github.com/robertxa
|
||||||
|
- Benoit Urruty https://github.com/BenoitURRUTY
|
||||||
|
|
||||||
|
Version 2025 03 21 : Création mode --update th2
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
Version ="2025.03.21"
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
from os.path import isfile, join, abspath
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
import argparse
|
||||||
|
import shutil
|
||||||
|
from datetime import datetime
|
||||||
|
import configparser
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
from helpers.survey import SurveyLoader, NoSurveysFoundException
|
||||||
|
from helpers.therion import compile_template, Colors, compile_file
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
## [Survey_Data] default values
|
||||||
|
Author = "Created by pyCreate_th2.py"
|
||||||
|
Copyright = "# Copyright (C) pyCreate_th2.py"
|
||||||
|
Copyright_Short = "Licence (C) pyCreate_th2.py"
|
||||||
|
map_comment = "Created by pyCreate_th2.py"
|
||||||
|
cs = "UTM30"
|
||||||
|
club = "Therion"
|
||||||
|
thanksto = "Therion"
|
||||||
|
datat = "https://therion.speleo.sk/"
|
||||||
|
wpage = "https://therion.speleo.sk/"
|
||||||
|
|
||||||
|
## [Application_data] default values
|
||||||
|
template_path = "./template"
|
||||||
|
station_by_scrap = 20
|
||||||
|
final_therion_exe = True
|
||||||
|
therion_path = "C:/Therion/therion.exe"
|
||||||
|
LINES = -1
|
||||||
|
NAMES = -1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# # Codes de couleur ANSI
|
||||||
|
# class Colors:
|
||||||
|
# BLACK = '\033[90m'
|
||||||
|
# RED = '\033[91m'
|
||||||
|
# GREEN = '\033[92m'
|
||||||
|
# YELLOW = '\033[93m'
|
||||||
|
# BLUE = '\033[94m'
|
||||||
|
# MAGENTA = '\033[95m'
|
||||||
|
# CYAN = '\033[96m'
|
||||||
|
# WHITE = '\033[97m'
|
||||||
|
|
||||||
|
# ERROR = '\033[91m'
|
||||||
|
# WARNING = '\033[95m'
|
||||||
|
# HEADER = '\033[96m'
|
||||||
|
|
||||||
|
# ENDC = '\033[0m'
|
||||||
|
# BOLD = '\033[1m'
|
||||||
|
# UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 illegal characters with an underscore (_)
|
||||||
|
th_name = re.sub(r'[<>:"/\\|?*\']', '_', th_name) # Characters not allowed on Windows
|
||||||
|
th_name = re.sub(r'[\s]', '_', th_name) # Replace spaces with underscores
|
||||||
|
th_name = re.sub(r'[^a-zA-Z0-9._-]', '_', th_name) # Keep letters, digits, . _ -
|
||||||
|
|
||||||
|
# Ensure the name is not empty or just underscores
|
||||||
|
return th_name.strip('_') or "default_filename"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def colored_help(parser):
|
||||||
|
# Captures the help output
|
||||||
|
help_text = parser.format_help()
|
||||||
|
|
||||||
|
# Coloration des différentes parties
|
||||||
|
colored_help_text = help_text.replace(
|
||||||
|
'usage:', f'{Colors.ERROR}usage:{Colors.ENDC}'
|
||||||
|
).replace(
|
||||||
|
'options:', f'{Colors.GREEN}options:{Colors.ENDC}'
|
||||||
|
).replace('positional arguments:', f'{Colors.BLUE}positional arguments:{Colors.ENDC}')
|
||||||
|
|
||||||
|
# Surligner les arguments
|
||||||
|
for action in parser._actions:
|
||||||
|
if action.option_strings:
|
||||||
|
# Colorer les options (--xyz)
|
||||||
|
for opt in action.option_strings:
|
||||||
|
colored_help_text = colored_help_text.replace(opt, f'{Colors.BLUE}{opt}{Colors.ENDC}')
|
||||||
|
|
||||||
|
# Imprimer le texte coloré
|
||||||
|
print(colored_help_text)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def read_config(config_file):
|
||||||
|
global Author
|
||||||
|
global Copyright
|
||||||
|
global Copyright_Short
|
||||||
|
global map_comment
|
||||||
|
global club
|
||||||
|
global thanksto
|
||||||
|
global datat
|
||||||
|
global wpage
|
||||||
|
global cs
|
||||||
|
global template_path
|
||||||
|
global station_by_scrap
|
||||||
|
global final_therion_exe
|
||||||
|
global therion_path
|
||||||
|
global LINES
|
||||||
|
global NAMES
|
||||||
|
|
||||||
|
|
||||||
|
# Initialize the configparser to read .ini files
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(config_file, encoding="utf-8")
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Author' in config['Survey_Data']:
|
||||||
|
Author = config['Survey_Data']['Author']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Copyright1' in config['Survey_Data']:
|
||||||
|
Copyright = config['Survey_Data']['Copyright1'] + "\n" + config['Survey_Data']['Copyright2'] + "\n" + config['Survey_Data']['Copyright3'] + "\n"
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Copyright_Short' in config['Survey_Data']:
|
||||||
|
Copyright_Short = config['Survey_Data']['Copyright_Short']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'map_comment' in config['Survey_Data']:
|
||||||
|
map_comment = config['Survey_Data']['map_comment']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'club' in config['Survey_Data']:
|
||||||
|
club = config['Survey_Data']['club']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'thanksto' in config['Survey_Data']:
|
||||||
|
thanksto = config['Survey_Data']['thanksto']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'datat' in config['Survey_Data']:
|
||||||
|
datat = config['Survey_Data']['datat']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'wpage' in config['Survey_Data']:
|
||||||
|
wpage = config['Survey_Data']['wpage']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'cs' in config['Survey_Data']:
|
||||||
|
cs = config['Survey_Data']['cs']
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'template_path' in config['Application_Data']:
|
||||||
|
template_path = config['Application_Data']['template_path']
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'station_by_scrap' in config['Application_Data']:
|
||||||
|
station_by_scrap = int(config['Application_Data']['station_by_scrap'])
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'final_therion_exe' in config['Application_Data']:
|
||||||
|
final_therion_exe = bool(config['Application_Data']['final_therion_exe'])
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'therion_path' in config['Application_Data']:
|
||||||
|
therion_path = config['Application_Data']['therion_path']
|
||||||
|
|
||||||
|
if LINES == -1 :
|
||||||
|
if 'Application_Data' in config and 'shot_lines_in_th2_files' in config['Application_Data']:
|
||||||
|
LINES = 0 if config['Application_Data']['shot_lines_in_th2_files'] == "False" else 1
|
||||||
|
|
||||||
|
if NAMES == -1 :
|
||||||
|
if 'Application_Data' in config and 'station_name_in_th2_files' in config['Application_Data']:
|
||||||
|
NAMES = 0 if config['Application_Data']['station_name_in_th2_files'] == "False" else 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def copy_template_if_not_exists(template_path, destination_path):
|
||||||
|
# Check if the destination folder exists
|
||||||
|
try:
|
||||||
|
if not os.path.exists(destination_path):
|
||||||
|
# If the destination folder does not exist, copy the template
|
||||||
|
shutil.copytree(template_path, destination_path)
|
||||||
|
print(f"{Colors.GREEN}The folder '{Colors.GREEN}{template_path}{Colors.ENDC}' has been copied to '{Colors.ENDC}{destination_path}{Colors.GREEN}'{Colors.ENDC}")
|
||||||
|
else:
|
||||||
|
print(f"{Colors.WARNING}Warning: The folder '{Colors.ENDC}{destination_path}{Colors.WARNING}' already exists. No files were copied.{Colors.ENDC}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Colors.ERROR}Copy template error: {Colors.ENDC}{e}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def add_copyright_header(file_path, copyright_text):
|
||||||
|
# Lire le contenu du fichier
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
content = file.readlines()
|
||||||
|
|
||||||
|
# Vérifier si le copyright est déjà présent
|
||||||
|
if not any("copyright" in line.lower() for line in content):
|
||||||
|
# Ajouter le copyright en en-tête
|
||||||
|
content.insert(0, f"{copyright_text}\n")
|
||||||
|
|
||||||
|
# Réécrire le fichier avec le copyright ajouté
|
||||||
|
with open(file_path, 'w') as file:
|
||||||
|
file.writelines(content)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def copy_file_with_copyright(th_file, destination_path, copyright_text):
|
||||||
|
# Vérifier si le fichier existe
|
||||||
|
if os.path.exists(th_file):
|
||||||
|
# Créer le dossier de destination s'il n'existe pas
|
||||||
|
os.makedirs(destination_path, exist_ok=True)
|
||||||
|
|
||||||
|
# Copier le fichier vers le dossier de destination
|
||||||
|
dest_file = os.path.join(destination_path, os.path.basename(th_file))
|
||||||
|
shutil.copy(th_file, dest_file)
|
||||||
|
|
||||||
|
# Ajouter le copyright dans l'en-tête si nécessaire
|
||||||
|
add_copyright_header(dest_file, copyright_text)
|
||||||
|
|
||||||
|
# print(f"{Colors.GREEN}File '{Colors.ENDC}{th_file}{Colors.GREEN}' has been copied to '{Colors.ENDC}{destination_path}{Colors.GREEN}' with the copyright header added.{Colors.ENDC}")
|
||||||
|
else:
|
||||||
|
print(f"{Colors.ERROR}Error: The file .th does not exist {Colors.ENDC}{th_file}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def process_template(template_path, variables, output_path):
|
||||||
|
"""
|
||||||
|
Process a Therion template file by replacing variables.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
template_path (str): Path to the original template file
|
||||||
|
variables (dict): Dictionary of variables to replace
|
||||||
|
output_path (str): Path for the new configuration file
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Read the content of the template file
|
||||||
|
with open(template_path, 'r', encoding='utf-8') as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
# Replace variables
|
||||||
|
for var, value in variables.items():
|
||||||
|
# Use regex to replace {variable} with its value
|
||||||
|
pattern = r'\{' + re.escape(var) + r'\}'
|
||||||
|
content = re.sub(pattern, str(value), content)
|
||||||
|
|
||||||
|
# Write the new file
|
||||||
|
with open(output_path, 'w', encoding='utf-8') as file:
|
||||||
|
file.write(content)
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Update template successfully: {Colors.ENDC}{output_path}")
|
||||||
|
|
||||||
|
# Delete the original template file
|
||||||
|
os.remove(template_path)
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"{Colors.WARNING}Warning: Template file {Colors.ENDC}{template_path}{Colors.WARNING} not found.{Colors.ENDC}")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"{Colors.ERROR}Error: Insufficient permissions to write the file.{Colors.ENDC}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Colors.ERROR}An error occurred: {Colors.ENDC}{e}")
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
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:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as file:
|
||||||
|
# Read all lines from the file
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
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:
|
||||||
|
print(f"{Colors.WARNING}Warning: File {Colors.ENDC}{file_path}{Colors.WARNING} not found.{Colors.ENDC}")
|
||||||
|
except PermissionError:
|
||||||
|
print(f"{Colors.ERROR}Error: Insufficient permissions to read {Colors.ENDC}{file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Colors.ERROR}An error occurred: {Colors.ENDC}{e}")
|
||||||
|
|
||||||
|
return survey_names
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def str_to_bool(value):
|
||||||
|
"""
|
||||||
|
Function to convert string to boolean
|
||||||
|
"""
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
if value.lower() in ('true', '1', 'yes', 'y'):
|
||||||
|
return True
|
||||||
|
elif value.lower() in ('false', '0', 'no', 'n'):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise argparse.ArgumentTypeError(f"{Colors.ERROR}Error: Invalid boolean value: {Colors.ENDC}{value}")
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def select_file():
|
||||||
|
# Créer une instance de la fenêtre tkinter
|
||||||
|
root = tk.Tk()
|
||||||
|
# Cacher la fenêtre principale
|
||||||
|
root.withdraw()
|
||||||
|
# Afficher la boîte de dialogue de sélection de fichier
|
||||||
|
file_path = filedialog.askopenfilename(title="Sélectionnez un fichier")
|
||||||
|
# Retourner le chemin complet du fichier sélectionné
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# main function #
|
||||||
|
#################################################################################################
|
||||||
|
if __name__ == u'__main__':
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Parse arguments #
|
||||||
|
#################################################################################################
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=f"{Colors.HEADER}Create a skeleton folder and th2 files with scraps from a .th Therion file\nVersion: {Colors.ENDC}{Version}\n",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser.print_help = colored_help.__get__(parser)
|
||||||
|
parser.add_argument("--survey_file", help="The survey file (*.th) 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=['plan', 'elevation', 'extended', 'none'], help="The scrap projection to produce", default="plan")
|
||||||
|
#parser.add_argument("--format", choices=['th2', 'plt'], help="Output format. Either th2 for producing skeleton for drawing or plt for visualizing in aven/loch", default="th2")
|
||||||
|
parser.add_argument("--output", default="./", help="Output folder path")
|
||||||
|
# parser.add_argument("--therion-path", help="Path to therion binary", default="therion")
|
||||||
|
parser.add_argument("--scale", help="Scale for the exports", default="500")
|
||||||
|
parser.add_argument("--lines", type=str_to_bool, help="Shot lines in th2 files", default=-1)
|
||||||
|
parser.add_argument("--names", type=str_to_bool, help="Stations names in th2 files", default=-1)
|
||||||
|
parser.add_argument("--update", help="Mode update, option th2", default="")
|
||||||
|
|
||||||
|
parser.epilog = (
|
||||||
|
f"{Colors.GREEN}Please, complete {Colors.RED}config.ini{Colors.GREEN} file for personal configuration{Colors.ENDC}\n"
|
||||||
|
f"{Colors.GREEN}If no argument :{Colors.RED} files selection windows\n{Colors.ENDC}\n"
|
||||||
|
f"{Colors.BLUE}Examples:{Colors.ENDC}\n"
|
||||||
|
f"\t> python pyCreate_th2.py ./test/Entree.th --survey_name Geophysicaya_01_entree --output ./test/ --scale 1000\n"
|
||||||
|
f"\t> python pyCreate_th2.py Entree.th\n"
|
||||||
|
f"\t> python pyCreate_th2.py\n\n")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# print("args.survey_file : " + args.survey_file )
|
||||||
|
# print("args.update : " + args.update )
|
||||||
|
|
||||||
|
if args.survey_file == "":
|
||||||
|
args.survey_file = select_file()
|
||||||
|
print(f"Selected file : {args.survey_file}")
|
||||||
|
|
||||||
|
ENTRY_FILE = abspath(args.survey_file)
|
||||||
|
# PROJECTION = args.proj.capitalize()
|
||||||
|
PROJECTION = "Plan"
|
||||||
|
TARGET = args.survey_name
|
||||||
|
OUTPUT = args.output
|
||||||
|
#FORMAT = args.format
|
||||||
|
FORMAT = "th2"
|
||||||
|
SCALE = args.scale
|
||||||
|
LINES = args.lines
|
||||||
|
NAMES = args.names
|
||||||
|
# TH_NAME = args.survey_file.split("/")[-1].strip(".th")
|
||||||
|
TH_NAME = sanitize_filename(os.path.splitext(os.path.basename(args.survey_file))[0])
|
||||||
|
DEST_PATH = os.path.dirname(args.survey_file) + "/" + TH_NAME
|
||||||
|
#DEST_PATH = args.output + TH_NAME.split("/")[-1].strip(".th")
|
||||||
|
#ABS_PATH = ENTRY_FILE.strip(args.survey_file)
|
||||||
|
ABS_PATH = os.path.dirname(ENTRY_FILE)
|
||||||
|
|
||||||
|
# print("args.survey_file : " + args.survey_file )
|
||||||
|
# print("ENTRY_FILE: " + ENTRY_FILE )
|
||||||
|
# print("PROJECTION: " + PROJECTION )
|
||||||
|
# print("TARGET: " + TARGET )
|
||||||
|
# print("OUTPUT: " + OUTPUT )
|
||||||
|
# print("FORMAT: " + FORMAT )
|
||||||
|
# print("SCALE: " + SCALE )
|
||||||
|
# print("TH_NAME: " + TH_NAME )
|
||||||
|
# print("DEST_PATH: " + DEST_PATH )
|
||||||
|
# print("ABS_PATH: " + ABS_PATH )
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Reading config.ini #
|
||||||
|
#################################################################################################
|
||||||
|
try:
|
||||||
|
# Load the 'database' section from the configuration file
|
||||||
|
read_config("config.ini")
|
||||||
|
# print("Auteur: " + Author)
|
||||||
|
# print(f"Copyright: \n{Copyright}")
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
# Handle errors if the section is missing
|
||||||
|
print(f"{Colors.ERROR}Error: read_config:{Colors.ERROR}", e)
|
||||||
|
|
||||||
|
if PROJECTION.lower() != "plan" :
|
||||||
|
print(f"{Colors.ERROR}Error: Sorry, projection '{Colors.ENDC}{PROJECTION}{Colors.ERROR}' not yet implemented{Colors.ENDC}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if not os.path.isfile(ENTRY_FILE):
|
||||||
|
print(f"{Colors.ERROR}Error: The Therion file didn't exist: {Colors.ENDC} {ENTRY_FILE}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if FORMAT not in ["th2", "plt"]:
|
||||||
|
print(f"{Colors.ERROR}Error: Please choose a supported format: th2, plt{Colors.ENDC}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Normalise name, namespace, key, file path
|
||||||
|
print(f"{Colors.GREEN}Parsing survey entry file:\t{Colors.ENDC} {args.survey_file}")
|
||||||
|
|
||||||
|
survey_list = parse_therion_surveys(ENTRY_FILE)
|
||||||
|
# print(survey_list)
|
||||||
|
|
||||||
|
if TARGET == "None" :
|
||||||
|
if len(survey_list) > 1 :
|
||||||
|
print(f"{Colors.ERROR}Error: Multiple surveys were found, not yet implemented{Colors.ENDC}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
TARGET = sanitize_filename(survey_list[0])
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Parsing survey target: \t{Colors.ENDC} {TARGET}")
|
||||||
|
|
||||||
|
loader = SurveyLoader(ENTRY_FILE)
|
||||||
|
survey = loader.get_survey_by_id(survey_list[0])
|
||||||
|
|
||||||
|
# print(survey.name)
|
||||||
|
|
||||||
|
if not survey:
|
||||||
|
raise NoSurveysFoundException(f"{Colors.ERROR}Error: No survey found with that selector{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
|
if args.update == "th2":
|
||||||
|
print(f"{Colors.GREEN} Update th2 files {Colors.ENDC}")
|
||||||
|
print(f"\t{Colors.BLUE}survey_file : {Colors.ENDC} {args.survey_file}")
|
||||||
|
print(f"\t{Colors.BLUE}ENTRY_FILE: {Colors.ENDC} {ENTRY_FILE}")
|
||||||
|
print(f"\t{Colors.BLUE}PROJECTION: {Colors.ENDC} {PROJECTION}")
|
||||||
|
print(f"\t{Colors.BLUE}TARGET: {Colors.ENDC} {TARGET}")
|
||||||
|
print(f"\t{Colors.BLUE}OUTPUT: {Colors.ENDC} {OUTPUT}")
|
||||||
|
print(f"\t{Colors.BLUE}FORMAT: {Colors.ENDC} {FORMAT}")
|
||||||
|
print(f"\t{Colors.BLUE}SCALE: {Colors.ENDC} {SCALE}")
|
||||||
|
print(f"\t{Colors.BLUE}TH_NAME: {Colors.ENDC} {TH_NAME}")
|
||||||
|
DEST_PATH = os.path.dirname(args.survey_file)
|
||||||
|
print(f"\t{Colors.BLUE}DEST_PATH: {Colors.ENDC} {DEST_PATH}")
|
||||||
|
print(f"\t{Colors.BLUE}ABS_PATH: {Colors.ENDC} {ABS_PATH}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Copy template folders #
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
if args.update == "":
|
||||||
|
# print(f"{Colors.GREEN}Copy template folder and adapte it{Colors.ENDC}")
|
||||||
|
copy_template_if_not_exists(template_path, DEST_PATH)
|
||||||
|
copy_file_with_copyright(ENTRY_FILE, DEST_PATH + "/Data", Copyright)
|
||||||
|
|
||||||
|
# Adapte templates
|
||||||
|
config_vars = {
|
||||||
|
'fileName': TH_NAME,
|
||||||
|
'cavename': TH_NAME.replace("_", " "),
|
||||||
|
'Author': Author,
|
||||||
|
'Copyright': Copyright,
|
||||||
|
'Scale' : SCALE,
|
||||||
|
'Target' : TARGET,
|
||||||
|
'map_comment' : map_comment,
|
||||||
|
'club' : club,
|
||||||
|
'thanksto' : thanksto.replace("_", r"\_"),
|
||||||
|
'datat' : datat.replace("_", r"\_"),
|
||||||
|
'wpage' : wpage.replace("_", r"\_"),
|
||||||
|
'cs' : cs,
|
||||||
|
'other_scraps_plan' : "",
|
||||||
|
'file_info' : f'# File generated by pyCreate_th2.py (version {Version}) date: {datetime.now().strftime("%Y.%m.%d %H:%M:%S")}',
|
||||||
|
}
|
||||||
|
|
||||||
|
process_template(DEST_PATH + '/template.thconfig', config_vars, DEST_PATH + '/' + TH_NAME + '.thconfig')
|
||||||
|
process_template(DEST_PATH + '/template-tot.th', config_vars, DEST_PATH + '/' + TH_NAME + '-tot.th')
|
||||||
|
process_template(DEST_PATH + '/template-readme.md', config_vars, DEST_PATH + '/readme.md')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Produce the parsable XVI file #
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Compiling 2D XVI file: \t{Colors.ENDC} {TH_NAME}")
|
||||||
|
|
||||||
|
template = """source "{th_file}"
|
||||||
|
layout minimal
|
||||||
|
scale 1 {scale}
|
||||||
|
endlayout
|
||||||
|
|
||||||
|
select {selector}
|
||||||
|
|
||||||
|
export model -o "{th_name}.lox"
|
||||||
|
export map -projection plan -o "{th_name}-Plan.xvi" -layout minimal -layout-debug station-names
|
||||||
|
export map -projection extended -o "{th_name}-Extended.xvi" -layout minimal -layout-debug station-names
|
||||||
|
"""
|
||||||
|
|
||||||
|
if args.update == "th2":
|
||||||
|
template_args = {
|
||||||
|
"th_file": DEST_PATH + "/" + TH_NAME + ".th",
|
||||||
|
"selector": survey.therion_id,
|
||||||
|
"th_name": DEST_PATH + "/" + TH_NAME,
|
||||||
|
"scale": SCALE,
|
||||||
|
}
|
||||||
|
|
||||||
|
else :
|
||||||
|
template_args = {
|
||||||
|
"th_file": DEST_PATH + "/Data/" + TH_NAME + ".th",
|
||||||
|
"selector": survey.therion_id,
|
||||||
|
"th_name": DEST_PATH + "/Data/" + TH_NAME,
|
||||||
|
"scale": SCALE,
|
||||||
|
}
|
||||||
|
|
||||||
|
log, tmpdir = compile_template(template, template_args, cleanup=False, therion_path=therion_path)
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Parse the Plan XVI file #
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
if args.update == "th2":
|
||||||
|
th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Plan.xvi"
|
||||||
|
else :
|
||||||
|
th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Plan.xvi"
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Parsing plan XVI file:\t{Colors.ENDC}{th_name_xvi}")
|
||||||
|
|
||||||
|
stations = {}
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
with open(join(th_name_xvi), "r", encoding="utf-8") as f:
|
||||||
|
xvi_content = f.read()
|
||||||
|
xvi_stations, xvi_shots = xvi_content.split("XVIshots")
|
||||||
|
|
||||||
|
# Extract all the stations
|
||||||
|
for line in xvi_stations.split("\n"):
|
||||||
|
match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line)
|
||||||
|
if match:
|
||||||
|
x = match.groups()[0]
|
||||||
|
y = match.groups()[1]
|
||||||
|
station_number = match.groups()[2]
|
||||||
|
namespace = match.groups()[3]
|
||||||
|
namespace_array = namespace.split(".") if namespace else []
|
||||||
|
station = station_number
|
||||||
|
if len(namespace_array) > 1:
|
||||||
|
station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1]))
|
||||||
|
stations["{}.{}".format(x, y)] = [x, y, station]
|
||||||
|
|
||||||
|
# Extraire les valeurs x et y à partir des listes dans stations
|
||||||
|
x_values = [float(value[0]) for value in stations.values()]
|
||||||
|
y_values = [float(value[1]) for value in stations.values()]
|
||||||
|
|
||||||
|
# Trouver les min et max de x
|
||||||
|
x_min = float(min(x_values))
|
||||||
|
x_max = float(max(x_values))
|
||||||
|
|
||||||
|
# Trouver les min et max de y
|
||||||
|
y_min = float(min(y_values))
|
||||||
|
y_max = float(max(y_values))
|
||||||
|
|
||||||
|
x_ecart = x_max - x_min
|
||||||
|
y_ecart = y_max - y_min
|
||||||
|
|
||||||
|
# Afficher les résultats
|
||||||
|
# print("x_min:", x_min, "x_max:", x_max)
|
||||||
|
# print("y_min:", y_min, "y_max:", y_max)
|
||||||
|
# print("Écart max-min pour x:", x_ecart)
|
||||||
|
# print("Écart max-min pour y:", y_ecart)
|
||||||
|
|
||||||
|
# Extract all the lines
|
||||||
|
for line in xvi_shots.split("\n"):
|
||||||
|
match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line )
|
||||||
|
if match:
|
||||||
|
x1 = match.groups()[0]
|
||||||
|
y1 = match.groups()[1]
|
||||||
|
x2 = match.groups()[2]
|
||||||
|
y2 = match.groups()[3]
|
||||||
|
key1 = "{}.{}".format(x1, y1)
|
||||||
|
key2 = "{}.{}".format(x2, y2)
|
||||||
|
# Splays won't have stations
|
||||||
|
station1 = stations[key1][2] if key1 in stations else None
|
||||||
|
station2 = stations[key2][2] if key2 in stations else None
|
||||||
|
lines.append([x1, y1, x2, y2, station1, station2])
|
||||||
|
# shutil.rmtree(tmpdir)
|
||||||
|
if args.update == "th2":
|
||||||
|
th2_name = DEST_PATH + "/" + TH_NAME
|
||||||
|
else :
|
||||||
|
th2_name = DEST_PATH + "/Data/" + TH_NAME
|
||||||
|
output_path = f'{th2_name}-{PROJECTION}.{FORMAT}'
|
||||||
|
|
||||||
|
scrap_to_add = int(len(stations)/station_by_scrap)-1
|
||||||
|
|
||||||
|
# print(stations)
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Writing output to:\t{Colors.ENDC}{output_path}")
|
||||||
|
|
||||||
|
# Write TH2
|
||||||
|
if FORMAT == "th2":
|
||||||
|
th2_file_header = """encoding utf-8"""
|
||||||
|
|
||||||
|
th2_file = """
|
||||||
|
##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max}
|
||||||
|
##XTHERION## xth_me_area_zoom_to 100
|
||||||
|
##XTHERION## xth_me_image_insert {insert_XVI}
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
# File generated by pyCreate_th2.py version {version} date: {date}
|
||||||
|
|
||||||
|
# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min}
|
||||||
|
# y_min: {Y_Min}, y_max: {Y_Max} ecart : {Y_Max_Y_Min}
|
||||||
|
|
||||||
|
scrap S{projection_short}-{name}_01 -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}"
|
||||||
|
|
||||||
|
{points}
|
||||||
|
|
||||||
|
{names}
|
||||||
|
|
||||||
|
{lines}
|
||||||
|
|
||||||
|
endscrap"""
|
||||||
|
|
||||||
|
th2_point = """ point {x} {y} station -name {station}"""
|
||||||
|
th2_name = """ point {x} {y} station-name -align tr -scale xs -text {station}"""
|
||||||
|
|
||||||
|
th2_line = """ line u:Shot_Survey
|
||||||
|
{x1} {y1}
|
||||||
|
{x2} {y2}
|
||||||
|
|
||||||
|
endline"""
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
th2_lines = []
|
||||||
|
th2_points = []
|
||||||
|
th2_names = []
|
||||||
|
other_scraps_plan = ""
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
th2_lines.append(th2_line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3]))
|
||||||
|
coords1 = "{}.{}".format(line[0], line[1])
|
||||||
|
|
||||||
|
if coords1 not in seen:
|
||||||
|
seen.add(coords1)
|
||||||
|
th2_points.append(th2_point.format(x=line[0], y=line[1], station=line[4]))
|
||||||
|
th2_names.append(th2_name.format(x=line[0], y=line[1], station=line[4]))
|
||||||
|
coords2 = "{}.{}".format(line[2], line[3])
|
||||||
|
|
||||||
|
if "{}.{}".format(line[2], line[3]) not in seen:
|
||||||
|
seen.add(coords2)
|
||||||
|
if line[5] != None:
|
||||||
|
th2_points.append(th2_point.format(x=line[2], y=line[3], station=line[5]))
|
||||||
|
th2_names.append(th2_name.format(x=line[2], y=line[3], station=line[5]))
|
||||||
|
|
||||||
|
|
||||||
|
if isfile(output_path):
|
||||||
|
print(f"{Colors.WARNING}Warning: {Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done{Colors.ENDC}")
|
||||||
|
|
||||||
|
else :
|
||||||
|
name = TARGET,
|
||||||
|
# print(f"{Colors.GREEN}Therion output path :\t{Colors.ENDC}{output_path}")
|
||||||
|
|
||||||
|
with open(str(output_path), "w+") as f:
|
||||||
|
f.write(th2_file_header)
|
||||||
|
f.write(th2_file.format(
|
||||||
|
name = name[0],
|
||||||
|
Copyright = Copyright,
|
||||||
|
Copyright_Short = Copyright_Short,
|
||||||
|
points="\n".join(th2_points),
|
||||||
|
lines="\n".join(th2_lines) if LINES else "",
|
||||||
|
names="\n".join(th2_names) if NAMES else "",
|
||||||
|
projection=PROJECTION.lower(),
|
||||||
|
projection_short=PROJECTION[0].upper(),
|
||||||
|
author=Author,
|
||||||
|
year=datetime.now().year,
|
||||||
|
version = Version,
|
||||||
|
date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"),
|
||||||
|
X_Min=x_min*1.2,
|
||||||
|
X_Max=x_max*1.2,
|
||||||
|
Y_Min=y_min*1.2,
|
||||||
|
Y_Max=y_max*1.2,
|
||||||
|
X_Max_X_Min =x_ecart,
|
||||||
|
Y_Max_Y_Min =y_ecart,
|
||||||
|
insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {"
|
||||||
|
+ stations[next(iter(stations))][1] + " "
|
||||||
|
+ stations[next(iter(stations))][2] +"} "
|
||||||
|
+ os.path.basename(th_name_xvi) + " 0 {}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if scrap_to_add >= 1 :
|
||||||
|
for i in range(scrap_to_add):
|
||||||
|
other_scraps_plan = other_scraps_plan + f"\tbreak\n\tS{PROJECTION[0].upper()}-{name[0]}_{i+2:02}\n"
|
||||||
|
th2_scrap = """
|
||||||
|
|
||||||
|
scrap S{projection_short}-{name}_{num:02} -station-names "" "@{name}" -projection {projection} -author {year} "{author}" -copyright {year} "{Copyright_Short}"
|
||||||
|
|
||||||
|
endscrap
|
||||||
|
|
||||||
|
"""
|
||||||
|
f.write(th2_scrap.format(
|
||||||
|
name=name[0],
|
||||||
|
projection=PROJECTION.lower(),
|
||||||
|
projection_short=PROJECTION[0].upper(),
|
||||||
|
author=Author,
|
||||||
|
year=datetime.now().year,
|
||||||
|
Copyright_Short = Copyright_Short,
|
||||||
|
num=f"{i+2:02}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Parse the Extended XVI file #
|
||||||
|
#################################################################################################
|
||||||
|
if args.update == "th2":
|
||||||
|
th_name_xvi = DEST_PATH + "/" + TH_NAME + "-Extended.xvi"
|
||||||
|
else :
|
||||||
|
th_name_xvi = DEST_PATH + "/Data/" + TH_NAME + "-Extended.xvi"
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Parsing extended XVI file:\t{Colors.ENDC}{th_name_xvi}")
|
||||||
|
|
||||||
|
# Parse the Extended XVI file
|
||||||
|
stations = {}
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
with open(join(th_name_xvi), "r", encoding="utf-8") as f:
|
||||||
|
xvi_content = f.read()
|
||||||
|
xvi_stations, xvi_shots = xvi_content.split("XVIshots")
|
||||||
|
|
||||||
|
# Extract all the stations
|
||||||
|
for line in xvi_stations.split("\n"):
|
||||||
|
match = re.search(r"{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s([^@]+)(?:@([^\s}]*))?\s*}", line)
|
||||||
|
if match:
|
||||||
|
x = match.groups()[0]
|
||||||
|
y = match.groups()[1]
|
||||||
|
station_number = match.groups()[2]
|
||||||
|
namespace = match.groups()[3]
|
||||||
|
namespace_array = namespace.split(".") if namespace else []
|
||||||
|
station = station_number
|
||||||
|
if len(namespace_array) > 1:
|
||||||
|
station = "{}@{}".format(station_number, ".".join(namespace_array[0:-1]))
|
||||||
|
stations["{}.{}".format(x, y)] = [x, y, station]
|
||||||
|
|
||||||
|
# Extraire les valeurs x et y à partir des listes dans stations
|
||||||
|
x_values = [float(value[0]) for value in stations.values()]
|
||||||
|
y_values = [float(value[1]) for value in stations.values()]
|
||||||
|
|
||||||
|
# Trouver les min et max de x
|
||||||
|
x_min = float(min(x_values))
|
||||||
|
x_max = float(max(x_values))
|
||||||
|
|
||||||
|
# Trouver les min et max de y
|
||||||
|
y_min = float(min(y_values))
|
||||||
|
y_max = float(max(y_values))
|
||||||
|
|
||||||
|
x_ecart = x_max - x_min
|
||||||
|
y_ecart = y_max - y_min
|
||||||
|
|
||||||
|
# Afficher les résultats
|
||||||
|
# print("x_min:", x_min, "x_max:", x_max)
|
||||||
|
# print("y_min:", y_min, "y_max:", y_max)
|
||||||
|
# print("Écart max-min pour x:", x_ecart)
|
||||||
|
# print("Écart max-min pour y:", y_ecart)
|
||||||
|
|
||||||
|
# Extract all the lines
|
||||||
|
for line in xvi_shots.split("\n"):
|
||||||
|
match = re.search(r"^\s*{\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*(-?\d+\.\d+)\s*.*}", line )
|
||||||
|
if match:
|
||||||
|
x1 = match.groups()[0]
|
||||||
|
y1 = match.groups()[1]
|
||||||
|
x2 = match.groups()[2]
|
||||||
|
y2 = match.groups()[3]
|
||||||
|
key1 = "{}.{}".format(x1, y1)
|
||||||
|
key2 = "{}.{}".format(x2, y2)
|
||||||
|
# Splays won't have stations
|
||||||
|
station1 = stations[key1][2] if key1 in stations else None
|
||||||
|
station2 = stations[key2][2] if key2 in stations else None
|
||||||
|
lines.append([x1, y1, x2, y2, station1, station2])
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
if args.update == "th2":
|
||||||
|
th2_name = DEST_PATH + "/" + TH_NAME
|
||||||
|
else :
|
||||||
|
th2_name = DEST_PATH + "/Data/" + TH_NAME
|
||||||
|
output_path = f'{th2_name}-Extended.{FORMAT}'
|
||||||
|
|
||||||
|
print(f"{Colors.GREEN}Writing output to:\t\t{Colors.ENDC}{output_path}")
|
||||||
|
|
||||||
|
# Write TH2
|
||||||
|
if FORMAT == "th2":
|
||||||
|
th2_file_header = """encoding utf-8"""
|
||||||
|
|
||||||
|
th2_file = """
|
||||||
|
##XTHERION## xth_me_area_adjust {X_Min} {Y_Min} {X_Max} {Y_Max}
|
||||||
|
##XTHERION## xth_me_area_zoom_to 100
|
||||||
|
##XTHERION## xth_me_image_insert {insert_XVI}
|
||||||
|
|
||||||
|
{Copyright}
|
||||||
|
# File generated by pyCreate_th2.py version {version} date: {date}
|
||||||
|
|
||||||
|
# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min}
|
||||||
|
# y_min: {Y_Min}, y_max: {Y_Max} ecart : {Y_Max_Y_Min}
|
||||||
|
|
||||||
|
scrap SC-{name}_01 -station-names "" "@{name}" -projection extended -author {year} "{author}" -copyright {year} "{Copyright_Short}"
|
||||||
|
|
||||||
|
{points}
|
||||||
|
|
||||||
|
{names}
|
||||||
|
|
||||||
|
{lines}
|
||||||
|
|
||||||
|
endscrap"""
|
||||||
|
|
||||||
|
th2_point = """ point {x} {y} station -name {station}"""
|
||||||
|
th2_name = """ point {x} {y} station-name -align tr -scale xs -text {station}"""
|
||||||
|
|
||||||
|
th2_line = """ line u:Shot_Survey
|
||||||
|
{x1} {y1}
|
||||||
|
{x2} {y2}
|
||||||
|
endline
|
||||||
|
"""
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
th2_lines = []
|
||||||
|
th2_points = []
|
||||||
|
th2_names = []
|
||||||
|
other_scraps_extended = ""
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
th2_lines.append(th2_line.format(x1=line[0], y1=line[1], x2=line[2], y2=line[3]))
|
||||||
|
coords1 = "{}.{}".format(line[0], line[1])
|
||||||
|
|
||||||
|
if coords1 not in seen:
|
||||||
|
seen.add(coords1)
|
||||||
|
th2_points.append(th2_point.format(x=line[0], y=line[1], station=line[4]))
|
||||||
|
th2_names.append(th2_name.format(x=line[0], y=line[1], station=line[4]))
|
||||||
|
coords2 = "{}.{}".format(line[2], line[3])
|
||||||
|
|
||||||
|
if "{}.{}".format(line[2], line[3]) not in seen:
|
||||||
|
seen.add(coords2)
|
||||||
|
if line[5] != None:
|
||||||
|
th2_points.append(th2_point.format(x=line[2], y=line[3], station=line[5]))
|
||||||
|
th2_names.append(th2_name.format(x=line[2], y=line[3], station=line[5]))
|
||||||
|
|
||||||
|
|
||||||
|
if isfile(output_path):
|
||||||
|
print(f"{Colors.WARNING}Warning: {Colors.ENDC}{os.path.basename(output_path)}{Colors.WARNING} file already exists - nothing done{Colors.ENDC}")
|
||||||
|
else :
|
||||||
|
name = TARGET,
|
||||||
|
# print(f"{Colors.GREEN}Therion output path :\t{Colors.ENDC}{output_path}")
|
||||||
|
|
||||||
|
with open(str(output_path), "w+") as f:
|
||||||
|
f.write(th2_file_header)
|
||||||
|
f.write(th2_file.format(
|
||||||
|
name = name[0],
|
||||||
|
Copyright = Copyright,
|
||||||
|
Copyright_Short = Copyright_Short,
|
||||||
|
points="\n".join(th2_points),
|
||||||
|
lines="\n".join(th2_lines) if LINES else "",
|
||||||
|
names="\n".join(th2_names) if NAMES else "",
|
||||||
|
projection="extended",
|
||||||
|
projection_short="C",
|
||||||
|
author=Author,
|
||||||
|
year=datetime.now().year,
|
||||||
|
version = Version,
|
||||||
|
date=datetime.now().strftime("%Y.%m.%d-%H:%M:%S"),
|
||||||
|
X_Min=x_min*1.2,
|
||||||
|
X_Max=x_max*1.2,
|
||||||
|
Y_Min=y_min*1.2,
|
||||||
|
Y_Max=y_max*1.2,
|
||||||
|
X_Max_X_Min =x_ecart,
|
||||||
|
Y_Max_Y_Min =y_ecart,
|
||||||
|
insert_XVI = "{" + stations[next(iter(stations))][0] + "1 1.0} {"
|
||||||
|
+ stations[next(iter(stations))][1] + " "
|
||||||
|
+ stations[next(iter(stations))][2] +"} "
|
||||||
|
+ os.path.basename(th_name_xvi) + " 0 {}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if scrap_to_add >= 1 :
|
||||||
|
for i in range(scrap_to_add):
|
||||||
|
other_scraps_extended = other_scraps_extended + f"\tbreak\n\tSC-{name[0]}_{i+2:02}\n"
|
||||||
|
th2_scrap = """
|
||||||
|
|
||||||
|
scrap SC-{name}_{num:02} -station-names "" "@{name}" -projection extended -author {year} "{author}" -copyright {year} "{Copyright_Short}"
|
||||||
|
|
||||||
|
endscrap
|
||||||
|
|
||||||
|
"""
|
||||||
|
f.write(th2_scrap.format(
|
||||||
|
name=name[0],
|
||||||
|
author=Author,
|
||||||
|
Copyright_Short = Copyright_Short,
|
||||||
|
year=datetime.now().year,
|
||||||
|
num=f"{i+2:02}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Update -maps files #
|
||||||
|
#################################################################################################
|
||||||
|
if args.update == "":
|
||||||
|
config_vars = {
|
||||||
|
'fileName': TH_NAME,
|
||||||
|
'Author': Author,
|
||||||
|
'Copyright': Copyright,
|
||||||
|
'Scale' : SCALE,
|
||||||
|
'Target' : TARGET,
|
||||||
|
'map_comment' : map_comment,
|
||||||
|
'club' : club,
|
||||||
|
'thanksto' : thanksto,
|
||||||
|
'datat' : datat,
|
||||||
|
'wpage' : wpage,
|
||||||
|
'cs' : cs,
|
||||||
|
'other_scraps_plan' : other_scraps_plan,
|
||||||
|
'other_scraps_extended' : other_scraps_extended,
|
||||||
|
'file_info' : f"# File generated by pyCreate_th2.py version {Version} date: {datetime.now().strftime("%Y.%m.%d-%H:%M:%S")}",
|
||||||
|
}
|
||||||
|
|
||||||
|
process_template(DEST_PATH + '/template-maps.th', config_vars, DEST_PATH + '/' + TH_NAME + '-maps.th')
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Final therion compilation #
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
if args.update == "":
|
||||||
|
if final_therion_exe == True:
|
||||||
|
print(f"{Colors.GREEN}Final therion compilation{Colors.ENDC}")
|
||||||
|
PATH = os.path.dirname(args.survey_file) + "/" + TH_NAME + "/" + TH_NAME + ".thconfig"
|
||||||
|
|
||||||
|
compile_file(PATH, therion_path=therion_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
numpy
|
||||||
|
ttkthemes
|
||||||
|
matplotlib
|
||||||
|
pandas
|
||||||
|
Shapely
|
||||||
|
Fiona
|
||||||
|
pyproj
|
||||||
|
scipy
|
||||||
|
netCDF4
|
||||||
|
xarray
|
||||||
|
joblib
|
||||||
|
geopandas
|
||||||
|
motionless
|
||||||
|
salem
|
||||||
|
configparser
|
||||||
@@ -31,6 +31,9 @@ encoding utf-8
|
|||||||
# "jb-dessin.th2")
|
# "jb-dessin.th2")
|
||||||
source Synthese-PSM_LARRA-tot.th
|
source Synthese-PSM_LARRA-tot.th
|
||||||
|
|
||||||
|
# pour le MNT avec une résolution spaciale de 1" STRM10
|
||||||
|
source SIG/DEM_SRTM30_UTM30_PSM.th
|
||||||
|
|
||||||
# Add Coordinates
|
# Add Coordinates
|
||||||
#input Legendes/entrances_coordinates.th
|
#input Legendes/entrances_coordinates.th
|
||||||
|
|
||||||
|
|||||||
+480
-480
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user