Следующее может не быть очень быстрым решением, но оно работает и имеет математический / геометрический смысл.
Но сначала - обратите внимание, что в вашем примере есть 12 подмножеств4 копланарные точки, а не 8, из-за наличия «диагональных» плоскостей, проходящих через ваш куб.Это может быть формализовано, но должно быть ясно, как есть (дайте мне знать, если не через комментарии).
Это, по нашему мнению, самый простой способ будет генерировать все подмножества размера 4 (без повторов для переупорядочения), изатем проверка, равен ли объем, определенный 4 точками, 0;т.е. любые 3 из этих 4 точек определяют плоскость, содержащую 4-ю.(Этот метод объясняется во многих вопросах обмена стека, а также показан в определении «wolfram» «Копланарность» ).
Реализовать это можно на самом деле просто следующим образом:
import numpy as np
import scipy.linalg as spl
from itertools import combinations
def rot(axis, theta):
return spl.expm(np.cross(np.eye(len(axis)), axis/spl.norm(axis)*theta))
rot3 = rot((1,0,0), np.pi/4) @ rot((0,1,0), np.pi/3) @ rot((0,0,1), np.pi/2)
points = np.array([[1, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 1],
[1, 1, 0, 1, 0, 1, 0, 0]])
points = rot3 @ points
subsets_of_4_points = list(combinations(points.T, 4)) # 70 subsets. 8 choose 4 is 70.
coplanar_points = [p for p in subsets_of_4_points if np.abs(np.linalg.det(np.vstack([np.stack(p).T, np.ones((1, 4))]))) < 0.000001] # due to precision stuff, you cant just do "det(thing) == 0"
И вы получите все 12 4-наборов копланарных точек.
Простая визуализация точек, полученных с помощью следующего простого кода (продолжение из последнего фрагмента с дополнительным импортом):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Get pairs of points for plotting the lines of the cube:
all_pairs_of_points = list(combinations(points.T, 2))
# Keep only points with distance equal to 1, to avoid drawing diagonals:
neighbouring_points = [list(zip(list(p1), list(p2))) for p1, p2 in all_pairs_of_points if np.abs(np.sqrt(np.sum((p1 - p2)**2)) - 1) < 0.0001]
plt.figure()
for i in range(12):
ax3d = plt.subplot(3, 4, i+1, projection='3d')
# Draw cube:
for point_pair in neighbouring_points:
ax3d.plot(point_pair[0], point_pair[1], point_pair[2], 'k')
# Choose coplanar set:
p = coplanar_points[i]
# Draw set:
for x, y, z in p:
ax3d.scatter(x, y, z, s=30, c='m')
ax3d.set_xticks([])
ax3d.set_yticks([])
ax3d.set_zticks([])
plt.suptitle('Coplanar sets of 4 points of the rotated 3D cube')
, который создает следующую визуализацию (опять же, для этого конкретногопример):
Надеюсь, это поможет.
Удачи!