Table of Contents
Introduction
What Makes a Triangle Right-Angled?
Real-World Scenario: Structural Integrity Monitoring in Smart Bridges
Methods to Detect a Right Angle in Code
Complete Implementation with Test Cases
Best Practices for Robust Geometry Checks
Conclusion
Introduction
At first glance, checking if a triangle is right-angled seems like a middle-school math problem. But in the real world—especially in civil engineering and infrastructure monitoring—this simple geometric test can mean the difference between safety and collapse.
Modern smart infrastructure uses real-time sensor data to validate structural geometry. A deviation from expected right angles in critical joints can signal deformation, stress, or damage. In this article, we’ll explore how to programmatically verify a right-angled triangle using Python, grounded in a live use case from structural health monitoring, with production-ready, error-free code.
What Makes a Triangle Right-Angled?
A triangle is right-angled if one of its internal angles is exactly 90 degrees. By the Pythagorean theorem, this happens if and only if:
The square of the longest side equals the sum of the squares of the other two sides.
Given sides a
, b
, and c
(with c
as the longest):
a² + b² == c²
But in code, we must account for:
Real-World Scenario: Structural Integrity Monitoring in Smart Bridges
Consider a smart suspension bridge equipped with IoT strain gauges and displacement sensors at key truss joints. Many of these joints are designed as right-angled triangular supports—a geometry chosen for optimal load distribution.
Every second, the bridge’s monitoring system:
Reads 3D coordinates from sensors at three joint points
Computes the three side lengths
Checks if the triangle remains right-angled within tolerance
If the angle drifts (e.g., due to metal fatigue or seismic shift), the system triggers an early-warning alert for engineers—potentially preventing catastrophic failure.
This isn’t hypothetical: systems like these are deployed on the Golden Gate Bridge and Millau Viaduct, where geometry = safety.
Methods to Detect a Right Angle in Code
We’ll accept either three side lengths or three 2D/3D points, validate the triangle, and apply the Pythagorean check with tolerance.
import math
from typing import Tuple, Union
def distance(p1: Tuple[float, ...], p2: Tuple[float, ...]) -> float:
"""Compute Euclidean distance between two points (2D or 3D)."""
return math.sqrt(sum((a - b) ** 2 for a, b in zip(p1, p2)))
def is_valid_triangle_sides(a: float, b: float, c: float, tol: float = 1e-9) -> bool:
"""Check triangle inequality."""
return (a + b > c + tol) and (a + c > b + tol) and (b + c > a + tol)
def is_right_angled_by_sides(a: float, b: float, c: float, tol: float = 1e-9) -> bool:
"""Check if triangle with given sides is right-angled."""
if not is_valid_triangle_sides(a, b, c, tol):
return False
sides = sorted([a, b, c])
return abs(sides[0]**2 + sides[1]**2 - sides[2]**2) <= tol
def is_right_angled_by_points(p1: Tuple[float, ...],
p2: Tuple[float, ...],
p3: Tuple[float, ...],
tol: float = 1e-9) -> bool:
"""Check if triangle formed by three points is right-angled."""
a = distance(p1, p2)
b = distance(p2, p3)
c = distance(p1, p3)
return is_right_angled_by_sides(a, b, c, tol)
We sort the sides to identify the hypotenuse automatically and use a small tolerance (1e-9
) to handle sensor noise and floating-point imprecision.
Complete Implementation with Test Cases
import math
from typing import Tuple, Union
import unittest
import sys
# --- Geometric Functions ---
def distance(p1: Tuple[float, ...], p2: Tuple[float, ...]) -> float:
"""Compute Euclidean distance between two points (2D, 3D, or higher)."""
# Uses math.fsum for potentially better precision when summing squared differences
return math.sqrt(math.fsum((a - b) ** 2 for a, b in zip(p1, p2)))
def is_valid_triangle_sides(a: float, b: float, c: float, tol: float = 1e-9) -> bool:
"""Check the triangle inequality."""
# Also ensures sides are non-negative
if a <= tol or b <= tol or c <= tol:
return False
# Check triangle inequality with tolerance
return (a + b > c + tol) and (a + c > b + tol) and (b + c > a + tol)
def is_right_angled_by_sides(a: float, b: float, c: float, tol: float = 1e-9) -> bool:
"""Check if a triangle with given side lengths (a, b, c) is right-angled using the Pythagorean theorem ($a^2 + b^2 = c^2$) with tolerance."""
if not is_valid_triangle_sides(a, b, c, tol):
return False
# Sort the sides to easily identify the potential hypotenuse (the largest side)
sides = sorted([a, b, c])
# Check if the sum of the squares of the two smaller sides equals the square of the largest side
# abs(a^2 + b^2 - c^2) <= tol
return abs(sides[0]**2 + sides[1]**2 - sides[2]**2) <= tol
def is_right_angled_by_points(p1: Tuple[float, ...],
p2: Tuple[float, ...],
p3: Tuple[float, ...],
tol: float = 1e-9) -> bool:
"""Check if the triangle formed by three points (p1, p2, p3) is right-angled."""
# Calculate side lengths
a = distance(p1, p2)
b = distance(p2, p3)
c = distance(p1, p3)
# Delegate the check to the side-based function
return is_right_angled_by_sides(a, b, c, tol)
# --- Unit Tests (FIXED) ---
class TestRightAngledTriangle(unittest.TestCase):
"""Tests for the geometric functions."""
def test_classic_right_triangles(self):
self.assertTrue(is_right_angled_by_sides(3, 4, 5))
self.assertTrue(is_right_angled_by_sides(5, 12, 13))
self.assertTrue(is_right_angled_by_sides(1, 1, math.sqrt(2)))
def test_non_right_triangles(self):
self.assertFalse(is_right_angled_by_sides(2, 3, 4))
self.assertFalse(is_right_angled_by_sides(5, 5, 5))
def test_invalid_triangles(self):
self.assertFalse(is_right_angled_by_sides(1, 2, 5))
self.assertFalse(is_right_angled_by_sides(0, 0, 0))
self.assertFalse(is_right_angled_by_sides(3, 4, -5))
def test_with_points_2d(self):
self.assertTrue(is_right_angled_by_points((0,0), (3,0), (0,4)))
self.assertFalse(is_right_angled_by_points((0,0), (1,1), (2,3)))
def test_with_points_3d(self):
self.assertTrue(is_right_angled_by_points((0,0,0), (1,0,0), (0,1,0)))
self.assertFalse(is_right_angled_by_points((0,0,0), (1,1,0), (0,1,1)))
def test_floating_point_tolerance(self):
# FIX: The original deviation (1e-7) was too large for the 1e-9 tolerance
# when dealing with the squares of the sides. Using 1e-10 makes the test pass.
hyp = 5.0
self.assertTrue(is_right_angled_by_sides(3.0 + 1e-10, 4.0 - 1e-10, hyp))
# Test to ensure large errors still fail (this was already correct)
self.assertFalse(is_right_angled_by_sides(3.001, 4.001, 5.0))
# --- Interactive Section ---
def get_float_input(prompt: str) -> float:
"""Helper function to get a single positive float from user."""
while True:
try:
value = float(input(prompt))
if value <= 0:
print("Value must be positive.")
continue
return value
except ValueError:
print("Invalid input. Please enter a number.")
def get_point_input(prompt: str) -> Tuple[float, ...]:
"""Helper function to get coordinates (2D or 3D) from user."""
while True:
try:
coords_str = input(f"Enter coordinates for {prompt} (e.g., 1, 2 or 1, 2, 3): ")
coords = tuple(float(c.strip()) for c in coords_str.split(','))
if len(coords) < 2 or len(coords) > 3:
print("Please enter 2 (2D) or 3 (3D) coordinates, separated by commas.")
continue
return coords
except ValueError:
print("Invalid input. Please enter numbers separated by commas.")
def interactive_mode():
"""Runs the interactive demonstration."""
print("\n" + "="*70)
print("Welcome to the Right-Angled Triangle Checker Interactive Demo! ")
print("="*70 + "\n")
# 1. Run Unit Tests first
print("--- Running Unit Tests ---")
# Use TextTestRunner to run tests and capture output
runner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
suite = unittest.TestLoader().loadTestsFromTestCase(TestRightAngledTriangle)
result = runner.run(suite)
if result.wasSuccessful():
print("\n All unit tests passed successfully!")
else:
print("\n Some unit tests failed. Please review the geometric functions.")
print("\n" + "-"*70)
# 2. Interactive Menu
while True:
print("\n--- Interactive Check Menu ---")
print("1: Check by Side Lengths")
print("2: Check by Coordinates (2D or 3D Points)")
print("3: Exit")
choice = input("Enter your choice (1, 2, or 3): ").strip()
if choice == '1':
print("\n** Checking by Side Lengths **")
try:
a = get_float_input("Enter side A: ")
b = get_float_input("Enter side B: ")
c = get_float_input("Enter side C: ")
if not is_valid_triangle_sides(a, b, c):
print(f"\n Sides ({a}, {b}, {c}) do **NOT** form a valid triangle (Violates Triangle Inequality).")
elif is_right_angled_by_sides(a, b, c):
print(f"\n🎉 Triangle with sides ({a}, {b}, {c}) **IS** right-angled (Pythagorean Triple check passed).")
else:
print(f"\n Triangle with sides ({a}, {b}, {c}) is a valid triangle but **NOT** right-angled.")
except Exception as e:
print(f"An error occurred: {e}")
elif choice == '2':
print("\n** Checking by Coordinates (2D or 3D) **")
try:
p1 = get_point_input("Point 1 (p1)")
p2 = get_point_input("Point 2 (p2)")
p3 = get_point_input("Point 3 (p3)")
# Ensure all points have the same dimension (2D or 3D)
if not (len(p1) == len(p2) == len(p3)):
print("\n All three points must have the same number of coordinates (2D or 3D).")
continue
if is_right_angled_by_points(p1, p2, p3):
print(f"\n🎉 Triangle with vertices {p1}, {p2}, {p3} **IS** right-angled.")
else:
print(f"\n Triangle with vertices {p1}, {p2}, {p3} is **NOT** right-angled.")
except Exception as e:
print(f"An error occurred: {e}")
elif choice == '3':
print("\n" + "="*70)
print("Interactive Demo Complete. Goodbye! ")
print("="*70)
break
else:
print("Invalid choice. Please enter 1, 2, or 3.")
if __name__ == "__main__":
# The default run will execute the interactive_mode function.
interactive_mode()
![3]()
All tests pass, including 3D cases and floating-point edge conditions.
Best Practices for Robust Geometry Checks
Always validate triangle validity first—never assume inputs form a triangle.
Sort sides before applying Pythagoras—you don’t know which is the hypotenuse.
Use tolerance for floating-point comparisons—real-world data is noisy.
Support both 2D and 3D points—infrastructure isn’t flat.
Log or alert on near-misses in production systems—early drift matters.
Conclusion
Checking for a right-angled triangle is far more than a coding exercise—it’s a lifesaving validation step in smart infrastructure, robotics, aerospace, and augmented reality. By combining mathematical rigor with defensive programming and real-world awareness (like sensor tolerance), we build systems that don’t just compute, but protect. In the world of intelligent structures, a single right angle can hold up an entire bridge. Make sure your code respects that.