# Circular Array Python calculate points

just adding a circular array feature for Blender for Python addon.

I have:

1. The blue circle and it's center (c1)
2. a variable number of items in the array (count)
3. The center for the array (CF).
4. The normal of the blue circle

Are there some good ideas how to calculate c2..c4 in 3d space?

With this code it kind of works:

Almost :-) With this code, the centers of the array are not build around the CF:

def create_circle_array(self, count: int):
self._array.clear()

CF = get_face_center(self._hit_face, self._hit_obj)

# Just to test if CF is set correctly.
bpy.context.scene.cursor.location = CF

# self._center_3d is center of circle c1
v1 = (self._center_3d - CF)

r = v1.length  # Radius

count = int(count + 1)

v1.normalize()

v2 = self._normal.cross(v1)

v1 = Vector(v1)
v2 = Vector(v2)

verts = []

t = 0
offset = 0  # Increase this to offset (in radians) the points along the circle perimeter
while t < 2 * pi + offset:
verts.append(CF + r * cos(t) * v1 + r * sin(t) * v2)
t += 2 * pi / count


But the new centers are not build around CF:

## 1 Answer

Thankfully there are this answer on the maths sister site and this answer (in python, yay!) on SO that make the process pretty straightforward.

Given a normal normal and a point in space p we can position the points of a "slanted" circle like so :

from mathutils import Vector
from math import pi, cos, sin
from random import random, seed

n = normal
seed(0)  # Change seed to get a different pattern
v1 = Vector((random(), random(), random()))
# OR you can use the vector (C1 <-> CF) which you already know is orthogonal to n
v1 -= v1.dot(n) * n
v1.normalize()

v2 = v1.cross(n) # Get a third orthogonal vector

r = 1  # Circle Radius when looking in the direction of the normal
points = 9  # Here's your array counter

verts = []

offset = 0  # Increase this to offset (in radians) the points along the circle perimeter
t = offset
while t < 2 * pi + offset:
verts.append(p + r * cos(t) * v1 + r * sin(t) * v2)
t += 2 * pi / points


I created a simple script to test this in a scene with a plane. I added this beforehand :

import bpy
new_mesh = bpy.data.meshes.new("mesh")
new_obj = bpy.data.objects.new(name="mesh", object_data=new_mesh)

bpy.data.collections["Collection"].objects.link(new_obj)

normal = bpy.data.objects["Plane"].data.polygons[0].normal
p = Vector(bpy.data.objects["Plane"].data.polygons[0].center + bpy.data.objects["Plane"].matrix_world.translation)


and this at the end :

new_mesh.from_pydata(verts, [], [range(len(verts))])


Result :

Or use an operator:

bpy.ops.mesh.primitive_circle_add(
vertices=points,
radius=r,
location=p,
rotation=Vector((0, 0, 1)).rotation_difference(n).to_euler()
)

• Almost :-) With the code (see my edition), the centers of the array are not build around the CF Jan 3 at 23:59
• Alright, got it now, had to subtract self._center_3d Vector :-) Thx! Jan 4 at 0:06
• Solved, but when I move the circle along the normal and then calculate the points, v1 is not orthogonal anymore. Do you have an idea for this? Jan 4 at 17:55
• Maybe I'm not seeing this correctly but can't you also move C1 (or CF) by the same amount along the normal and recalculate v1 ? Jan 4 at 18:16
• Yep, was missing this step: v1 -= v1.dot(self._normal) * self._normal Then radius before normalizing r = v1.length Now it works, thx again Jan 4 at 18:35