diff --git a/src/cli/validate.py b/src/cli/validate.py index b90ea20..2bb3d6a 100644 --- a/src/cli/validate.py +++ b/src/cli/validate.py @@ -262,6 +262,100 @@ def validate_all_tracks_have_at_least_two_points( return result +def validate_track_points_only_change_in_two_directions_at_once(worlds: dict[str, list[MarkerSet]]) -> list[ValidationError]: + result = [] + + for world_name, marker_sets in worlds.items(): + for marker_set in marker_sets: + for marker in marker_set.markers: + if isinstance(marker, Track): + for i in range(len(marker.points) - 1): + x1, y1, z1 = marker.points[i] + x2, y2, z2 = marker.points[i + 1] + + changes = sum([ + x1 != x2, + y1 != y2, + z1 != z2, + ]) + + if changes > 2: + result.append( + ValidationError( + error_type = "invalid_track_movement", + world_name = world_name, + marker_set_name = marker_set.name, + marker_name = marker.name, + point_indices = (i, i + 1), + point_a = ValidationErrorPoint(*marker.points[i]), + point_b = ValidationErrorPoint(*marker.points[i + 1]), + note = "All of X, Y, and Z changed between these two points, please only change in two directions at once.", + ) + ) + + return result + +def validate_xy_zy_track_ratios(worlds: dict[str, list[MarkerSet]]) -> list[ValidationError]: + result = [] + + for world_name, marker_sets in worlds.items(): + for marker_set in marker_sets: + for marker in marker_set.markers: + if isinstance(marker, Track): + for i in range(len(marker.points) - 1): + x1, y1, z1 = marker.points[i] + x2, y2, z2 = marker.points[i + 1] + + if y1 == y2: + continue + + if x1 != x2 and z1 != z2: + continue + + dy = abs(y2 - y1) + dh = abs(x2 - x1) + abs(z2 - z1) + + if dh == 0: + result.append( + ValidationError( + error_type = "vertical_movement", + world_name = world_name, + marker_set_name = marker_set.name, + marker_name = marker.name, + point_indices = (i, i + 1), + point_a = ValidationErrorPoint(*marker.points[i]), + point_b = ValidationErrorPoint(*marker.points[i + 1]), + ) + ) + elif dy - dh > 1: + result.append( + ValidationError( + error_type = "excessive_slope", + world_name = world_name, + marker_set_name = marker_set.name, + marker_name = marker.name, + point_indices = (i, i + 1), + point_a = ValidationErrorPoint(*marker.points[i]), + point_b = ValidationErrorPoint(*marker.points[i + 1]), + dy = dy, + dh = dh, + ) + ) + elif dh - dy > 1: + result.append( + ValidationError( + error_type = "shallow_slope", + world_name = world_name, + marker_set_name = marker_set.name, + marker_name = marker.name, + point_indices = (i, i + 1), + point_a = ValidationErrorPoint(*marker.points[i]), + point_b = ValidationErrorPoint(*marker.points[i + 1]), + dy = dy, + dh = dh, + ) + ) + return result _tests: dict[str, Callable[[dict[str, list[MarkerSet]]], list[ValidationError]]] = { "No non-included files": validate_no_non_included_files, @@ -272,4 +366,6 @@ _tests: dict[str, Callable[[dict[str, list[MarkerSet]]], list[ValidationError]]] "No unused icons": validate_no_unused_icons, "No duplicate points": validate_no_duplicate_points, "All tracks have at least two points": validate_all_tracks_have_at_least_two_points, + "Track points only change in two directions at once": validate_track_points_only_change_in_two_directions_at_once, + "Track slopes are not too steep or too shallow": validate_xy_zy_track_ratios, }