# How can I create a mathematically correct arc/circular segment?

Given 3 vertices, or a chord and height, how can I create a mathematically correct arc/circular segment with an even distribution of vertices while controlling for the number of vertices.

I frequently need to model arcs in Blender from real-world measurements. Typically I know the cord and height of the arc, giving me 3 points on the full circle.

To create a mathematically correct arc, controlling for the number of vertices, my workflow is as follows:

1. Plug the coordinates of the three vertices into a digital graphics calculator.
2. Retrieve the location of the centre of the full circle, and the angle between the vertices at either end of the cord.
3. Place the cursor at the centre of the full circle in Blender by editing the 3D cursor coordinates.
4. Select one vertex on the chord and use the spin tool, manually entering in the angle retrieved from the graphics calculator and the number of desired vertices.

While this produces an accurate result it is a rather tedious process. How can I achieve this same result using a faster workflow?

The theory is well covered here Calculate the radius of a circle given the chord length and height of a segment

The text editor > Templates > Python > Operator Add Mesh template modified to add an arc.

Input the arc length, arc height and number of segments and it creates an arc.

Notes. Haven't dealt with the restriction that arc height can only ever by at most half chord length for a semi circle.

import bpy
import bmesh
from mathutils import Matrix
from math import asin

from bpy.props import (
IntProperty,
BoolProperty,
FloatProperty,
)

bl_options = {'REGISTER', 'UNDO'}

length: FloatProperty(
name="length",
description="Chord Length",
min=0.01,
max=100.0,
default=2.0,
)
height: FloatProperty(
name="Height",
description="Arc Height",
min=0.01,
max=100.0,
default=1.0,
)
segments: IntProperty(
name="Arc Segments",
description="Number of Segments",
min=1,
default=8,
)

def draw(self, context):
'''Generic Draw'''
layout = self.layout
# annnotated on this class
for prop in self.__class__.__annotations__.keys():
layout.prop(self, prop)
layout.prop(self, prop)

def execute(self, context):
h = self.height
a = self.length / 2
r = (a * a + h * h) / (2 * h)
if abs(a / r) > 1:
# math domain error on arcsin
return {'CANCELLED'}
angle = 2 * asin(a / r)

mesh = bpy.data.meshes.new("Arc")

bm = bmesh.new()
v = bm.verts.new((0, r, 0))
bmesh.ops.rotate(
bm, verts=[v], matrix=Matrix.Rotation(angle / 2, 3, 'Z'))
bmesh.ops.spin(
bm,
geom=[v],
axis=(0, 0, 1),
steps=self.segments,
angle=-angle,
)

for v in bm.verts:
v.co.y -= r - h
v.select = True
bm.to_mesh(mesh)
mesh.update()

# add the mesh as an object into the scene with this utility module
from bpy_extras import object_utils

return {'FINISHED'}

def register():

def unregister():

if __name__ == "__main__":
register()

# test call