Skip to content

Commit

Permalink
compute course_point distance/altitude from tcx file directly if poss…
Browse files Browse the repository at this point in the history
…ible

fix (partly) #44

add test
  • Loading branch information
Ptosiek committed Oct 12, 2023
1 parent db5d3ed commit 6f798a7
Show file tree
Hide file tree
Showing 8 changed files with 2,099 additions and 86 deletions.
178 changes: 97 additions & 81 deletions modules/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,95 +641,104 @@ def modify_course_points(self):
len_dist = len(self.distance)
len_alt = len(self.altitude)

# calculate course point distance
if not len_pnt_dist and len_dist:
course_points.distance = np.empty(len_pnt_lat)
if not len_pnt_alt and len_alt:
course_points.altitude = np.zeros(len_pnt_lat)

min_index = 0
for i in range(len_pnt_lat):
b_a_x = self.points_diff[0][min_index:]
b_a_y = self.points_diff[1][min_index:]
lon_diff = course_points.longitude[i] - self.longitude[min_index:]
lat_diff = course_points.latitude[i] - self.latitude[min_index:]
p_a_x = lon_diff[:-1]
p_a_y = lat_diff[:-1]
inner_p = (
b_a_x * p_a_x + b_a_y * p_a_y
) / self.points_diff_sum_of_squares[min_index:]
inner_p_check = np.where(
(0.0 <= inner_p) & (inner_p <= 1.0), True, False
)

