Debug pyCreateTh

This commit is contained in:
Alex38Lyon
2025-08-21 17:09:35 +02:00
parent 70ea9b352c
commit af1b72f5c4
53 changed files with 18 additions and 8180 deletions
+7 -5
View File
@@ -199,10 +199,10 @@ def load_config(args, configIni="config.ini"):
survey_keys = {
'Author': 'Author',
'Copyright1': None,
'Copyright2': None,
'Copyright3': None,
'Copyright_Short': 'CopyrightShort',
'Copyright1': 'Copyright',
'Copyright2': 'Copyright',
'Copyright3': 'Copyright',
'Copyright_Short': None,
'map_comment': 'mapComment',
'club': 'club',
'thanksto': 'thanksto',
@@ -221,6 +221,7 @@ def load_config(args, configIni="config.ini"):
config['Survey_Data']['Copyright2'],
config['Survey_Data']['Copyright3']
])
global_data.CopyrightShort = config['Survey_Data']['Copyright_Short']
elif attr:
setattr(global_data, attr, config['Survey_Data'][key])
@@ -232,7 +233,8 @@ def load_config(args, configIni="config.ini"):
'survey_prefix_name': 'SurveyPrefixName',
'shot_lines_in_th2_files': ('linesInTh2', lambda x: x.lower() == 'true'),
'station_name_in_th2_files': ('stationNamesInTh2', lambda x: x.lower() == 'true'),
'kSmooth': ('kSmooth', float),
'wall_lines_in_th2_files': ('wallLinesInTh2', lambda x: x.lower() == 'true'),
'kSmooth': ('kSmooth', float)
}
for key, value in app_keys.items():
+4 -3
View File
@@ -11,8 +11,8 @@ error_count = 0 # Compteur d'erreurs
## [Survey_Data] default values
Author = "Created by pyCreateTh.py"
Copyright = "# Copyright (C) pyCreateTh.py"
CopyrightShort = "Licence (C) pyCreateTh.py"
Copyright = "# Copyright(C) pyCreateTh.py"
CopyrightShort = "Licence(C) pyCreateTh.py"
mapComment = "Created by pyCreateTh.py"
cs = "UTM30"
club = "Therion"
@@ -28,7 +28,7 @@ therionPath = "C:/Therion/therion.exe"
SurveyPrefixName = f"Survey_"
linesInTh2 = True
stationNamesInTh2 = True
wallLineInTh2 = True
wallLinesInTh2 = True
kSmooth = 0.5
XVIScale = 100
@@ -100,6 +100,7 @@ th2File = """
##XTHERION## xth_me_image_insert {insert_XVI}
{Copyright}
# File generated by pyCreateTh.py version {version} date: {date}
# x_min: {X_Min}, x_max: {X_Max} ecart : {X_Max_X_Min}
+1 -1
View File
@@ -27,7 +27,7 @@ therion_path = C:\Program Files\Therion\therion.exe
# Survey prefix name use tu create Survey folders
survey_prefix_name = Explo_
# Options for Th2 files
# Options for th2 files
shot_lines_in_th2_files = False
station_name_in_th2_files = False
wall_lines_in_th2_files = False
+4 -4
View File
@@ -987,7 +987,7 @@ def create_th_folders(ENTRY_FILE,
th2_walls = []
if globalData.wallLineInTh2 :
if globalData.wallLinesInTh2 :
th2_walls, x_min, x_max, y_min, y_max = wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max)
@@ -1044,7 +1044,7 @@ def create_th_folders(ENTRY_FILE,
Copyright_Short = globalData.CopyrightShort,
points="\n".join(th2_points),
lines="\n".join(th2_lines) if globalData.linesInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLineInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLinesInTh2 else "",
names="\n".join(th2_names) if globalData.stationNamesInTh2 else "",
projection="plan",
projection_short="P",
@@ -1115,7 +1115,7 @@ def create_th_folders(ENTRY_FILE,
th2_walls = []
if globalData.wallLineInTh2 :
if globalData.wallLinesInTh2 :
th2_walls, x_min, x_max, y_min, y_max, = wall_construction_smoothed(df_lines, df_splays, x_min, x_max, y_min, y_max)
@@ -1171,7 +1171,7 @@ def create_th_folders(ENTRY_FILE,
Copyright_Short = globalData.CopyrightShort,
points="\n".join(th2_points),
lines="\n".join(th2_lines) if globalData.linesInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLineInTh2 else "",
walls="\n".join(th2_walls) if globalData.wallLinesInTh2 else "",
names="\n".join(th2_names) if globalData.stationNamesInTh2 else "",
projection="extended",
projection_short="C",
-22
View File
@@ -1,22 +0,0 @@
# 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
-307
View File
@@ -1,307 +0,0 @@
from dataclasses import dataclass,field
from enum import Enum
import pandas as pd
import numpy as np
from os.path import abspath, exists
from helpers.geo import *
#from geo import *
from subprocess import check_output, CalledProcessError
class Expedition(str, Enum):
"""A class to represent the different expeditions"""
UP2006 = "UP2006"
UP2008 = "UP2008"
UP2010 = "UP2010"
UP2014 = "UP2014"
UP2017 = "UP2017"
UP2019 = "UP2019"
UP2023 = "UP2023"
ENG08 = "ENG08"
ITA08 = "ITA08"
unknown = "unknown"
def assignExpedition(name: str) -> Expedition:
"""Assign the correct expedition given a date"""
target = Expedition.unknown
for expedition in Expedition:
if expedition.name.__contains__(name):
target = expedition
return target
@dataclass
class Cave:
"""A class that contains the information about a specific cavity"""
cadnum : str
exped : Expedition
comment : str
altitude : str
carto : str
explo_status : int
_index : int
coordinates : coordinatePairUTM = coordinatePairUTM(x=-999.,y=-999.)
name : str = "undefined"
length: float = 0
depth : float = 0
complete_name: str = "undefined"
explorers : str = "undefined"
_search_string : str = field(init=False)
_folder_path : str = field(init=False)
_sector_folder_path : str = field(init=False)
def __post_init__(self) -> None:
self._search_string=f"{self.cadnum} {self.name}"
# set the local folder path for the caves
def add_coordinates(self, coords : coordinatePairUTM) -> None:
"""A method for adding coordinates to the Cave entry"""
self.coordinates = coordinatePairUTM(coords.x,coords.y)
self.coordinates.add_lat_long_from_xy()
self.coordinates.add_sector()
self._folder_path = f"../therion/data/{self.cadnum[:-3]}/{self.name}"
self._sector_folder_path = f"../therion/data/{self.cadnum[:-3]}/{self.cadnum[:-3]}.th"
def makeTheriontemplate(self) -> str:
""" Generate an empty therion file using the cave data"""
TEMPLATE = f"""survey {self.name} -title '{self.complete_name}' \\
-attr cadnum {self.cadnum} \\
-attr exped {self.exped}\n
\tcentreline
\t\tcs epsg:32718
\t\t#fix ENT {self.coordinates.x} {self.coordinates.y} {self.altitude}
\t#explo-date {self.exped}
\t#team "{self.explorers}"
\tunits length meters
\t units compass clino degrees
\tdata normal from to tape compass clino
\t#<RENSEIGNER LES DONNEES ICI>
\tendcentreline
endsurvey
"""
return TEMPLATE
def make_folder(self) -> None:
"""A method which creates an empty folder for the cave of interest."""
filepath = abspath(self._folder_path).strip('\n')
print(filepath)
try:
check_output(f'mkdir {filepath}', shell=True)
cavename = self.name.strip("\n").strip(' ')
TH_FILE = f'{filepath}/{cavename}.th'
print("Name of the filepath",TH_FILE)
MD_FILE = f"{filepath}/NOTES.md"
if not exists(TH_FILE):
with open(TH_FILE, 'w+') as th_file:
th_file.write(self.makeTheriontemplate())
with open(MD_FILE, 'w+') as md_file:
md_file.write(self.comment)
except CalledProcessError:
TH_FILE = f"{filepath}/{self.name}.th"
MD_FILE = f"{filepath}/NOTES.md"
if not exists(TH_FILE):
with open(TH_FILE, 'w+') as th_file:
th_file.write(self.makeTheriontemplate())
with open(MD_FILE, 'w+') as md_file:
md_file.write(self.comment)
pass
def make_entry_in_sector_file(self) -> None:
"""adds an entry line to the sector .th file"""
with open(self._sector_folder_path, "r+") as f:
lines = f.readlines()
startindex = [x for x,line in enumerate(lines) if ("centreline" in line) or ("centerline" in line)]
formatted = f"""
#input {self.name}/{self.name}.th
"""
lines.insert(startindex[0]-1,formatted)
f.seek(0)
endindex = [x for x,line in enumerate(lines) if ("endcentreline" in line) or ("endcenterline" in line)]
name_as = f'"{self.complete_name}"'
formatted = f"""
fix ENT_{self.cadnum} {self.coordinates.x} {self.coordinates.y} {self.altitude}
station ENT_{self.cadnum} {name_as}
#equate ENT_{self.cadnum} 0@{self.name}
"""
lines.insert(endindex[0],formatted)
f.seek(0)
f.writelines(lines)
class CaveExistsError(Exception):
pass
class CadasterNotLoadedError(Exception):
pass
class CaveNotFoundError(Exception):
pass
class MoreCavesFoundError(Exception):
pass
@dataclass
class CaveCadaster:
"""A class that expects a list of caves and contains methods for reporting info about these caves"""
caves : list[Cave] = field(default_factory=list)
def add_entry(self, cave: Cave) -> None:
"""Enter an instance of a Cave to the database"""
self.caves.append(cave)
def check_existing(self, cave: Cave) -> None:
"""Check from a cave's coodinates that it does not already exist in the cadaster"""
for existing_cave in self.caves:
if cave.coordinates.x != float('nan'):
dist = np.sqrt((cave.coordinates.x - existing_cave.coordinates.x)**2 + (cave.coordinates.y - existing_cave.coordinates.y)**2)
if dist < 1:
raise CaveExistsError("the cave exists already")
def find_cave(self,search_string: str) -> list[Cave]:
"""Return a Cave instance given a cadastral number"""
targets = []
for cave in self.caves:
if cave._search_string.lower().__contains__(search_string.lower()):
targets.append(cave)
if len(targets)>=1:
return targets
else:
raise CaveNotFoundError("there is no cave with this cadastral number")
def delete_cave(self, search_string: str) -> None:
cave = self.find_cave(search_string)
proceed = input("Are you sure you want to delete this cave entry? Type <y/n> to proceed.")
if proceed == 'y':
self.caves.remove(cave)
print(f"Deleting the cave '{cave.name}' from the database")
else:
print(f"keeping the cave '{cave.name}' in the database")
def generate_dataframe(self) -> pd.DataFrame:
"""A method which generates a pandas.DataFrame out of the list of caves objects"""
lines = []
for cave in self.caves:
line = [cave.cadnum,
cave.coordinates.sector_name,
cave.complete_name,
f'{cave.name}',
cave.comment,
cave.coordinates.x,
cave.coordinates.y,
cave.altitude,
cave.length,
cave.depth,
cave.explorers,
cave.exped,
f"{cave.coordinates._orig_lat:.7f}",
f"{cave.coordinates._orig_long:.7f}",
cave.carto,
cave.explo_status
]
lines.append(line)
cols = ['cadnum',
'secteur',
'complete_name',
'name',
'comment',
'X_UTM18S',
'Y_UTM18S',
'altitude',
'length',
'depth',
'explorers',
'exped',
'latitude',
'longitude',
'carto',
'explo_status'
]
return pd.DataFrame(lines,columns=cols)
def write_to_file(self, output_path: str)-> None:
"""Writing the pandas.DataFrame to a file formatted exactly as expected for rereading into cave cadaster"""
df = self.generate_dataframe()
#df.sort_values(by='cadnum', inplace =True)
df.to_csv(output_path)
def generate_entry_from_file(df: pd.DataFrame, row: int) -> Cave:
"""A function to generate an entry from a specific line of a formatted dataframe"""
line = df.loc[row]
coords = coordinatePairUTM(x=line.X_UTM18S,y=line.Y_UTM18S)
coords.add_lat_long(lat=line.latitude,long=line.longitude)
coords.add_sector()
cave = Cave(
cadnum=line.cadnum,
exped= assignExpedition(str(line.exped)),
comment=line.comment,
altitude= line.altitude,
coordinates=coords,
name= line['name'],
complete_name= line.complete_name,
explorers= line.explorers,
length= line.length,
depth= line.depth,
carto=line.carto,
explo_status=line.explo_status,
_index = row
) # type: ignore
return cave
def initialise_database(filepath : str) -> CaveCadaster:
"""Reads a csv file containing the cave data into a CaveCadaster object"""
df = pd.read_csv(filepath)
cadaster = CaveCadaster()
for row in range(len(df)):
cadaster.add_entry(generate_entry_from_file(df,row))
return cadaster
# play with a subclass for the different sectors of cave exploration.
@dataclass
class CadasterSector(CaveCadaster):
"""A cave cadaster subclass"""
parent : CaveCadaster = CaveCadaster()
name : str = 'undefined'
root_cadnum : int = 999
caves: list[Cave] = field(init = False, default_factory=list)
next_cad_num : int = field(init=False)
def __post_init__(self) -> None:
self.caves = [cave for cave in self.parent.caves if str(cave.cadnum)[:3].__contains__(str(self.root_cadnum))]
self.next_cad_num = self.root_cadnum*1000+len(self.caves)+1
def add_entry(self, cave: Cave) -> None:
self.next_cad_num +=1
return super().add_entry(cave)
## test
-130
View File
@@ -1,130 +0,0 @@
from dataclasses import dataclass, field
from typing import Tuple
from shapely.geometry import shape, Point
import fiona
import pyproj as proj
from os.path import abspath
@dataclass
class coordinatePairUTM:
"""A class that expects two floats"""
x : float
y : float
cadnum_root : str = field(init=False)
sector_name : str = field(init=False)
_orig_lat : float = field(init=False)
_orig_long : float = field(init=False)
def add_lat_long(self,lat,long) -> None:
"""Attributes exploration zone to the cave"""
self._orig_lat,self._orig_long = lat,long
def add_lat_long_from_xy(self) -> None:
self._orig_lat,self._orig_long = transformer(crs_in='epsg:32718',crs_out='epsg:4326').transform(self.x,self.y)
def add_sector(self) -> None:
pt = Point(self._orig_long,self._orig_lat)
fp = abspath("../therion/data/gis/secteurs.shp")
multipolygons = read_multipolygons(fp)
intersects = [(pt.within(poly),properties) for poly,properties in multipolygons]
self.cadnum_root = "undefined"
self.sector_name = "undefined"
for intersect,property in intersects:
if intersect:
self.cadnum_root = property["Cadastre_I"]
self.sector_name = property["Nom"]
@dataclass
class coordinatePairLatLong:
"""A class containing Latitude and Longitude values"""
lat : str
long : str
hemisphere : tuple = field(init=False, default_factory=tuple)
lat_asfloat : float = field(init=False)
long_asfloat : float = field(init=False)
def __post_init__(self) -> None:
"""convert however the latitude and longitude are given to decimal format."""
self.parse_hemisphere()
if (self.lat.__contains__('°')) and (self.lat.__contains__("'")) and (self.lat.__contains__("''")):
self.parse_degree_minutes_seconds()
elif(self.lat.__contains__('°')) and (self.lat.__contains__("'")):
self.parse_degree_decimal_minutes()
else:
self.parse_decimal_degrees()
def parse_hemisphere(self) -> None:
"""Parses the lat/long coordinates given and determines in which hemisphere to go"""
if self.lat.__contains__('N'):
NH = 1
else:
NH = -1
if self.long.__contains__('E'):
EH = 1
else:
EH = -1
self.hemisphere = (NH,EH)
def parse_decimal_degrees(self) -> None:
"""Parses lat/long coordinates to a decimal float"""
self.lat_asfloat = self.hemisphere[0] * float(self.lat.strip('N').strip('S').split('°')[0])
self.long_asfloat = self.hemisphere[1] * float(self.long.strip('E').strip('W').split('°')[0])
def parse_degree_decimal_minutes(self) -> None:
"""Parses lat/long coordinates to a decimal float"""
lat_split = self.lat.strip('N').strip('S').split('°')
long_split = self.long.strip('E').strip('W').split('°')
lat_degree = float(lat_split[0])
long_degree = float(long_split[0])
lat_mins = float(lat_split[1].split("'")[0])
long_mins = float(long_split[1].split("'")[0])
self.lat_asfloat = self.hemisphere[0] * (lat_degree + lat_mins/60)
self.long_asfloat = self.hemisphere[1] * (long_degree + long_mins/60)
def parse_degree_minutes_seconds(self) -> None:
"""Parses lat/long coordinates to a decimal float"""
lat_split = self.lat.strip('N').strip('S').split('°')
long_split = self.long.strip('E').strip('W').split('°')
lat_degree = float(lat_split[0])
long_degree = float(long_split[0])
lat_mins = float(lat_split[1].split("'")[0])
long_mins = float(long_split[1].split("'")[0])
lat_secs = float(lat_split[1].split("'")[1])
long_secs = float(long_split[1].split("'")[1])
self.lat_asfloat = self.hemisphere[0] * (lat_degree + lat_mins/60 + lat_secs/3600)
self.long_asfloat = self.hemisphere[1] * (long_degree + long_mins/60 + long_secs/3600)
def read_multipolygons(filepath: str) -> list:
"""Reads a shapefile of exploration zones and makes a list of polygons"""
dataset = fiona.open(filepath)
multipolygons = [(shape(poly["geometry"]), poly["properties"]) for poly in dataset] # type: ignore
return multipolygons
def transformer(crs_out: str ,crs_in: str) -> proj.Transformer:
"""A function returning a transformer instance based on crs codes"""
return proj.Transformer.from_crs(crs_in, crs_out)
TRANSFORMER_LATLONG = transformer(crs_in="epsg:4326", crs_out="epsg:32718")
def convert_coords(coord : coordinatePairLatLong) -> coordinatePairUTM:
"""Convert from lat-long to UTM18S"""
X,Y = TRANSFORMER_LATLONG.transform(coord.lat_asfloat,coord.long_asfloat)
return coordinatePairUTM(x=X,y=Y)
import profile
import pstats
profile = profile.Profile()
#profile.runcall(convert_coords)
ps = pstats.Stats(profile)
ps.print_stats()
-60
View File
@@ -1,60 +0,0 @@
import pandas as pd
import time
# 2010-01-04T23:37:42Z
timenow = time.localtime()
timestamp = f"{timenow.tm_year}-{timenow.tm_mon}-{timenow.tm_mday}T{timenow.tm_hour}:{timenow.tm_min}:{timenow.tm_sec}Z"
TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<gpx
version="1.0"
creator="Centre Terre"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<time>'{time}'</time>
<bounds minlat="-52" minlon="-72" maxlat="49" maxlon="-70"/>
{data}
</gpx>"""
WPT_TEMPLATE = """
<wpt lat="{latitude}" lon="{longitude}">
<ele>{elevation}</ele>
<name>{name}</name>
<cmt>{comment}</cmt>
<desc>{description}</desc>
<sym>{symbol}</sym>
</wpt>"""
def pyToGPX(fp):
# "../../therion/data/SYNTHESE_POINTAGES.csv"
data = pd.read_csv(fp)
waypoints = ""
for index,line in data.iterrows():
if ("camp" in line.complete_name) or ("Camp" in line.complete_name):
symbol= "Lodging"
else:
symbol = "Waypoint"
formatted = WPT_TEMPLATE.format(
latitude= line.latitude,
longitude= line.longitude,
elevation= line.altitude,
comment= line.cadnum,
name= line.complete_name,
description= line.comment,
symbol= symbol
)
if "inf" not in formatted:
waypoints+=formatted
with open(fp.strip("csv") + "gpx", "w+") as f:
f.write(TEMPLATE.format(data=waypoints,time = timestamp))
-3
View File
@@ -1,3 +0,0 @@
import pandas as pd
data = pd.read_csv("../therion/data/SYNTHESE_POINTAGES.csv")
-19
View File
@@ -1,19 +0,0 @@
LANG = {
"main_menu" : {
"title" : {
"fr" : "Menu Principal",
"en" : "Main Menu",
"es" : "Menu principal"
},
"savebutton" : {
"fr" : "Sauvegarder",
"en" : "Save",
"es" : "Salvar"
},
"selectfile" : {
"fr" : "Selectionner un fichier",
"en" : "Select a file",
"es" : "Selectionar una fila"
}
}
}
@@ -1,16 +0,0 @@
matplotlib
pandas
Shapely
Fiona
pyproj
scipy
netCDF4
xarray
joblib
geopandas
motionless
salem
configparser
@@ -1,9 +0,0 @@
conda create --name ultima2 python==3.9
y
conda activate ultima2
conda install matplotlib==3.5.3 pandas==1.5.2 Shapely==1.8.4
Fiona==1.8.13.post1 pyproj==2.6.1.post1 scipy==1.9.3 netCDF4==1.5.7
xarray==2022.11.0 joblib==1.1.1 geopandas==0.9.0
y
pip install motionless==1.3.3
pip install salem==0.3.8
-63
View File
@@ -1,63 +0,0 @@
from dataclasses import dataclass, field
import matplotlib.pyplot as plt
from salem import GoogleVisibleMap, Map, transform_geopandas
import geopandas as gpd
import pandas as pd
from shapely.geometry import Point, MultiPoint
from helpers.geo import coordinatePairUTM
from helpers.cadaster import CaveCadaster,Cave, Expedition
@dataclass
class SatelliteMapPlot:
# Configure image aspect
size_x : int
size_y : int
dpi : int
scale : float = 0.013988764
points : list[coordinatePairUTM] = field(init = False)
point_names : list[str] = field(init=False)
new_x : float = field(init = False)
new_y : float = field(init=False)
def add_points(self, cadaster : CaveCadaster) -> None:
self.points = [cave.coordinates for cave in cadaster.caves]
self.point_names = [cave.name for cave in cadaster.caves]
def add_point_to_plot(self, x: float, y: float) -> None:
self.new_x = x
self.new_y = y
def plot_map(self):
# Get the Google Static image
g = GoogleVisibleMap(y=[self.new_y-0.64*self.scale, self.new_y+0.64*self.scale], x=[self.new_x-1.5*self.scale, self.new_x+1.5*self.scale],
scale=2, # scale is for more details
maptype='satellite',
size_x=self.size_x, size_y=self.size_y
)
# the google static image is a standard rgb image
ggl_img = g.get_vardata()
sm = Map(g.grid, nx=self.size_x, factor=1)
sm.set_rgb(ggl_img) # add the background rgb image
# prepare the figure
fig, ax = plt.subplots(figsize=(self.size_x/self.dpi,self.size_y/self.dpi), dpi=self.dpi)
# plot 1
x, y = sm.grid.transform([self.new_x],[self.new_y])
xi, yi = sm.grid.transform([p._orig_long for p in self.points],[p._orig_lat for p in self.points])
ax.scatter(x, y, zorder= 100, s=5,color="blue", marker = "d") # type:ignore
ax.scatter(xi, yi, zorder= 100, s=3,color="red", marker = "d") # type:ignore
for name,x,y in zip(self.point_names,xi,yi):
ax.text(x+.0001,y+.0001,name,fontsize=5,color = "red")
sm.plot(ax=ax)
fig.patch.set_facecolor('black') # type:ignore
return fig,ax
@@ -1,34 +0,0 @@
import tkinter as tk
class ScrollbarFrame(tk.Frame):
"""
Extends class tk.Frame to support a scrollable Frame
This class is independent from the widgets to be scrolled and
can be used to replace a standard tk.Frame
"""
def __init__(self, parent, **kwargs):
tk.Frame.__init__(self, parent, **kwargs)
# The Scrollbar, layout to the right
vsb = tk.Scrollbar(self, orient="vertical")
vsb.pack(side="right", fill="y")
# The Canvas which supports the Scrollbar Interface, layout to the left
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.canvas.pack(side="left", fill="both", expand=True)
# Bind the Scrollbar to the self.canvas Scrollbar Interface
self.canvas.configure(yscrollcommand=vsb.set)
vsb.configure(command=self.canvas.yview)
# The Frame to be scrolled, layout into the canvas
# All widgets to be scrolled have to use this Frame as parent
self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg'))
self.canvas.create_window((4, 4), window=self.scrolled_frame, anchor="nw")
# Configures the scrollregion of the Canvas dynamically
self.scrolled_frame.bind("<Configure>", self.on_configure)
def on_configure(self, event):
"""Set the scroll region to encompass the scrolled frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
-243
View File
@@ -1,243 +0,0 @@
import re
from os.path import dirname, abspath, join, splitext, basename
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))
-5
View File
@@ -1,5 +0,0 @@
import numpy as np
a = np.array([1,2,3,4,5])
print(a)
-114
View File
@@ -1,114 +0,0 @@
import tempfile
import shutil
import os
from os.path import join
import subprocess
import re
#################################################################################################
# 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 compile_template(template, template_args, **kwargs):
try:
log = ""
tmpdir = tempfile.mkdtemp()
config = template.format(**template_args, tmpdir=tmpdir.replace("\\", "/"))
print(f"{Colors.YELLOW}{config}{Colors.ENDC}\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()
log = tmp2.read()
if kwargs["cleanup"]:
shutil.rmtree(tmpdir)
print("\n" )
return log, tmpdir
except Exception as e:
print(f"{Colors.ERROR}Error: Therion template compilation error: {Colors.ENDC}{e}")
#################################################################################################
def compile_file(filename, **kwargs):
try:
tmpdir = os.path.dirname(filename)
log_file = join(tmpdir, "log.log").replace("\\", "/")
therion_path = kwargs["therion_path"] if "therion_path" in kwargs else "therion"
# print(f"{Colors.BLUE}therion_path: {Colors.ENDC}{therion_path}")
# print(f"{Colors.BLUE}filename: {Colors.ENDC}{filename}")
# print(f"{Colors.BLUE}log_file: {Colors.ENDC}{log_file}")
# subprocess.check_output('''"{}" "{}" -l "{}"'''.format(therion_path, filename, log_file), shell=True, )
result = subprocess.run(
[therion_path, filename, "-l", log_file],
stdout=subprocess.PIPE, # Capture de la sortie standard
stderr=subprocess.PIPE, # Capture des erreurs
shell=True
)
stdout_with_tabs = "\n".join("\t" + line for line in result.stdout.decode().splitlines())
# Si la commande échoue, result.returncode sera non nul
if result.returncode != 0:
# Affichage des erreurs et de la sortie standard
print(f"{Colors.ERROR}Error during Therion compilation:{Colors.ENDC}")
print(f"{Colors.WARNING}stdout: {Colors.YELLOW}{stdout_with_tabs}{Colors.ENDC}")
print(f"{Colors.ERROR}stderr: \n{result.stderr.decode()}{Colors.ENDC}")
else:
# Si la commande réussit, affichez la sortie standard
print(f"{Colors.GREEN}Therion compilation succeeded.\n{Colors.YELLOW}{stdout_with_tabs}{Colors.ENDC}")
except Exception as e:
print(f"{Colors.ERROR}Error: Therion file {Colors.ENDC}{filename}{Colors.ERROR} compilation error: {Colors.ENDC}{e}")
#################################################################################################
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
lengthre = re.compile(r".*Total length of survey legs =\s*(\S+)m")
depthre = re.compile(r".*Vertical range =\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}
@@ -1,460 +0,0 @@
from dataclasses import dataclass, field
import re
@dataclass
class Date:
"""A class which represents a string formatted date"""
year : int = 2000
month : int = 1
day : int = 1
date_string : str = field(init = False)
def __post_init__(self) -> None:
self.date_string = f"{self.year}.{self.month:02d}.{self.day:02d}"
@dataclass
class StationWithComment:
name : str
comment : str
command : str = field(init=False)
def __post_init__(self) -> None:
self.command = f'station {self.name} "{self.comment}"'
@dataclass
class LineLRUD:
from_station : str
left : float
right : float
up : float
down : float
@dataclass
class DataLine:
from_station : str
to_station : str
tape : float
compass : float
@dataclass
class NormalDataLine(DataLine):
clino : float
@dataclass
class DivingDataLine(DataLine):
to_depth : float
from_depth : float
@dataclass
class Centreline:
explo_date : Date = Date()
explorers : list[str] = field(init= False, default_factory= list)
type : str = "normal"
data_header : list[str] = field(init= False, default_factory= list)
units_length : dict[str, str] = field(default_factory=lambda: {"units length" : "meters"})
units_compass_clino : dict[str, str] = field(default_factory=lambda: {"units compass clino": "degrees"})
lrud_reader : list[str] = field(default_factory=lambda: ["data", "dimensions", "station", "left", "right", "up", "down"])
data : list[DataLine] = field(init=False, default_factory= list)
lrud_data : list[LineLRUD] = field(init=False, default_factory= list)
commented_stations : list[StationWithComment] = field(init=False, default_factory=list)
_string_repr : str = field(init=False, default_factory= str)
def __post_init__(self) -> None:
if self.type == 'normal':
self.data_header = ["data", "normal", "from", "to", "tape", "compass", "clino"]
elif self.type == "normal_backclino":
self.data_header = ["data", "normal", "from", "to", "tape", "compass", "backclino"]
elif self.type == "normal_backcompass":
self.data_header = ["data", "normal", "from", "to", "tape", "backcompass", "clino"]
elif self.type == "normal_backcompass_backclino":
self.data_header = ["data", "normal", "from", "to", "tape", "backcompass", "backclino"]
elif self.type == "diving":
self.data_header = ["data", "diving", "from", "fromdepth","to", "todepth", "tape", "compass"]
elif self.type == "diving_backcompass":
self.data_header = ["data", "diving", "from", "fromdepth","to", "todepth", "tape", "backcompass"]
def add_explorers(self, explorers : list[str]) -> None:
self.explorers += explorers
def add_dataline(self, line: DataLine) -> None:
self.data+= [line]
def add_station_line(self, station : StationWithComment) -> None:
self.commented_stations.append(station)
def add_LRUDdataline(self, line: LineLRUD) -> None:
self.lrud_data+= [line]
def add_Date(self, date: str) -> None:
DATE = date.split(".")
self.date = Date(year=int(DATE[0]),month=int(DATE[0]),day=int(DATE[2]))
self.explo_date = Date(year=int(DATE[0]),month=int(DATE[1]),day=int(DATE[2]))
def update_type(self, type: str):
self.type = type
self.__post_init__()
def add_string_repr(self) -> None:
explorers = ""
for explorer in self.explorers:
explorers += f"explo-team {explorer}\n\t"
formatted_data : str = ""
formatted_lrud : str = ""
formatted_comments : str = ""
for line,lrud_line in zip(self.data,self.lrud_data):
if "clino" in self.data_header:
formatted_data += f"""
{line.from_station}\t{line.to_station}\t{line.tape}\t{line.compass}\t{line.clino}\t""" # type: ignore
formatted_lrud += f"""
{lrud_line.from_station}\t{lrud_line.left}\t{lrud_line.right}\t{lrud_line.up}\t{lrud_line.down}\t"""
elif "todepth" in self.data_header:
formatted_data += f"""
{line.from_station}\t{line.from_depth}\t{line.to_station}\t{line.to_depth}\t{line.tape}\t{line.compass}\t""" # type: ignore
formatted_lrud += f"""
{lrud_line.from_station}\t{lrud_line.left}\t{lrud_line.right}\t{lrud_line.up}\t{lrud_line.down}\t"""
for comment in self.commented_stations:
formatted_comments += f"""
{comment.command}"""
self._string_repr = f"""
centreline
explo-date {self.explo_date.date_string}
date {self.explo_date.date_string}
{explorers}
{join(self.data_header)}
{formatted_data}
{join(self.lrud_reader)}
{formatted_lrud}
{formatted_comments}
endcentreline"""
@dataclass
class Survey:
name : str
entrance : str = field(init= False, default_factory= str)
centrelines : list[Centreline] = field(init= False, default_factory= list)
_string_repr : str = field(init=False, default_factory= str)
def add_centrelines(self, centrelines: list[Centreline]) -> None:
self.centrelines += centrelines
def add_entrance(self, entrance : str) -> None:
self.entrance = entrance
def add_string_repr(self) -> None:
centrelines = ""
for centreline in self.centrelines:
centrelines += f"{centreline._string_repr}\n"
self._string_repr = f"""
## a survey compiled from Visual Topo Data using the visual_therion.py script
survey "{self.name}" -entrance {self.entrance}
{centrelines}
endsurvey
"""
@dataclass
class StrategyParser:
input_str : str
compass : str = "normal"
clino : str = "normal"
strategy_name: str = "normal"
def __post_init__(self) -> None:
if "Dir,Dir,Inv" in self.input_str:
self.clino = "back"
self.strategy_name = "normal_backclino"
elif "Inv,Inv,Dir" in self.input_str or "Inv,Dir,Dir" in self.input_str:
self.compass = "back"
if "Prof" in self.input_str:
self.strategy_name = "diving_backcompass"
else:
self.strategy_name = "normal_backcompass"
elif "Inv,Inv,Inv" in self.input_str:
self.compass = "back"
self.clino = "back"
self.strategy_name = "normal_backcompass_backclino"
elif ("Dir Dir Dir" in self.input_str) and ("Prof") in self.input_str:
self.strategy_name = "diving"
def join(l : list[str])-> str:
newstr = ""
for elem in l:
newstr += f"{elem} "
return newstr
def find_entrance_stn(data: list[str], format : str) -> str:
if format == "tro":
"""Search the visual topo file for the entrance station"""
for c,l in enumerate(data):
if 'Entree' in l:
entrance_stations = re.findall(r"(?<=Entree\s).+",l)
else:
for c,l in enumerate(data):
if '<Entree>' in l:
entrance_stations = re.findall(r"(?<=<Entree>)[0-9a-z]+",l)
return entrance_stations[0] # type: ignore
def return_centreline_params(data: list[str], fmt: str):
if fmt == "tro":
return return_centreline_params_tro(data)
else:
return return_centreline_params_trox(data)
def return_centreline_params_trox(data):
start,end = [],[]
survey_dates = []
surveyor_groups = []
for c,l in enumerate(data):
if ('Param' in l) and ('/Param' not in l):
if 'Comment' in data[c+1]:
if len(start) >= 1:
end.append(c-1)
start.append(c+2)
else:
if len(start) >= 1:
end.append(c-1)
start.append(c+1)
reg_explodate = re.findall(r'(?<=Date\=")\d\d\/\d\d\/\d\d\d\d', l)
reg_explodate = [elem for elem in reg_explodate[0].split("/")]
explodate = "{yyyy}.{mm}.{dd}".format(yyyy =reg_explodate[2], mm =reg_explodate[1], dd = reg_explodate[0])
if len(explodate) == 0:
survey_dates.append('')
else:
survey_dates.append(re.sub(r"/",".",explodate))
tp = re.findall(r"(?<=Topo réalisée par )[\w+\s]*",l)
if len(tp) == 0:
surveyor_groups.append('')
else:
surveyor_groups.append(tp[0].split(' '))
elif 'Configuration' in l:
end.append(c-1)
return surveyor_groups,survey_dates,start,end
def return_centreline_params_tro(data):
# find the parameters of the file.
start,end = [],[]
survey_dates = []
surveyor_groups = []
for c,l in enumerate(data):
if 'Param' in l:
if len(start) >= 1:
end.append(c-1)
start.append(c+1)
explodate = re.findall(r"\d\d.\d\d.\d\d", l)
if len(explodate) == 0:
survey_dates.append('')
else:
survey_dates.append(re.sub(r"-",".",explodate[0]))
tp = re.findall(r"(?<=Topo réalisée par )[\w+\s]*",l)
if len(tp) == 0:
surveyor_groups.append('')
else:
surveyor_groups.append(tp[0].split(' '))
elif 'Configuration' in l:
end.append(c-1)
return surveyor_groups,survey_dates,start,end
def parseFloat(x: str) -> float:
try:
X = float(x)
return X
except ValueError:
X = 0.
return X
def parse_CommentedStations(lines : list[str]) -> list[StationWithComment]:
parsed_lines = [[elem for elem in line.split(";") if elem != ""] for line in lines[1:]]
stations_list = []
for line in parsed_lines:
if len(line) > 1:
stn_name = [elem for elem in line[0].split(" ") if elem != ""][0]
comment = line[1]
station = StationWithComment(stn_name,comment)
stations_list.append(station)
return stations_list
def parse_LRUDS(lines: list[str], format : str) -> list[LineLRUD]:
if format == "tro":
LRUDlines = [[elem for elem in line.split(" ") if elem != ""] for line in lines[:]]
elif format == "trox":
print("parsing a trox file")
LRUDlines = []
LRUDlines.append([elem.split("=")[-1].strip('"') for elem in lines[0].split(" ")[1:] if elem != ""])
LRUDlines = LRUDlines + [["*"]+[elem.split("=")[-1].strip('"') for elem in line.split(" ")[1:] if elem != ""] for line in lines[:]]
else:
LRUDlines = [[]]
lrud_lines = []
for c,line in enumerate(LRUDlines):
if "*" in line[0] and len(line) >=9:
LRUDline =LineLRUD(LRUDlines[c][1],parseFloat(line[5]),parseFloat(line[6]),parseFloat(line[7]),parseFloat(line[8]))
elif len(line) >=9:
LRUDline =LineLRUD(line[1],parseFloat(line[5]),parseFloat(line[6]),parseFloat(line[7]),parseFloat(line[8]))
else:
print("skipping empty line {}".format(c))
if len(line) >=9:
if line[0] != line[1]:
#check there is no asterisk
lrud_lines.append(LRUDline) # type:ignore
return lrud_lines
def parse_normal_data(lines: list[str], format: str ) -> list[NormalDataLine]:
if format == "tro":
datalines = [[elem for elem in line.split(" ") if elem != ""] for line in lines[1:]]
elif format == "trox":
print("parsing a trox file")
datalines: list = []
datalines.append([elem.split("=")[-1].strip('"') for elem in lines[0].split(" ")[1:] if elem != ""])
for line in lines[1:]:
if "Dep=" in line:
datalines.append([elem.split("=")[-1].strip('"') for elem in line.split(" ")[1:] if elem != ""])
else:
datalines.append(["*"]+[elem.split("=")[-1].strip('"') for elem in line.split(" ")[1:] if elem != ""])
else:
datalines = [[]]
dataLines = []
for c,line in enumerate(datalines):
if "*" in line[0] and len(line) >=9:
dataLine = NormalDataLine(datalines[c-1][1],line[1],float(line[2]),float(line[3]),float(line[4]))
print(line)
elif len(line) >=9:
dataLine = NormalDataLine(line[0],line[1],float(line[2]),float(line[3]),float(line[4]))
else:
print("skipping empty line {}".format(c))
if dataLine.tape != 0: # type:ignore
dataLines.append(dataLine) # type:ignore
return dataLines
def parse_diving_data(lines: list[str], format: str) -> list[DivingDataLine]:
if format == "tro":
datalines = [[elem for elem in line.split(" ") if elem != ""] for line in lines[1:]]
elif format == "trox":
print("parsing a trox file")
datalines = []
datalines.append([elem.split("=")[-1].strip('"') for elem in lines[0].split(" ")[1:] if elem != ""])
datalines = datalines + [["*"]+[elem.split("=")[-1].strip('"') for elem in line.split(" ")[1:] if elem != ""] for line in lines[1:]]
else:
print("oops empty")
datalines = [[]]
dataLines = []
for c,line in enumerate(datalines[:]): # keep and index and ignore the first one.
if len(line) >=9:
if "*" in line and len(datalines[c-1]) > 9:
dataLine = DivingDataLine(from_depth= float(datalines[c][4]),
from_station= datalines[c-1][1],
to_depth= float(line[4]),
to_station=line[1],
tape= float(line[2]),
compass =float(line[3]))
else:
dataLine = DivingDataLine(from_depth= float(datalines[c][4]),
from_station= line[0],
to_depth= float(line[4]),
to_station=line[1],
tape= float(line[2]),
compass =float(line[3]))
if dataLine.tape != 0:
dataLines.append(dataLine)
return dataLines
def make_centrelines_list(data : list[str], format: str ) -> list[Centreline]:
surveyor_groups,survey_dates,starts,ends = return_centreline_params(data, fmt= format) # type:ignore
centrelines : list[Centreline] = []
for start,end,date in zip(starts,ends,survey_dates):
newCentreline = Centreline()
newCentreline.add_Date(date)
if format == "tro":
header = data[start-1]
else:
if "Comment" in data[start-1]:
header = ""
for elem in data[start-2].split(" ")[1:]:
header += elem.split("=")[-1].strip('"')+" "
else:
header = ""
for elem in data[start-1].split(" ")[1:]:
header += elem.split("=")[-1].strip('"')+" "
print("data header: ", newCentreline.data_header)
strategy = StrategyParser(header)
newCentreline.update_type(strategy.strategy_name)
station_lines = parse_CommentedStations(data[start:end])
if "normal" in strategy.strategy_name:
lrudLines = parse_LRUDS(data[start:end], format = format)
dataLines = parse_normal_data(data[start:end], format= format)
for dataLine,lrudLine in zip(dataLines,lrudLines):
newCentreline.add_dataline(dataLine)
newCentreline.add_LRUDdataline(lrudLine)
elif "diving" in strategy.strategy_name:
lrudLines = parse_LRUDS(data[start:end], format = format)
dataLines = parse_diving_data(data[start:end], format = format)
for dataLine,lrudLine in zip(dataLines,lrudLines):
newCentreline.add_dataline(dataLine)
newCentreline.add_LRUDdataline(lrudLine)
for line in station_lines:
newCentreline.add_station_line(line)
newCentreline.add_string_repr()
centrelines.append(newCentreline)
return centrelines
-993
View File
@@ -1,993 +0,0 @@
"""
#############################################################################################
# #
# 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)
@@ -1,20 +0,0 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"cSpell.words": [
"datat",
"ecart",
"ENDC",
"endlayout",
"endscrap",
"thanksto",
"thconfig",
"therion",
"wpage"
]
}
}
-15
View File
@@ -1,15 +0,0 @@
numpy
ttkthemes
matplotlib
pandas
Shapely
Fiona
pyproj
scipy
netCDF4
xarray
joblib
geopandas
motionless
salem
configparser
@@ -1,2 +0,0 @@
Folder where Therion outputs are exported
File diff suppressed because it is too large Load Diff
@@ -1,18 +0,0 @@
#Template for pyCreate_th2.py
encoding utf-8
{Copyright}
{file_info}
map MP-{fileName}-Plan-tot -title "{fileName}"
SP-{Target}_01
{other_scraps_plan} break
endmap
map MC-{fileName}-Extended-tot -title "{fileName}"
SC-{Target}_01
{other_scraps_extended} break
endmap
@@ -1,11 +0,0 @@
#Template for pyCreate_th2.py
encoding utf-8
{Copyright}
{file_info}
to add this survey in a main survey add in your -tot.th file:
input Data/{fileName}/{fileName}-tot.th
equate
@@ -1,20 +0,0 @@
#Template for pyCreate_th2.py
encoding utf-8
{Copyright}
{file_info}
survey {fileName} -title "{fileName}"
input Data/{fileName}.th
## Pour le plan
input Data/{fileName}-Plan.th2
## Pour la coupe développée
input Data/{fileName}-Extended.th2
## Appel des maps
input {fileName}-maps.th
endsurvey
@@ -1,389 +0,0 @@
#Template for pyCreate_th2.py
encoding utf-8
###############################################################################################
{Copyright}
{file_info}
###############################################################################################
## 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
###############################################################################################
-810
View File
@@ -1,810 +0,0 @@
# 2024.04.12 created by TopoDroid v 5.1.40
# This work is under the Creative Commons Attribution-ShareAlike-NonCommecial License:
# <http://creativecommons.org/licenses/by-nc-sa/4.0/>
survey Geophysicaya_01_entree -title "Geophysicalskaya 01 entree"
# depart pt fr24 A00
centerline
date 2024.04.12
team "Alexandre Pont"
team "Jean-Philippe Grandcolas"
team "Gaël Cazes"
#cs long-lat
#fix PTR_FR24_A00_Geophysicalskaya 66.394767 37.673152 856 # Alt from Google Earth
cs UTM42
fix PTR_FR24_A00_Geophysicalskaya 0270251 4172755 870 # gps alex / Altitude PhA
station PTR_FR24_A00_Geophysicalskaya "Geophysicalskaya" entrance air-draught
#explo-date 19??
#explo-team " "
#explo-date 1972
#explo-team "Groupe AVEN"
units length meters
units compass clino degrees
data normal from to length compass clino
# extend auto
PTR_FR24_A00_Geophysicalskaya . 0.77 171.9 -42.1
PTR_FR24_A00_Geophysicalskaya . 0.59 345.7 -42.1
PTR_FR24_A00_Geophysicalskaya . 1.07 280.3 -83.5
PTR_FR24_A00_Geophysicalskaya . 0.17 77.9 54.4
extend right
PTR_FR24_A00_Geophysicalskaya 1 1.16 155.5 -59.6 # PTR_FR24_A00
# extend auto
1 . 0.87 1.2 3.5
1 . 1.07 23.9 2.8
1 . 0.31 19.8 -43.1
1 . 1.25 51.5 -14.6
1 . 0.68 111.1 0.1
1 . 1.60 79.2 -1.7
1 . 1.28 30.6 0.9
extend right
1 2 2.94 69.9 5.4
# extend auto
2 . 1.15 251.7 -12.0
2 . 0.94 232.5 -35.4
2 . 0.66 215.5 -45.5
2 . 1.12 264.4 3.9
2 . 0.62 276.1 24.2
2 . 0.54 237.2 50.1
2 . 1.70 313.3 -1.9
2 . 1.24 332.6 0.8
2 . 0.51 224.5 60.7
2 . 0.84 261.0 -49.5
2 . 1.55 171.2 -80.3
extend vertical
2 3 1.50 179.0 -57.3
# extend auto
3 . 2.59 62.1 15.4
3 . 2.72 85.4 4.2
3 . 1.29 124.2 -6.9
3 . 0.99 147.5 -9.4
3 . 1.76 179.1 -6.3
3 . 1.80 207.9 -0.5
3 . 0.97 237.3 1.0
3 . 0.90 274.2 16.6
3 . 0.56 339.4 68.3
3 . 0.80 199.3 73.4
3 . 0.70 172.9 25.6
3 . 0.75 159.0 -44.1
extend vertical
3 4 1.76 189.9 -14.9
# extend auto
4 . 1.05 44.5 -4.3
4 . 0.97 76.9 -5.0
4 . 0.73 42.8 42.7
4 . 1.00 66.1 -61.5
4 . 1.44 74.5 -48.2
extend right
4 5 1.40 85.5 -40.9
# extend auto
5 . 0.81 6.9 0.7
5 . 0.71 27.4 -2.1
5 . 0.53 167.6 23.1
5 . 0.65 132.1 31.3
5 . 0.44 62.0 64.9
5 . 1.01 64.7 5.2
5 . 0.44 168.0 -6.4
extend right
5 6 2.38 87.9 -41.5
# extend auto
6 . 1.44 15.0 35.4
6 . 2.17 37.6 29.2
6 . 1.52 158.1 9.7
6 . 1.90 217.0 16.6
6 . 0.35 200.8 -51.1
6 . 0.92 207.6 56.8
6 . 1.74 114.8 30.9
6 . 3.32 100.0 3.8
extend right
6 7 7.07 91.7 -15.0
# extend auto
7 . 6.16 334.1 28.8
7 . 7.14 1.2 22.1
7 . 8.14 37.3 7.9
7 . 9.31 97.1 -2.5
7 . 13.25 121.4 -3.4
7 . 1.63 133.8 62.7
7 . 0.89 120.0 -58.0
7 . 10.93 240.5 4.6
7 . 11.74 219.7 -1.8
7 . 2.04 201.6 42.7
7 . 4.65 171.2 18.7
7 . 12.10 165.1 1.7
7 . 7.11 160.3 -24.2
extend right
7 8 8.55 29.2 8.0
extend vertical
7 9 9.73 170.9 -20.0
# extend auto
9 . 10.71 91.8 8.0
9 . 15.71 255.1 -5.7
9 . 15.41 240.0 -11.6
9 . 16.44 209.0 -19.0
9 . 1.28 159.3 -40.3
9 . 5.37 162.4 -26.3
9 . 4.72 168.9 4.0
9 . 11.77 164.8 -4.8
extend ignore
9 10 12.21 150.7 -17.3
# extend auto
10 . 10.35 44.2 19.0
10 . 12.19 67.8 12.0
10 . 15.37 87.8 8.0
10 . 16.74 174.0 -15.4
10 . 19.62 149.0 -12.4
10 . 13.94 243.2 -9.9
10 . 3.13 143.3 -33.1
10 . 3.51 152.5 71.2
10 . 3.97 127.8 42.1
10 . 13.50 128.0 13.8
extend right
10 11 12.27 146.2 -10.7
# extend auto
11 . 7.08 162.3 -17.0
11 . 9.80 130.5 -7.6
11 . 3.62 100.9 40.2
11 . 10.67 102.6 20.2
11 . 2.07 130.7 -41.8
11 . 6.76 109.7 -20.5
extend right
11 12 12.24 114.3 -8.3
# extend auto
12 . 8.54 37.7 5.2
12 . 1.68 158.4 -1.0
12 . 4.09 135.3 -19.6
12 . 4.71 88.5 30.3
12 . 6.41 114.8 -33.4
12 . 2.42 77.4 -31.4
extend right
12 13 6.78 114.0 -18.5
# extend auto
13 . 3.87 34.7 9.8
13 . 1.37 324.4 -82.3
13 . 3.24 88.5 -60.6
extend right
13 14 4.88 89.5 -28.4
# extend auto
14 . 1.90 229.0 13.3
14 . 1.16 206.0 9.9
14 . 1.71 137.9 -8.0
14 . 0.96 64.1 -6.7
14 . 1.00 174.3 71.3
14 . 1.33 1.1 42.9
14 . 1.88 315.2 -2.0
14 . 3.96 336.6 -12.0
extend vertical
14 15 4.25 9.4 -26.4
# extend auto
15 . 1.96 165.5 -35.4
15 . 1.56 220.7 -35.0
15 . 1.72 230.2 -62.6
15 . 2.42 329.3 1.0
extend right
15 16 1.98 107.9 -85.5
# extend auto
16 . 2.24 54.5 -56.7
16 . 1.39 80.2 22.8
16 . 1.11 81.6 57.5
extend right
16 17 9.21 105.0 -24.3
# extend auto
17 . 5.24 201.1 0.5
17 . 10.15 142.2 2.4
17 . 3.50 281.7 51.8
17 . 2.97 146.8 71.6
17 . 4.22 74.9 41.0
17 . 5.82 76.1 12.2
17 . 11.16 25.7 0.7
17 . 6.69 8.9 11.3
17 . 19.90 41.3 -3.3
17 . 5.72 76.6 -23.9
17 . 9.74 70.1 -23.9
extend right
17 18 8.45 75.9 -21.0
# extend auto
18 . 10.52 10.4 10.7
18 . 14.54 42.0 7.9
18 . 10.86 162.9 15.0
18 . 19.17 144.0 9.3
18 . 4.55 87.6 -27.3
18 . 8.61 87.7 -19.4
18 . 4.40 115.4 64.5
18 . 11.46 97.3 30.4
extend right
18 PTR_FR24_A01_19 19.59 100.6 -1.2 # 19 : PTR_FR24_A01_ depart rg
# extend auto
PTR_FR24_A01_19 . 14.69 214.8 8.8
PTR_FR24_A01_19 . 10.74 18.1 -12.8
PTR_FR24_A01_19 . 15.31 359.0 -19.2
PTR_FR24_A01_19 . 15.06 15.0 -27.2
PTR_FR24_A01_19 . 6.51 15.4 -41.7
PTR_FR24_A01_19 . 12.68 59.4 -17.0
PTR_FR24_A01_19 . 14.74 79.6 -5.3
PTR_FR24_A01_19 . 6.13 55.5 71.4
PTR_FR24_A01_19 . 27.16 160.6 16.8
PTR_FR24_A01_19 . 9.64 120.5 -5.5
PTR_FR24_A01_19 . 18.68 120.1 1.9
PTR_FR24_A01_19 . 11.54 133.9 6.1
extend right
PTR_FR24_A01_19 20 21.34 131.3 7.9
# extend auto
20 . 11.72 60.1 -2.3
20 . 24.25 83.3 -1.4
20 . 8.41 145.3 64.6
20 . 15.97 129.9 40.0
20 . 12.64 231.9 15.9
20 . 14.12 200.4 21.2
20 . 1.81 55.9 -34.2
20 . 8.24 91.6 -16.3
extend right
20 21 13.25 120.2 6.1
# extend auto
21 . 21.20 79.1 3.5
21 . 27.03 99.6 3.0
21 . 13.82 216.3 7.0
21 . 19.89 184.8 5.7
21 . 9.16 133.2 57.8
21 . 18.70 139.3 28.9
21 . 6.14 146.7 -11.8
21 . 14.14 141.3 -4.8
extend right
21 22 24.07 137.6 0.7
# extend auto
22 . 12.50 88.5 1.2
22 . 17.53 116.7 -3.7
22 . 19.99 127.7 -5.0
22 . 16.46 244.5 7.0
22 . 19.33 215.1 2.6
22 . 7.32 196.2 44.9
22 . 20.67 160.7 10.9
22 . 10.38 191.9 -19.2
22 . 14.93 152.8 -17.5
22 . 7.97 144.4 70.7
extend right
22 23 21.01 155.1 -13.1
# extend auto
23 . 17.29 237.9 6.0
23 . 23.42 201.3 0.9
23 . 35.04 176.1 -0.8
23 . 8.90 201.5 63.0
23 . 13.84 158.5 49.6
23 . 11.95 47.7 8.8
23 . 11.29 75.3 6.2
23 . 2.26 22.3 -23.8
23 . 4.76 140.1 -33.2
23 . 12.10 142.3 -15.0
extend right
23 PTR_FR24_A02_24 24.18 162.8 -5.1 # PTR_FR24_A02
# extend auto
PTR_FR24_A02_24 . 25.81 49.0 1.5
PTR_FR24_A02_24 . 10.69 64.4 48.5
PTR_FR24_A02_24 . 12.91 82.2 35.5
PTR_FR24_A02_24 . 13.66 130.4 -8.2
PTR_FR24_A02_24 . 20.98 109.3 -6.0
PTR_FR24_A02_24 . 3.75 92.4 -27.6
PTR_FR24_A02_24 . 14.87 96.4 -16.9
PTR_FR24_A02_24 . 17.48 214.8 1.9
PTR_FR24_A02_24 . 11.90 199.5 48.4
extend left
PTR_FR24_A02_24 25 12.58 197.1 -14.8
# extend auto
25 . 12.47 15.4 15.8
25 . 7.94 103.2 2.4
25 . 4.98 152.3 -2.1
25 . 9.92 262.7 3.9
25 . 10.09 239.2 -10.3
25 . 4.68 243.1 57.1
25 . 5.95 207.1 21.9
25 . 8.39 201.3 -11.5
25 . 2.38 278.8 -19.9
25 . 6.27 228.3 -31.6
extend left
25 26 8.73 195.3 -32.9
# extend auto
26 . 1.39 81.4 -17.5
26 . 1.95 103.6 -26.9
26 . 3.44 235.8 -6.6
26 . 1.22 165.5 51.8
26 . 1.11 159.7 1.3
26 . 3.32 174.8 -51.6
26 . 4.14 157.0 -49.3
extend right
26 27 7.92 164.8 -40.9
# extend auto
27 . 4.69 253.0 5.1
27 . 10.44 232.5 -8.4
27 . 1.05 285.8 56.5
27 . 1.55 165.3 20.1
27 . 1.74 163.9 -30.9
27 . 4.38 36.4 10.5
27 . 9.30 95.3 -14.0
27 . 10.56 106.6 -17.1
27 . 8.66 145.4 -24.0
extend right
27 28 11.40 156.3 -21.1
# extend auto
28 . 9.43 59.0 -5.6
28 . 7.54 103.6 -3.7
28 . 6.01 344.5 46.6
28 . 3.38 165.1 64.7
28 . 1.33 166.7 -35.5
28 . 15.04 276.5 4.6
28 . 18.01 248.3 1.6
28 . 25.17 216.7 2.3
28 . 6.82 205.2 -16.5
28 . 12.45 181.1 -11.1
28 . 7.15 173.8 20.1
extend right
28 29 30.02 156.5 -2.9
# extend auto
29 . 15.48 47.8 6.9
29 . 19.97 76.7 8.9
29 . 15.77 242.5 12.9
29 . 17.79 194.6 8.3
29 . 8.31 323.1 36.7
29 . 5.53 36.7 69.3
29 . 11.26 104.2 29.5
29 . 2.37 130.2 -36.2
29 . 6.88 120.7 -16.1
29 . 4.33 335.1 -31.8
29 . 10.90 327.5 -7.4
extend right
29 PTR_FR24_A03_30 14.82 114.9 -3.8 # PTR_FR24_A03
# extend auto
PTR_FR24_A03_30 . 14.79 9.8 13.2
PTR_FR24_A03_30 . 13.04 38.2 11.4
PTR_FR24_A03_30 . 9.91 114.8 5.8
PTR_FR24_A03_30 . 11.98 121.5 5.2
PTR_FR24_A03_30 . 12.15 102.6 5.5
PTR_FR24_A03_30 . 19.22 141.5 4.7
PTR_FR24_A03_30 . 17.68 214.5 7.3
PTR_FR24_A03_30 . 22.98 243.0 9.9
PTR_FR24_A03_30 . 7.73 229.7 50.4
PTR_FR24_A03_30 . 6.25 170.5 71.2
PTR_FR24_A03_30 . 8.19 87.4 56.2
PTR_FR24_A03_30 . 3.64 77.5 -8.7
PTR_FR24_A03_30 . 9.72 85.5 35.9
extend right
PTR_FR24_A03_30 31 13.97 82.1 5.2
# extend auto
31 . 1.66 48.2 24.6
31 . 3.63 200.3 3.0
31 . 5.22 162.9 1.8
31 . 3.62 173.0 -21.9
31 . 6.84 124.0 24.9
extend vertical
PTR_FR24_A03_30 32 19.55 186.9 -3.7
# extend auto
32 . 12.52 93.1 14.6
32 . 6.09 266.3 6.0
32 . 5.85 161.2 88.6
32 . 1.43 237.3 -81.9
32 . 9.73 186.5 5.2
32 . 16.59 51.4 9.3
32 . 10.56 300.8 12.6
extend right
32 33 16.05 159.4 -13.4
# extend auto
33 . 6.78 79.1 18.5
33 . 7.28 261.6 22.0
33 . 3.68 152.9 86.4
33 . 1.56 276.4 -79.5
33 . 11.85 153.0 14.7
33 . 9.07 49.4 27.8
33 . 9.20 315.8 34.4
33 . 9.92 218.7 11.6
extend left
33 34 11.85 199.8 1.5
# extend auto
34 . 3.22 305.0 10.7
34 . 8.37 103.7 9.0
34 . 3.09 351.7 86.2
34 . 1.53 45.9 -65.0
34 . 13.94 55.2 5.8
34 . 6.44 341.0 12.6
34 . 6.04 266.4 12.2
34 . 9.82 137.4 23.0
extend left
34 35 8.67 207.7 10.2
# extend auto
35 . 10.92 78.6 10.6
35 . 2.43 145.9 89.0
35 . 8.63 238.7 12.7
35 . 1.65 183.4 -85.5
35 . 14.95 112.3 14.2
35 . 13.10 169.4 8.3
35 . 5.74 335.5 2.9
extend left
35 36 8.78 247.8 10.0
# extend auto
36 . 8.67 172.9 5.4
36 . 11.41 172.7 5.7
extend vertical
35 PTR_FR24_A05_37 8.69 172.9 5.3 # PTR_FR24_A05_ sur bite gypse
# extend auto
PTR_FR24_A05_37 . 3.24 244.8 23.0
PTR_FR24_A05_37 . 12.43 53.8 9.2
PTR_FR24_A05_37 . 1.84 131.1 88.3
PTR_FR24_A05_37 . 1.57 30.9 -68.2
PTR_FR24_A05_37 . 5.17 144.4 13.6
PTR_FR24_A05_37 . 9.93 317.7 7.3
PTR_FR24_A05_37 . 14.47 40.0 8.2
extend right
PTR_FR24_A05_37 38 6.07 93.8 4.6
# extend auto
38 . 6.91 74.6 13.8
38 . 5.24 227.8 9.0
38 . 1.88 174.7 84.5
38 . 1.45 284.8 -79.0
extend right
38 39 8.85 167.0 -12.8
# extend auto
39 . 4.91 275.0 13.4
39 . 9.05 50.0 15.8
39 . 2.46 176.7 80.6
39 . 1.53 270.8 -79.1
39 . 11.08 162.1 6.6
extend left
39 40 7.84 201.4 2.0
# extend auto
40 . 5.54 161.6 7.0
40 . 4.78 330.3 14.9
40 . 1.81 225.3 82.6
40 . 1.41 334.7 -75.2
40 . 6.94 104.0 8.2
40 . 6.83 298.6 8.6
extend left
40 41 10.61 248.7 3.2
# extend auto
41 . 7.60 125.4 -2.9
41 . 9.91 177.4 0.9
41 . 5.06 349.4 3.7
41 . 1.17 212.9 87.7
41 . 1.91 211.4 -84.2
extend left
41 42 13.83 266.1 -4.4
# extend auto
42 . 5.93 349.8 22.7
42 . 5.17 176.3 0.7
42 . 1.62 170.9 82.3
42 . 0.87 93.4 -86.0
42 . 6.30 23.3 14.7
42 . 8.51 261.2 5.3
extend left
42 43 6.06 256.2 -1.4
# extend auto
43 . 1.38 205.9 5.4
43 . 3.94 26.6 26.9
43 . 1.68 332.7 83.5
43 . 1.20 236.7 -54.7
extend left
43 44 4.52 310.2 2.9
# extend auto
44 . 2.95 226.3 -24.4
44 . 13.10 48.2 38.4
44 . 9.24 293.2 1.2
44 . 2.88 156.7 26.1
44 . 1.30 70.9 -78.2
44 . 1.09 325.4 88.0
extend left
44 45 7.07 311.1 -8.8
# extend auto
45 . 3.71 168.8 4.8
45 . 4.46 311.2 4.7
45 . 4.81 291.7 80.5
45 . 1.26 249.1 -77.8
extend left
45 46 12.62 275.8 -24.3
# extend auto
46 . 2.61 352.6 3.1
46 . 6.04 170.3 10.9
46 . 2.45 335.9 82.8
46 . 1.46 119.6 -84.4
46 . 5.22 219.0 5.2
46 . 4.03 84.6 8.5
extend left
46 47 12.85 242.1 -2.5
# extend auto
47 . 1.22 150.2 -0.6
47 . 2.17 304.4 8.3
47 . 1.52 358.0 88.3
47 . 0.86 333.6 -89.5
47 . 1.96 106.6 4.6
47 . 2.83 11.8 0.8
47 . 4.13 248.9 9.4
extend left
47 PTR_FR24_A06_48 4.78 245.3 2.3 # PTR_FR24_A06_
# extend auto
PTR_FR24_A06_48 . 1.19 107.7 2.8
PTR_FR24_A06_48 . 1.31 301.2 0.8
PTR_FR24_A06_48 . 0.96 5.6 85.7
PTR_FR24_A06_48 . 1.39 244.8 -84.8
extend vertical
PTR_FR24_A06_48 49 2.32 182.0 -33.1
# extend auto
49 . 1.22 157.0 13.6
49 . 1.47 325.7 18.8
49 . 0.43 241.9 78.5
49 . 0.38 134.1 -76.3
extend left
49 50 5.87 234.0 -3.0 # laminoire a suivre...
45 51 10.31 349.4 22.5
# extend auto
51 . 0.61 284.6 2.3
51 . 18.47 134.2 8.0
51 . 0.85 149.6 80.7
51 . 1.19 104.7 -70.1
extend right
51 52 9.88 83.0 6.3
# extend auto
52 . 12.11 146.7 25.2
52 . 10.12 194.2 12.5
52 . 2.64 351.8 -7.1
52 . 1.09 235.2 85.3
52 . 1.83 356.1 -84.6
extend right
52 53 14.63 93.9 15.2
# extend auto
53 . 7.84 182.3 4.1
53 . 6.10 11.3 3.4
53 . 2.69 207.3 80.8
53 . 3.04 241.0 -64.2
53 . 15.74 219.1 -1.3
53 . 19.02 245.7 -1.8
53 . 10.01 266.9 -0.9
53 . 5.30 326.9 -1.3
53 . 10.98 128.2 -0.3
53 . 6.92 76.7 2.3
53 . 12.49 87.6 1.9
extend right
53 54 10.80 87.7 -12.5 # 54 pt topo 2023 35
# extend auto
54 . 2.39 101.4 12.5
54 . 4.68 303.6 7.3
54 . 1.73 58.8 10.0
54 . 1.36 172.9 -79.4
54 . 3.95 205.3 85.0
extend vertical
# bouclage pt 37
54 PTR_FR24_A05_37 5.29 2.7 -33.4
extend right
31 55 4.93 146.6 -17.1
# extend auto
55 . 2.42 5.0 7.4
55 . 1.27 190.1 19.0
55 . 3.78 80.2 84.2
55 . 3.44 24.9 46.1
55 . 0.88 75.0 -80.7
55 . 7.00 73.4 -4.9
55 . 4.33 110.6 1.0
extend right
55 56 10.18 93.9 -13.6
# extend auto
56 . 4.07 201.2 12.0
56 . 3.09 351.6 12.8
56 . 4.81 144.5 84.5
56 . 1.12 221.7 -86.5
56 . 6.05 155.1 7.6
56 . 8.48 58.1 11.5
56 . 3.87 318.5 7.1
extend right
56 57 10.94 104.5 6.3
# extend auto
57 . 6.10 200.7 2.4
57 . 7.67 24.3 3.6
57 . 8.37 326.4 2.4
57 . 14.02 82.6 9.0
57 . 10.30 150.9 9.9
57 . 2.11 124.2 86.8
57 . 2.77 211.2 -74.8
extend right
57 58 17.08 121.9 12.1
# extend auto
58 . 5.52 39.9 6.2
58 . 2.32 214.2 -6.6
58 . 1.30 110.9 85.1
58 . 1.68 214.4 -86.9
58 . 9.81 93.9 5.8
extend right
58 59 12.74 122.3 2.7
# extend auto
59 . 10.93 50.2 -2.3
59 . 5.96 214.6 -0.5
59 . 1.84 268.1 85.4
59 . 2.49 255.9 -78.7
59 . 7.94 146.5 -0.1
59 . 14.86 358.7 0.9
59 . 12.57 120.6 -0.2
59 . 14.29 120.7 -0.2
extend right
59 PTR_FR24_A07_60 12.55 120.7 -0.2 # PTR_FR24_A07_
# extend auto
PTR_FR24_A07_60 . 2.52 58.6 13.3
PTR_FR24_A07_60 . 2.35 223.8 -4.8
PTR_FR24_A07_60 . 0.99 125.8 85.3
PTR_FR24_A07_60 . 1.70 218.9 -78.5
extend left
PTR_FR24_A07_60 61 4.83 250.4 -37.7
# extend auto
61 . 3.45 254.0 2.6
61 . 1.18 104.3 12.3
61 . 0.78 259.3 85.4
61 . 1.53 149.1 -78.0
extend right
61 62 5.21 135.6 6.7 # non marqué, etroiture dans gypse
57 63 6.36 15.5 -2.8
# extend auto
63 . 9.55 276.4 5.7
63 . 4.16 93.3 12.7
63 . 2.46 266.1 86.3
63 . 1.05 94.3 -84.5
63 . 19.59 5.7 -6.9
63 . 13.22 185.6 10.5
63 . 8.38 286.2 -8.9
extend right
63 64 9.58 30.7 -8.4
# extend auto
64 . 8.81 35.5 -2.2
64 . 9.83 116.7 4.0
64 . 8.26 198.9 5.0
64 . 15.67 259.1 -3.3
64 . 19.65 280.3 -2.1
64 . 1.56 325.3 84.6
64 . 1.12 160.8 -84.0
extend left
64 65 9.67 324.1 -4.7
# extend auto
65 . 9.73 2.3 4.8
65 . 15.44 218.1 2.2
65 . 13.76 111.4 5.6
65 . 10.17 334.2 4.7
65 . 17.78 281.5 0.3
65 . 1.56 219.4 87.6
65 . 1.54 352.4 -88.9
extend left
65 66 21.63 297.4 -0.1
# extend auto
66 . 3.71 25.2 7.0
66 . 1.93 206.0 1.0
66 . 0.57 271.5 77.6
66 . 1.04 185.3 -87.3
extend left
# arret etroiture
66 67 10.91 307.6 -0.9
# extend auto
67 . 0.49 190.2 -3.8
67 . 0.64 10.0 1.8
67 . 0.54 8.3 -74.5
67 . 0.27 295.2 68.0
extend right
65 68 10.62 16.4 5.9
# extend auto
68 . 2.69 79.6 -3.1
68 . 0.44 266.3 1.3
68 . 0.69 352.1 84.2
68 . 1.01 4.1 -82.3
extend vertical
68 69 3.07 4.0 18.7
# extend auto
69 . 6.43 84.1 10.2
69 . 8.88 250.5 8.4
69 . 3.56 340.6 73.8
69 . 1.39 247.8 -75.6
69 . 21.08 0.8 12.5
69 . 25.84 49.5 4.3
69 . 22.31 278.6 1.0
69 . 22.91 286.3 2.6
69 . 4.16 101.9 -0.2
69 . 2.16 158.4 0.4
extend left
69 70 10.37 320.9 12.9
# extend auto
70 . 19.22 342.6 26.8
70 . 10.19 205.4 5.1
70 . 21.67 46.9 12.3
70 . 15.46 86.4 7.8
70 . 13.80 109.1 0.8
70 . 1.95 197.2 -79.6
70 . 1.70 213.8 81.6
70 . 6.20 330.6 75.3
extend left
70 71 17.68 261.0 -3.7
# extend auto
71 . 1.08 188.6 -1.8
71 . 1.20 30.5 4.7
71 . 0.89 270.8 80.4
71 . 1.30 312.9 -83.8
extend left
71 72 10.98 332.5 16.7
# extend auto
72 . 16.22 350.3 22.6
72 . 9.66 128.1 12.8
72 . 25.59 63.1 11.2
72 . 3.55 206.1 -2.0
72 . 5.55 186.6 89.6
72 . 1.24 111.2 -69.5
extend right
72 PTR_FR24_A04_73 15.82 68.9 10.2 # PTR_FR24_A04_
# extend auto
PTR_FR24_A04_73 . 15.77 63.7 12.6
PTR_FR24_A04_73 . 16.28 230.0 -4.7
PTR_FR24_A04_73 . 11.77 179.7 -1.8
PTR_FR24_A04_73 . 25.50 115.7 -3.1
PTR_FR24_A04_73 . 0.16 323.7 4.2
PTR_FR24_A04_73 . 5.18 215.9 80.5
PTR_FR24_A04_73 . 2.37 127.6 -86.7
extend right
PTR_FR24_A04_73 74 7.12 128.1 -2.5
# extend auto
74 . 8.44 213.7 2.6
74 . 7.51 27.5 14.8
74 . 4.81 166.1 80.9
74 . 2.13 55.6 -83.3
74 . 7.31 179.1 -0.3
74 . 16.99 103.5 0.8
74 . 18.71 67.3 -0.2
extend right
# boucle
74 70 9.14 165.7 -24.0
70 75 16.58 70.3 -0.5
# extend auto
75 . 10.00 7.4 14.2
75 . 0.34 159.5 -1.0
75 . 3.82 50.7 78.9
75 . 1.36 56.9 -81.4
75 . 10.89 68.1 6.4
75 . 13.26 308.8 16.6
extend right
75 76 10.72 88.7 -11.3
# extend auto
76 . 9.39 30.2 1.7
76 . 5.90 177.9 -6.0
76 . 1.18 12.4 83.8
76 . 1.44 94.0 -88.2
76 . 3.71 357.8 31.7
76 . 9.77 343.8 26.0
76 . 2.34 215.8 10.0
extend right
76 PTR_FR24_A08_77 22.34 88.2 5.6 # PTR_FR24_A08
# extend auto
PTR_FR24_A08_77 . 0.71 354.7 5.3
PTR_FR24_A08_77 . 0.95 174.6 1.2
PTR_FR24_A08_77 . 1.00 5.7 81.4
PTR_FR24_A08_77 . 0.52 173.3 -79.4
extend right
# arret etr
PTR_FR24_A08_77 78 5.38 89.6 13.8
extend left
PTR_FR24_A04_73 79 19.38 314.8 9.8
# extend auto
79 . 4.59 214.6 2.4
79 . 4.98 35.5 8.8
79 . 4.73 290.3 67.0
79 . 0.97 206.0 -81.0
extend left
79 PTR_FR24_A09_80 4.80 307.5 39.3 # PTR_FR24_A09 jonction equipe audra pt 2
endcenterline
endsurvey
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1,6 +0,0 @@
therion 6.3.1 (2024-11-22)
- using Proj 9.4.1, compiled against 9.4.1
initialization file: C:\Program Files\Therion/therion.ini
reading ... done
C:\Program Files\Therion\therion.exe: error -- can't open file for input -- B3_Amonts.thconfig
Press ENTER to exit!