Well, actually, you can pass a list - as I did in my example above with PlaneFromPoints() - to a lot of rhinoscriptsyntax methods that expect a point3d object - it tries to convert them automatically. The main problem was trying to pass a list of 4 coordinate triples as a “plane” instead of just 3 separate arguments.

The exception got thrown when coerceplane (which is called by AddCircle) failed to convert the 4 triples into a plane object. Then AddCircle(), not having a plane as input, tried to interpret that list as one point3d by using coerce3dpoint… which failed, and then the exception was thrown.

Here’s what AddCircle() is doing “behind the scenes”:

```
def AddCircle(plane_or_center, radius):
"""Adds a circle curve to the document
Parameters:
plane_or_center = plane on which the circle will lie. If a point is
passed, this will be the center of the circle on the active
construction plane
radius = the radius of the circle
Returns:
id of the new curve object
"""
rc = None
plane = rhutil.coerceplane(plane_or_center, False)
if plane:
circle = Rhino.Geometry.Circle(plane, radius)
rc = scriptcontext.doc.Objects.AddCircle(circle)
else:
center = rhutil.coerce3dpoint(plane_or_center, True)
view = scriptcontext.doc.Views.ActiveView
plane = view.ActiveViewport.ConstructionPlane()
plane.Origin = center
circle = Rhino.Geometry.Circle(plane, radius)
rc = scriptcontext.doc.Objects.AddCircle(circle)
if rc==System.Guid.Empty: raise Exception("Unable to add circle to document")
scriptcontext.doc.Views.Redraw()
return rc
```

Here are the coerceplane and coerce3dpoint methods respectively:

```
def coerceplane(plane, raise_on_bad_input=False):
"Convert input into a Rhino.Geometry.Plane if possible."
if type(plane) is Rhino.Geometry.Plane: return plane
if type(plane) is list or type(plane) is tuple:
length = len(plane)
if length==3 and type(plane[0]) is not list:
rc = Rhino.Geometry.Plane.WorldXY
rc.Origin = Rhino.Geometry.Point3d(plane[0],plane[1],plane[2])
return rc
if length==9 and type(plane[0]) is not list:
origin = Rhino.Geometry.Point3d(plane[0],plane[1],plane[2])
xpoint = Rhino.Geometry.Point3d(plane[3],plane[4],plane[5])
ypoint = Rhino.Geometry.Point3d(plane[6],plane[7],plane[8])
rc = Rhino.Geometry.Plane(origin, xpoint, ypoint)
return rc
if length==3 and (type(plane[0]) is list or type(plane[0]) is tuple):
origin = Rhino.Geometry.Point3d(plane[0][0],plane[0][1],plane[0][2])
xpoint = Rhino.Geometry.Point3d(plane[1][0],plane[1][1],plane[1][2])
ypoint = Rhino.Geometry.Point3d(plane[2][0],plane[2][1],plane[2][2])
rc = Rhino.Geometry.Plane(origin, xpoint, ypoint)
return rc
if raise_on_bad_input: raise TypeError("%s can not be converted to a Plane"%plane)
```

```
def coerce3dpoint(point, raise_on_error=False):
"Convert input into a Rhino.Geometry.Point3d if possible."
if type(point) is Rhino.Geometry.Point3d: return point
if hasattr(point, "__len__") and len(point)==3 and hasattr(point, "__getitem__"):
try:
return Rhino.Geometry.Point3d(float(point[0]), float(point[1]), float(point[2]))
except:
if raise_on_error: raise
if type(point) is Rhino.Geometry.Vector3d or type(point) is Rhino.Geometry.Point3f or type(point) is Rhino.Geometry.Vector3f:
return Rhino.Geometry.Point3d(point.X, point.Y, point.Z)
if type(point) is str:
point = point.split(',')
return Rhino.Geometry.Point3d( float(point[0]), float(point[1]), float(point[2]) )
if type(point) is System.Guid:
rhobj = coercerhinoobject(point, raise_on_error)
if rhobj:
geom = rhobj.Geometry
if isinstance(geom, Rhino.Geometry.Point): return geom.Location
if raise_on_error: raise ValueError("Could not convert %s to a Point3d" % point)
```

—Mitch