Однако после этого возникают проблемы. Мне нужны пути от a1 ко всем остальным сферам, и они должны соответствовать следующим требованиям:
- Длина пути должна быть как можно ближе к длине пути от a1 до b6.
- Пути не должны пересекаться с другими сферами, то есть путь например, от а1 до а3 не должно пересекаться ни с какими другими сферами кроме а1 и а3. В идеале пути также должны сохранять некоторую обязательную дистанцию от других сфер и друг от друга. Однако пересечение начальной и конечной сфер обязательно.
- Пути не должны пересекаться друг с другом. Вначале они могут перекрываться, но в дальнейшем не должны пересекаться.
- Путь может изгибаться, но изгибы не должны быть резким (90 градусов и более), а количество изгибов также должно быть ограничено (например, не более 10). Вот здесь и нужен работающий алгоритм поиска нужных изгибов.
- Путь должен лежать на сфере. Он не обязательно должен точно следовать сетке сферы, но должен оставаться на поверхности сферы.



Вот код:
import bpy
import math
import mathutils
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=6, radius=1)
sphere = bpy.context.object
sphere.name = "MainSphere"
bpy.ops.object.shade_smooth()
bpy.ops.object.mode_set(mode='OBJECT')
num_points = 32
phi = (1 + math.sqrt(5)) / 2
def calculate_A(n):
if n == 1:
return 1
elif n == 2:
return 4
else:
A = [1, 4]
for i in range(2, n):
A.append(A[i-1] + A[i-2])
return A[n-1]
def calculate_g(N):
k = math.floor(math.log(N / 1.5) / math.log(phi))
if k % 2 == 0:
return 3 - phi
else:
j = (k + 7) // 2
A_j_next = calculate_A(j + 1)
A_j = calculate_A(j)
return A_j_next / A_j
def delini_sphere_points(num_points):
points = []
for k in range(num_points):
g_n = calculate_g(k + 1)
theta = math.acos(1 - 2 * (k + 0.5) / num_points)
phi_angle = math.pi * (1 + 5**0.5) * (k + 1)
x_pos = math.sin(theta) * math.cos(phi_angle)
y_pos = math.sin(theta) * math.sin(phi_angle)
z_pos = math.cos(theta)
points.append((x_pos, y_pos, z_pos))
return points
points = delini_sphere_points(num_points)
sphere_objects = []
for idx, point in enumerate(points):
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.04, location=point)
small_sphere = bpy.context.object
letter = chr(97 + (idx // 26))
number = (idx % 26) + 1
small_sphere.name = f"{letter}{number}"
sphere_objects.append(small_sphere)
a1_location = sphere_objects[0].location
b6_location = sphere_objects[31].location
def distance(point1, point2):
return (point1 - point2).length
def create_constrained_path(start, end, num_segments, max_deviation_angle=90):
path_coords = [start]
prev_direction = (end - start).normalized()
for i in range(1, num_segments - 1):
t = i / (num_segments - 1)
interpolated_point = start.lerp(end, t)
direction = (interpolated_point - start).normalized()
angle = prev_direction.angle(direction)
if math.degrees(angle) > max_deviation_angle:
direction = prev_direction
prev_direction = direction
path_coords.append(start + direction * distance(start, end) * t)
path_coords.append(end)
return path_coords
def normalize_to_sphere(path_coords):
return [point.normalized() for point in path_coords]
num_segments = 35
path_coords_a1_b6 = create_constrained_path(a1_location, b6_location, num_segments)
path_coords_a1_b6 = normalize_to_sphere(path_coords_a1_b6)
def create_tube_from_path(path_coords, radius=0.05):
curve_data = bpy.data.curves.new(name="PathCurve", type='CURVE')
curve_data.dimensions = '3D'
spline = curve_data.splines.new(type='POLY')
spline.points.add(count=len(path_coords) - 1)
for i, vertex in enumerate(path_coords):
spline.points.co = (vertex.x, vertex.y, vertex.z, 1)
curve_object = bpy.data.objects.new("PathCurveObject", curve_data)
bpy.context.scene.collection.objects.link(curve_object)
bpy.ops.object.select_all(action='DESELECT')
curve_object.select_set(True)
bpy.context.view_layer.objects.active = curve_object
bpy.ops.object.convert(target='MESH')
bpy.ops.object.modifier_add(type='BEVEL')
bevel = curve_object.modifiers["Bevel"]
bevel.width = radius
bevel.segments = 4
return curve_object
create_tube_from_path(path_coords_a1_b6, radius=0.05)
distance_a1_b6 = distance(a1_location, b6_location)
def create_paths_to_all_spheres():
for idx, sphere_object in enumerate(sphere_objects):
if sphere_object != sphere_objects[0]:
path_length = distance(a1_location, sphere_object.location)
num_segments = max(int((path_length / distance_a1_b6) * len(path_coords_a1_b6)), 30)
path_coords = create_constrained_path(a1_location, sphere_object.location, num_segments)
path_coords = normalize_to_sphere(path_coords)
create_tube_from_path(path_coords, radius=0.05)
create_paths_to_all_spheres()
Подробнее здесь: https://stackoverflow.com/questions/792 ... in-blender
Мобильная версия