How many points are need to construct a smooth circular arc?

1244
4
08-03-2016 04:05 PM
TieshengWu
Occasional Contributor

Hi all.  I need to construct circular arc by  array using Arcpy. Apparently the larger the circle, the more number of points in ArcMap. How many points are need to keep same smoothness with ArcMap platform, what's the relationship between diameter R and Number of points to get it?

0 Kudos
4 Replies
DanPatterson_Retired
MVP Esteemed Contributor

three points are needed to constuct a circle.  Depending on what you are using, circles are often represented by n-gons (n-sided regular polygons) typically with 360 segments.  True circles? certainly not in shapefiles.  Arcs? not sure either.  Pure geometry would create the arc, circle, sector geometry using equations rather than representing them as polylines.  Points can be sampled along their length, but the intervening space between points are line segments.

Do you have an example of a featureclass (not graphics) in some incarnation that you are trying to create circular or elliptical components?

0 Kudos
TieshengWu
Occasional Contributor

Thank you Dan. below is code:

def circle_array(x,y,c1,c2,r):     #x,y for center, c1,c2 for start and end angle, r for diameter

ar=[]

deg2rad=math.pi/180.0

n=360.0

for i in range(0,n+1):

  ang = (c1+(c2-c1)*i/n) * deg2rad

  arx=x + r * math.cos(ang)

  ary=y + r * math.sin(ang)

 

  ar.append([arx,ary,0])

return ar

I just wonder how to decide the n to keep the same smoothness with arcmap platform

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor

up for some numpy and python?

# -*- coding: UTF-8 -*-
"""
:Script:   circle_make.py
:Author:   Dan.Patterson@carleton.ca
:Modified: 2016-08-03
:Purpose: make a circle
"""
#---- imports, formats, constants ----
import sys
import numpy as np
from textwrap import dedent

ft={'bool':lambda x: repr(x.astype('int32')),
    'float': '{: 0.3f}'.format}
np.set_printoptions(edgeitems=10, linewidth=80, precision=2,
                    suppress=True, threshold=100, 
                    formatter=ft)
script = sys.argv[0]

#---- functions ----
def _demo(radius=100, theta=1, xc=0.0, yc=0.0):
    """   
    :Requires
    :--------
    :  radius - in projected units
    :  angle - integer
    :Returns
    :-------
    :  list of coordinates rounded to 3 decimal places
    :Notes:
    :------
    : If you need more than 360 points use, for example 720 points
    : np.linspace(start, stop, num=50, endpoint=True, retstep=False)
    : np.linspace(-180, 180, num=720, endpoint=True, retstep=False)
    """
    angle = [np.deg2rad(i) for i in range(-180,180,theta)]
    Xs = radius*np.cos(angle)         # X values
    Ys = radius*np.sin(angle)         # Y values
    pnts = np.array(list(zip(Xs,Ys)))
    pnts = np.round(pnts + [xc,yc], 3)
    p_lst = pnts.tolist()
    return p_lst

#----------------------
if __name__=="__main__":
    """   """
    #print("Script... {}".format(script))
    p_lst = _demo(radius=1, theta=30, xc=5, yc=5)
    print(p_lst)

Now if I return the pnts array instead of the list (p_lst) then the output for the demo with a center (5,5) radius 1 and angle of 30

array([[ 4.000,  5.000],

       [ 4.134,  4.500],

       [ 4.500,  4.134],

       [ 5.000,  4.000],

       [ 5.500,  4.134],

       [ 5.866,  4.500],

       [ 6.000,  5.000],

       [ 5.866,  5.500],

       [ 5.500,  5.866],

       [ 5.000,  6.000],

       [ 4.500,  5.866],

       [ 4.134,  5.500]]))

in list form

[[4.0, 5.0], [4.134, 4.5], [4.5, 4.134], [5.0, 4.0], [5.5, 4.134], [5.866, 4.5], [6.0, 5.0], [5.866, 5.5], [5.5, 5.866], [5.0, 6.0], [4.5, 5.866], [4.134, 5.5]]

If you need more than 360 points, see the notes in the header section and generate the angles using np.linspace

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor

follow up   an arc between 0 and 5 degrees, center at 5,5, 50 points... using the np.linspace option

>>> ang=np.linspace(0, 5, num=50, endpoint=True, retstep=False)
>>> ang= np.deg2rad(ang)
>>> Xs = 1*np.cos(ang)
>>> Ys = 1*np.sin(ang)
>>> pnts = np.array(list(zip(Xs,Ys)))
>>> pnts = np.round(pnts + [5,5], 3)
>>> pnts
array([[ 6.000,  5.000],
       [ 6.000,  5.002],
       ...
       [ 5.997,  5.080],
       [ 5.997,  5.082],
       [ 5.996,  5.084],
       [ 5.996,  5.085],
       [ 5.996,  5.087]])

much finer resolution, over a 5 degree range.  Using this option you are pretty well limitless.

0 Kudos