# Wrong outcome for mathematically correct circle segment 180 degrees

I am trying to program an add-on for Blender that would make a perfect circle segment.

Pure mathematics. No bmesh or bpy.

The green vertices are my result and the blue circle is what I am after

With h1 = (h + (sqrt(a**2 - (math.cos(angle)*a)**2) - a)) you can calculate the height offset of all vertices, but the operator menu will not allow you to change the height anymore.

So verts1.append((math.cos(angle)*a, math.sin(angle)*h, 0.0)) will allow you to change height and diameter but the outcome is wrong. As sees on the screenshot above.

While verts1.append((math.cos(angle)*a, h1, 0.0)) moves all vertices up or down as you can see in this screenshot below.

My goal is to keep the lowest vertices on the X axis as in the first screenshot.

The circle is radius 1000mm (1M) and moved -500 Y. The height of the segment is 500 and diameter is 1732mm

This is the code so far. Upon running a new "button" will appear under add --> mesh --> Segment circle

bl_info = {
"name": "segment",
"author": "The Bold Guy",
"version": (1, 0),
"blender": (2, 80, 1),
"location": "View3D > Add > Mesh > segment",
"description": "Adds a new Mesh Object",
"warning": "",
"wiki_url": "",
}

import bpy
import bmesh
import math
import mathutils
from mathutils import Matrix
from bpy import types
from bpy.props import (
StringProperty,
BoolProperty,
IntProperty,
IntVectorProperty,
FloatProperty,
FloatVectorProperty,
EnumProperty,
PointerProperty,
)
from bpy.types import (
Panel,
Operator,
PropertyGroup,
)
from mathutils import Vector
from math import degrees, radians, pi, tan, asin, sin, cos, acos, sqrt

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

verts = []
edges = []
faces = []

h = self.height
a = self.diam/2
h1 = []

for i in range(self.segments+1):
angle = (math.pi * (i / self.segments))

##Calculate the offset of vertices on any given point of circle (180 degrees)
#(math.cos(angle)*a)

##Calculating Height of an Arc at Any Point
h1 = (h + (sqrt(a**2 - (math.cos(angle)*a)**2) - a))

##make list X,Y,Z for vertices to be added
verts.append((math.cos(angle)*a, math.sin(angle)*h, 0.0))

mesh.from_pydata(verts, edges, faces)

return mesh

return {"FINISHED"}

"""Create a new Mesh Object"""

bl_options = {"REGISTER", "UNDO", 'PRESET'}

segments: IntProperty(
name="Segments",
# unit='LENGTH',
min=1,
default=8,
)
angle: IntProperty(
name="Segments",
# unit='LENGTH',
min=0,
max=360,
default=180,
)
height: FloatProperty(
attr='height', name="Height", unit="LENGTH", default=1000 / 1000 ,
)
diam: FloatProperty(
attr='diam', name="length", unit="LENGTH", default=2000 / 1000,
)

def execute(self, context):

return {"FINISHED"}

# Registration
self.layout.operator(
)

# This allows you to right click on a button and link to documentation
url_manual_prefix = "https://docs.blender.org/manual/en/latest/"
url_manual_mapping = (
)
return url_manual_prefix, url_manual_mapping

def register():

def unregister():

if __name__ == "__main__":
register()

• I'm not fully understanding what you want to achieve. If I'm understanding correctly, you don't want to go from $0 \to \pi$ but the angles between the circle origin and start/end points. Dec 5 '21 at 21:47
• @RonJensen See the first screenshot. The lowest vertices needs to stay on the red line. That will represent the chord of the segment. Then the rest of all the vertices should represent the sagitta of the segment. i.e. the vertices should be on the same height as the circle in the screenshot thus forming an circle segment. I hope I made it clearer. If not please let me know and I will try to reform my question better. Dec 5 '21 at 22:18

IIUC the question is how to draw the part of the circle $$(x, y) = (r \cos \theta, r \sin \theta - h)$$ that is above the x-axis. In that case, like Ron Jensen says, you just need to calculate the angle to start and end at.


h = self.height
diam = abs(self.diam)
r = diam/2

if r == 0:
# No circle
return mesh
elif h >= r:
# Circle entirely below x-axis
return mesh
elif h <= -r:
# Circle entirely above x-axis
angle_start = -math.pi/2
angle_end = math.pi*3/2
else:
# Circle partially above x-axis
angle_start = math.asin(h/r)
angle_end = math.pi - angle_start

for i in range(self.segments+1):
factor = i / self.segments
angle = angle_start*(1 - factor) + angle_end*factor
verts.append((math.cos(angle)*r, math.sin(angle)*r - h, 0.0))

• this is what I meant. May I ask, Is it also possible to adjust the segment start and end point angle? lets say the start point is most right vertex (0 degrees) and end point is most left vertex (18.0 degrees) self.angle can be used to make the segment between 1 and 180 degrees Dec 5 '21 at 23:45
• You can adjust angle_start and angle_end. Dec 6 '21 at 0:02