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

enter image description here

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. enter image description here

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": "",
    "category": "Add Mesh",

import bpy
import bmesh
import math
import mathutils
from mathutils import Matrix
from bpy import types
from bpy.props import (
from bpy.types import (
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
from math import degrees, radians, pi, tan, asin, sin, cos, acos, sqrt

def add_plane_mesh(self, context):

    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)
        ##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

def add_plane_mesh1(self, context):

    return {"FINISHED"}

class OBJECT_Oval_pipe_add_object(Operator, AddObjectHelper):
    """Create a new Mesh Object"""

    bl_idname = "tools.add_segment"
    bl_label = "Add segment"
    bl_options = {"REGISTER", "UNDO", 'PRESET'}

    segments: IntProperty(
        # unit='LENGTH',
    angle: IntProperty(
        # unit='LENGTH',
    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):

        object_data_add(context, add_plane_mesh(self, context), operator=self)
        return {"FINISHED"}

# Registration
def add_object_button(self, context):
        OBJECT_Oval_pipe_add_object.bl_idname, text="Segment Circle", icon="PLUGIN"

# This allows you to right click on a button and link to documentation
def add_object_manual_map():
    url_manual_prefix = "https://docs.blender.org/manual/en/latest/"
    url_manual_mapping = (
        ("bpy.ops.mesh.add_object", "scene_layout/object/types.html"),
    return url_manual_prefix, url_manual_mapping

def register():

def unregister():

if __name__ == "__main__":
  • 1
    $\begingroup$ 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. $\endgroup$
    – Ron Jensen
    Dec 5 '21 at 21:47
  • $\begingroup$ @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. $\endgroup$
    – cecevo
    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
        # 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))
  • $\begingroup$ 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 $\endgroup$
    – cecevo
    Dec 5 '21 at 23:45
  • $\begingroup$ You can adjust angle_start and angle_end. $\endgroup$
    – scurest
    Dec 6 '21 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.