min_j = None
min_dist_diff_h = np.inf
min_dist_delta = 0
min_alt_delta = 0
for j in list(*np.where(inner_p_check == True)):
h_lon = (
self.longitude[min_index + j]
+ (
self.longitude[min_index + j + 1]
- self.longitude[min_index + j]
)
* inner_p[j]
)
h_lat = (
self.latitude[min_index + j]
+ (
self.latitude[min_index + j + 1]
- self.latitude[min_index + j]
)
* inner_p[j]
)
dist_diff_h = get_dist_on_earth(
h_lon,
h_lat,
course_points.longitude[i],
course_points.latitude[i],
# calculate course point distance/altitude if not both already set
# If one is already set, it's not going to be overwritten
# But if both are already set there's no need to recalculate anything
if not len_pnt_dist or not len_pnt_alt:
if not len_pnt_dist and len_dist:
course_points.distance = np.empty(len_pnt_lat)
if not len_pnt_alt and len_alt:
course_points.altitude = np.zeros(len_pnt_lat)

min_index = 0

for i in range(len_pnt_lat):
b_a_x = self.points_diff[0][min_index:]
b_a_y = self.points_diff[1][min_index:]
lon_diff = course_points.longitude[i] - self.longitude[min_index:]
lat_diff = course_points.latitude[i] - self.latitude[min_index:]
p_a_x = lon_diff[:-1]
p_a_y = lat_diff[:-1]
inner_p = (
b_a_x * p_a_x + b_a_y * p_a_y
) / self.points_diff_sum_of_squares[min_index:]
inner_p_check = np.where(
(0.0 <= inner_p) & (inner_p <= 1.0), True, False
)

if (
dist_diff_h < self.config.G_GPS_ON_ROUTE_CUTOFF
and dist_diff_h < min_dist_diff_h
):
if min_j is not None and j - min_j > 2:
continue
min_j = j
min_dist_diff_h = dist_diff_h
min_dist_delta = (
get_dist_on_earth(
self.longitude[min_index + j],
self.latitude[min_index + j],
h_lon,
h_lat,
min_j = None
min_dist_diff_h = np.inf
min_dist_delta = 0
min_alt_delta = 0

for j in list(*np.where(inner_p_check == True)):
h_lon = (
self.longitude[min_index + j]
+ (
self.longitude[min_index + j + 1]
- self.longitude[min_index + j]
)
/ 1000
* inner_p[j]
)
if len_alt:
min_alt_delta = (
(
self.altitude[min_index + j + 1]
- self.altitude[min_index + j]
)
/ (
self.distance[min_index + j + 1]
- self.distance[min_index + j]
h_lat = (
self.latitude[min_index + j]
+ (
self.latitude[min_index + j + 1]
- self.latitude[min_index + j]
)
* inner_p[j]
)
dist_diff_h = get_dist_on_earth(
h_lon,
h_lat,
course_points.longitude[i],
course_points.latitude[i],
)

if (
dist_diff_h < self.config.G_GPS_ON_ROUTE_CUTOFF
and dist_diff_h < min_dist_diff_h
):
if min_j is not None and j - min_j > 2:
continue

min_j = j
min_dist_diff_h = dist_diff_h
min_dist_delta = (
get_dist_on_earth(
self.longitude[min_index + j],
self.latitude[min_index + j],
h_lon,
h_lat,
)
* min_dist_delta
/ 1000
)
if len_alt:
min_alt_delta = (
(
self.altitude[min_index + j + 1]
- self.altitude[min_index + j]
)
/ (
self.distance[min_index + j + 1]
- self.distance[min_index + j]
)
* min_dist_delta
)

if min_j is None:
min_j = 0
min_index = min_index + min_j
if min_j is None:
min_j = 0

if not len_pnt_dist and len_dist:
course_points.distance[i] = (
self.distance[min_index] + min_dist_delta
)
if not len_pnt_alt and len_alt:
course_points.altitude[i] = self.altitude[min_index] + min_alt_delta
min_index = min_index + min_j

if not len_pnt_dist and len_dist:
course_points.distance[i] = (
self.distance[min_index] + min_dist_delta
)
if not len_pnt_alt and len_alt:
course_points.altitude[i] = (
self.altitude[min_index] + min_alt_delta
)

# add climb tops
# if len(self.climb_segment):
Expand All @@ -755,6 +764,9 @@ def modify_course_points(self):
# TODO do not use float
and course_points.distance[0] != 0.0
):
app_logger.info(
f"Missing start of the course point, first value is {course_points.distance[0]}, inserting"
)
course_points.name = np.insert(course_points.name, 0, "Start")
course_points.latitude = np.insert(
course_points.latitude, 0, self.latitude[0]
Expand All @@ -770,6 +782,7 @@ def modify_course_points(self):
course_points.altitude = np.insert(
course_points.altitude, 0, self.altitude[0]
)

# add end course point
end_distance = None
if len(self.latitude) and len(course_points.longitude):
Expand All @@ -786,6 +799,9 @@ def modify_course_points(self):
and end_distance is not None
and end_distance > 5
):
app_logger.info(
f"Missing end of the course point last distance is {end_distance}, inserting"
)
course_points.name = np.append(course_points.name, "End")
course_points.latitude = np.append(
course_points.latitude, self.latitude[-1]
Expand Down
4 changes: 2 additions & 2 deletions modules/helper/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,13 +564,13 @@ async def send_livetrack_data_internal(self, quick_send=False):
await asyncio.sleep(5)
self.bt_cmd_lock = False
app_logger.error(
f"[BT] {timestamp_str} connect error, network status: {detect_network()}"
f"[BT] {timestamp_str} connect error, network status: {bool(detect_network())}"
)
self.config.logger.sensor.values["integrated"]["send_time"] = (
datetime.datetime.now().strftime("%H:%M") + "CE"
)
return
# print("[BT] {} connect, network status:{} {}".format(timestamp_str, detect_network(), count))
# print(f"[BT] {timestamp_str} connect, network status:{bool(detect_network())} {count}")

await asyncio.sleep(5)

Expand Down
4 changes: 4 additions & 0 deletions modules/helper/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,15 @@ async def download_maptile(
additional_save_paths = []

max_zoom_cond = True

if (
"max_zoomlevel" in map_config[map_name]
and z + 1 >= map_config[map_name]["max_zoomlevel"]
):
max_zoom_cond = False

min_zoom_cond = True

if (
"min_zoomlevel" in map_config[map_name]
and z - 1 <= map_config[map_name]["min_zoomlevel"]
Expand Down Expand Up @@ -243,6 +246,7 @@ async def download_maptile(
async def download_demtile(self, z, x, y):
if not detect_network():
return False

try:
os.makedirs(
f"maptile/{self.config.G_DEM_MAP}/{z}/{x}/",
Expand Down
57 changes: 55 additions & 2 deletions modules/loaders/tcx.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
"longitude": re.compile(r"<LongitudeDegrees>(?P<text>[^<]*)</LongitudeDegrees>"),
"altitude": re.compile(r"<AltitudeMeters>(?P<text>[^<]*)</AltitudeMeters>"),
"distance": re.compile(r"<DistanceMeters>(?P<text>[^<]*)</DistanceMeters>"),
"time": re.compile(r"<Time>(?P<text>[^<]*)</Time>"),
"course_point": re.compile(r"<CoursePoint>(?P<text>[\s\S]+)</CoursePoint>"),
"course_name": re.compile(r"<Name>(?P<text>[^<]*)</Name>"),
"course_point_type": re.compile(r"<PointType>(?P<text>[^<]*)</PointType>"),
"course_notes": re.compile(r"<Notes>(?P<text>[^<]*)</Notes>"),
"course_time": re.compile(r"<Time>(?P<text>[^<]*)</Time>"),
}


Expand All @@ -39,8 +41,9 @@ def load_file(cls, file):
"longitude": None,
"altitude": None,
"distance": None,
"time": None,
}
course_points = defaultdict(list)
course_points = defaultdict(lambda: np.array([]))

with open(file, "r", encoding="utf-8_sig") as f:
tcx = f.read()
Expand Down Expand Up @@ -82,6 +85,9 @@ def load_file(cls, file):
for m in patterns["distance"].finditer(track)
]
)
course["time"] = np.array(
[m.group("text").strip() for m in patterns["time"].finditer(track)]
)

match_course_point = patterns["course_point"].search(tcx)

Expand Down Expand Up @@ -117,6 +123,12 @@ def load_file(cls, file):
for m in patterns["course_notes"].finditer(course_point)
]
)
course_points["time"] = np.array(
[
m.group("text").strip()
for m in patterns["course_time"].finditer(course_point)
]
)

valid_course = True
if len(course["latitude"]) != len(course["longitude"]):
Expand Down Expand Up @@ -145,7 +157,7 @@ def load_file(cls, file):
course["altitude"] = np.array([])
course["latitude"] = np.array([])
course["longitude"] = np.array([])
course_points = defaultdict(lambda x: np.array([]))
course_points = defaultdict(lambda: np.array([]))
else:
# delete 'Straight' from course points
if len(course_points["type"]):
Expand All @@ -156,4 +168,45 @@ def load_file(cls, file):
for key in ["name", "latitude", "longitude", "notes", "type"]:
course_points[key] = course_points[key][not_straight_cond]

# if time is given in the field, try to set the course point distance/altitude directly from there
# if a point can not be found, let's fail and modify_course_point will try to compute it instead
if (
course["time"] is not None
and len(course["time"])
and len(course_points["time"])
):
distance_error = False
altitude_error = False

for point_time in course_points["time"]:
try:
index = np.where(course["time"] == point_time)[0][0]
except Exception: # noqa
# Point time not found in trackpoint reset and break
course_points.distance = np.array([])
course_points.altitude = np.array([])
break
if not distance_error:
try:
# course_point distance is set in [km]
course_points["distance"] = np.append(
course_points["distance"], course["distance"][index] / 1000
)
except IndexError:
distance_error = True
course_points.distance = np.array([])
if not altitude_error:
try:
# course_point altitude is set in [m]
course_points["altitude"] = np.append(
course_points["altitude"], course["altitude"][index]
)
except IndexError:
altitude_error = True
course_points.altitude = np.array([])

# do not keep these in memory
del course["time"]
del course_points["time"]

return course, course_points
2 changes: 1 addition & 1 deletion modules/pyqt/graph/pyqt_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ def get_image_file(self, use_mbtiles, map_name, z_draw, x, y):
else:
sql = (
f"select tile_data from tiles where "
f"zoom_level={z_draw} and tile_column={x} and tile_row={2 ** z_draw - 1 - y}"
f"zoom_level={z_draw} and tile_column={x} and tile_row={2**z_draw - 1 - y}"
)
img_file = io.BytesIO((self.cur.execute(sql).fetchone())[0])
return img_file
Expand Down
Loading

0 comments on commit 6f798a7

Please sign in to comment.