manimgeo.math.three_points 源代码

from .base import close, array2float
from logging import getLogger
from typing import Tuple
import numpy as np

logger = getLogger(__name__)

[文档] @array2float def inscribed(p1: np.ndarray, p2: np.ndarray, p3: np.ndarray) -> Tuple[float, np.ndarray]: """ 计算三维空间中三点构成的三角形的内切圆半径和内切圆圆心,内切圆和圆心位于这三点定义的平面内 - Returns: `Tuple[float, np.ndarray]`, 内切圆半径和内切圆圆心坐标 """ a_len = np.linalg.norm(p2 - p3) b_len = np.linalg.norm(p3 - p1) c_len = np.linalg.norm(p1 - p2) # 三点重合退化 perimeter = float(a_len + b_len + c_len) if close(perimeter, 0): logger.warning("三点退化为一点,无法形成有效三角形:{}, {}, {}".format(p1, p2, p3)) return 0.0, (p1 + p2 + p3) / 3.0 # 半周长 s = perimeter / 2.0 # 海伦公式 area_squared_term = float(s * (s - a_len) * (s - b_len) * (s - c_len)) if close(area_squared_term, 0): logger.warning("三点共线退化,无法形成有效三角形:{}, {}, {}".format(p1, p2, p3)) return 0.0, (p1 + p2 + p3) / 3.0 r = np.sqrt(area_squared_term) / s incenter = (a_len * p1 + b_len * p2 + c_len * p3) / perimeter return r, incenter
[文档] @array2float def circumcenter(p1: np.ndarray, p2: np.ndarray, p3: np.ndarray) -> Tuple[float, np.ndarray]: """ 计算三维空间中三点构成的三角形的外接圆半径和外接圆圆心,外接圆和圆心位于这三点定义的平面内 Returns: `Tuple[float, np.ndarray]`, 外接圆半径和外接圆圆心坐标。 """ v1 = p2 - p1 v2 = p3 - p1 dot_v1_v1 = np.dot(v1, v1) # |v1|^2 dot_v1_v2 = np.dot(v1, v2) # v1.v2 dot_v2_v2 = np.dot(v2, v2) # |v2|^2 # 构建 2x2 矩阵 A 和右侧向量 B A = np.array([ [2 * dot_v1_v1, 2 * dot_v1_v2], [2 * dot_v1_v2, 2 * dot_v2_v2] ]) B = np.array([dot_v1_v1, dot_v2_v2]) # 求解线性方程组 Ax = B 得到 x, y # np.linalg.solve 会检查 A 是否奇异,如果奇异会抛出 LinAlgError try: coeffs = np.linalg.solve(A, B) except np.linalg.LinAlgError: logger.warning("三点共线退化,无法计算外接圆:{}, {}, {}".format(p1, p2, p3)) raise ValueError("三点共线,无法计算外接圆") x, y = coeffs[0], coeffs[1] # 计算圆心坐标 circumcenter = p1 + x * v1 + y * v2 # 计算半径:圆心到任意一个顶点的距离 r = float(np.linalg.norm(circumcenter - p1)) return r, circumcenter
[文档] @array2float def orthocenter(p1: np.ndarray, p2: np.ndarray, p3: np.ndarray) -> np.ndarray: """ 计算三维空间中三点构成的三角形的垂心坐标,垂心位于这三点定义的平面内 Returns: `np.ndarray`, 垂心坐标。 """ v1 = p2 - p1 v2 = p3 - p1 v_p2p3 = p3 - p2 area_vec = np.cross(v1, v2) if np.linalg.norm(area_vec) < 1e-9: # Use a small tolerance for floating point comparison logger.warning("三点共线退化,无法计算垂心:{}, {}, {}".format(p1, p2, p3)) raise ValueError("三点共线,无法计算垂心") dot_v1_v_p2p3 = np.dot(v1, v_p2p3) dot_v2_v_p2p3 = np.dot(v2, v_p2p3) dot_v1_v2 = np.dot(v1, v2) dot_v2_v2 = np.dot(v2, v2) # |v2|^2 A = np.array([ [dot_v1_v_p2p3, dot_v2_v_p2p3], [dot_v1_v2, dot_v2_v2] ]) B = np.array([0, dot_v1_v2]) # Right-hand side of the 2x2 system try: coeffs = np.linalg.solve(A, B) except np.linalg.LinAlgError: logger.warning("无法求解垂心方程组,可能存在数值问题:{}, {}, {}".format(p1, p2, p3)) raise ValueError("无法求解垂心方程组,可能存在数值问题") x, y = coeffs[0], coeffs[1] orthocenter = p1 + x * v1 + y * v2 return orthocenter