#
tokens: 32907/50000 1/82 files (page 6/7)
lines: off (toggle) GitHub
raw markdown copy
This is page 6 of 7. Use http://codebase.md/jingcheng-chen/rhinomcp?lines=false&page={x} to view the full context.

# Directory Structure

```
├── .github
│   └── workflows
│       ├── mcp-server-publish.yml
│       └── rhino-plugin-publish.yml
├── .gitignore
├── assets
│   ├── claude_enable_instruction.jpg
│   ├── cursor_enable_instruction.jpg
│   ├── cursor_usage_instruction.jpg
│   ├── demo1.jpg
│   ├── demo2.jpg
│   ├── rhino_plugin_instruction.jpg
│   └── rhinomcp_logo.svg
├── demo_chats
│   ├── create_6x6x6_boxes.txt
│   └── create_rhinoceros_lego_blocks.txt
├── LICENSE
├── README.md
├── rhino_mcp_plugin
│   ├── .gitignore
│   ├── Commands
│   │   ├── MCPStartCommand.cs
│   │   ├── MCPStopCommand.cs
│   │   └── MCPVersionCommand.cs
│   ├── EmbeddedResources
│   │   └── plugin-utility.ico
│   ├── Functions
│   │   ├── _utils.cs
│   │   ├── CreateLayer.cs
│   │   ├── CreateObject.cs
│   │   ├── CreateObjects.cs
│   │   ├── DeleteLayer.cs
│   │   ├── DeleteObject.cs
│   │   ├── ExecuteRhinoscript.cs
│   │   ├── GetDocumentInfo.cs
│   │   ├── GetObjectInfo.cs
│   │   ├── GetOrSetCurrentLayer.cs
│   │   ├── GetSelectedObjectsInfo.cs
│   │   ├── ModifyObject.cs
│   │   ├── ModifyObjects.cs
│   │   └── SelectObjects.cs
│   ├── manifest.yml
│   ├── Properties
│   │   ├── AssemblyInfo.cs
│   │   └── launchSettings.json
│   ├── rhinomcp.csproj
│   ├── rhinomcp.sln
│   ├── RhinoMCPPlugin.cs
│   ├── RhinoMCPServer.cs
│   ├── RhinoMCPServerController.cs
│   └── Serializers
│       └── Serializer.cs
└── rhino_mcp_server
    ├── .gitignore
    ├── dev.sh
    ├── main.py
    ├── pyproject.toml
    ├── README.md
    ├── src
    │   └── rhinomcp
    │       ├── __init__.py
    │       ├── prompts
    │       │   └── assert_general_strategy.py
    │       ├── server.py
    │       ├── static
    │       │   └── rhinoscriptsyntax.py
    │       └── tools
    │           ├── create_layer.py
    │           ├── create_object.py
    │           ├── create_objects.py
    │           ├── delete_layer.py
    │           ├── delete_object.py
    │           ├── execute_rhinoscript_python_code.py
    │           ├── get_document_info.py
    │           ├── get_object_info.py
    │           ├── get_or_set_current_layer.py
    │           ├── get_rhinoscript_python_code_guide.py
    │           ├── get_rhinoscript_python_function_names.py
    │           ├── get_selected_objects_info.py
    │           ├── modify_object.py
    │           ├── modify_objects.py
    │           └── select_objects.py
    ├── static
    │   ├── application.py
    │   ├── block.py
    │   ├── compat.py
    │   ├── curve.py
    │   ├── dimension.py
    │   ├── document.py
    │   ├── geometry.py
    │   ├── grips.py
    │   ├── group.py
    │   ├── hatch.py
    │   ├── layer.py
    │   ├── light.py
    │   ├── line.py
    │   ├── linetype.py
    │   ├── material.py
    │   ├── mesh.py
    │   ├── object.py
    │   ├── plane.py
    │   ├── pointvector.py
    │   ├── selection.py
    │   ├── surface.py
    │   ├── toolbar.py
    │   ├── transformation.py
    │   ├── userdata.py
    │   ├── userinterface.py
    │   ├── utility.py
    │   └── view.py
    └── uv.lock
```

# Files

--------------------------------------------------------------------------------
/rhino_mcp_server/static/surface.py:
--------------------------------------------------------------------------------

```python
import math

import System
from System.Collections.Generic import List

import Rhino

import scriptcontext

import rhinocompat as compat
from rhinoscript import utility as rhutil
from rhinoscript import object as rhobject


def AddBox(corners):
    """Adds a box shaped polysurface to the document
    Parameters:
      corners ([point, point, point ,point, point, point ,point,point]) 8 points that define the corners of the box. Points need to
        be in counter-clockwise order starting with the bottom rectangle of the box
    Returns:
      guid: identifier of the new object on success
    Example:
      import rhinoscriptsyntax as rs
      box = rs.GetBox()
      if box: rs.AddBox(box)
    See Also:
      AddCone
      AddCylinder
      AddSphere
      AddTorus
    """
    box = rhutil.coerce3dpointlist(corners, True)
    brep = Rhino.Geometry.Brep.CreateFromBox(box)
    if not brep: raise ValueError("unable to create brep from box")
    rc = scriptcontext.doc.Objects.AddBrep(brep)
    if rc==System.Guid.Empty: raise Exception("unable to add brep to document")
    scriptcontext.doc.Views.Redraw()
    return rc


def AddCone(base, height, radius, cap=True):
    """Adds a cone shaped polysurface to the document
    Parameters:
      base (point|plane): 3D origin point of the cone or a plane with an apex at the origin
          and normal along the plane's z-axis
      height (point|number): 3D height point of the cone if base is a 3D point. The height
          point defines the height and direction of the cone. If base is a
          plane, height is a numeric value
      radius (number): the radius at the base of the cone
      cap (bool, optional): cap base of the cone
    Returns:
      guid: identifier of the new object on success
    Example:
      import rhinoscriptsyntax as rs
      radius = 5.0
      base = rs.GetPoint("Base of cone")
      if base:
          height = rs.GetPoint("Height of cone", base)
          if height: rs.AddCone(base, height, radius)
    See Also:
      AddBox
      AddCylinder
      AddSphere
      AddTorus
    """
    plane = None
    height_point = rhutil.coerce3dpoint(height)
    if height_point is None:
        plane = rhutil.coerceplane(base, True)
    else:
        base_point = rhutil.coerce3dpoint(base, True)
        normal = base_point - height_point
        height = normal.Length
        plane = Rhino.Geometry.Plane(height_point, normal)
    cone = Rhino.Geometry.Cone(plane, height, radius)
    brep = Rhino.Geometry.Brep.CreateFromCone(cone, cap)
    rc = scriptcontext.doc.Objects.AddBrep(brep)
    scriptcontext.doc.Views.Redraw()
    return rc


def AddCutPlane(object_ids, start_point, end_point, normal=None):
    """Adds a planar surface through objects at a designated location. For more
    information, see the Rhino help file for the CutPlane command
    Parameters:
      objects_ids ([guid, ...]): identifiers of objects that the cutting plane will
          pass through
      start_point, end_point (line): line that defines the cutting plane
      normal (vector, optional): vector that will be contained in the returned planar
          surface. In the case of Rhino's CutPlane command, this is the
          normal to, or Z axis of, the active view's construction plane.
          If omitted, the world Z axis is used
    Returns:
      guid: identifier of new object on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select objects for cut plane")
      if objs:
          point0 = rs.GetPoint("Start of cut plane")
          if point0:
              point1 = rs.GetPoint("End of cut plane", point0)
              if point1: rs.AddCutPlane( objs, point0, point1 )
    See Also:
      AddPlaneSurface
    """
    objects = []
    for id in object_ids:
        rhobj = rhutil.coercerhinoobject(id, True, True)
        objects.append(rhobj)

    rc, bbox = Rhino.DocObjects.RhinoObject.GetTightBoundingBox(objects)
    if not bbox.IsValid:
        return scriptcontext.errorhandler()

    bbox_min = bbox.Min
    bbox_max = bbox.Max
    for i in range(0, 3):
        if (System.Math.Abs(bbox_min[i] - bbox_max[i]) < Rhino.RhinoMath.SqrtEpsilon):
            bbox_min[i] = bbox_min[i] - 1.0
            bbox_max[i] = bbox_max[i] + 1.0

    v = bbox_max - bbox_min
    v = v * 1.1
    p = bbox_min + v
    bbox_min = bbox_max - v
    bbox_max = p
    bbox = Rhino.Geometry.BoundingBox(bbox_min, bbox_max)

    start_point = rhutil.coerce3dpoint(start_point, True)
    end_point = rhutil.coerce3dpoint(end_point, True)
    line = Rhino.Geometry.Line(start_point, end_point)
    if normal:
        normal = rhutil.coerce3dvector(normal, True)
    else:
        normal = scriptcontext.doc.Views.ActiveView.ActiveViewport.ConstructionPlane().Normal

    surface = Rhino.Geometry.PlaneSurface.CreateThroughBox(line, normal, bbox)
    if surface is None: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddSurface(surface)
    if id==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return id


def AddCylinder(base, height, radius, cap=True):
    """Adds a cylinder-shaped polysurface to the document
    Parameters:
      base (point|plane): The 3D base point of the cylinder or the base plane of the cylinder
      height (point|number): if base is a point, then height is a 3D height point of the
        cylinder. The height point defines the height and direction of the
        cylinder. If base is a plane, then height is the numeric height value
        of the cylinder
      radius (number): radius of the cylinder
      cap (bool, optional): cap the cylinder
    Returns:
      guid: identifier of new object if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      radius = 5.0
      base = rs.GetPoint("Base of cylinder")
      if base:
          height = rs.GetPoint("Height of cylinder", base)
          if height: rs.AddCylinder( base, height, radius )
    See Also:
      AddBox
      AddCone
      AddSphere
      AddTorus
    """
    cylinder=None
    height_point = rhutil.coerce3dpoint(height)
    if height_point:
        #base must be a point
        base = rhutil.coerce3dpoint(base, True)
        normal = height_point-base
        plane = Rhino.Geometry.Plane(base, normal)
        height = normal.Length
        circle = Rhino.Geometry.Circle(plane, radius)
        cylinder = Rhino.Geometry.Cylinder(circle, height)
    else:
        #base must be a plane
        if type(base) is Rhino.Geometry.Point3d: base = [base.X, base.Y, base.Z]
        base = rhutil.coerceplane(base, True)
        circle = Rhino.Geometry.Circle(base, radius)
        cylinder = Rhino.Geometry.Cylinder(circle, height)
    brep = cylinder.ToBrep(cap, cap)
    id = scriptcontext.doc.Objects.AddBrep(brep)
    if id==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return id


def AddEdgeSrf(curve_ids):
    """Creates a surface from 2, 3, or 4 edge curves
    Parameters:
      curve_ids ([guid, ...]): list or tuple of curves
    Returns:
      guid: identifier of new object if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curves = rs.GetObjects("Select 2, 3, or 4 curves", rs.filter.curve)
      if curves and len(curves)>1 ): rs.AddEdgeSrf(curves)
    See Also:
      AddPlanarSrf
      AddSrfControlPtGrid
      AddSrfPt
      AddSrfPtGrid
    """
    curves = [rhutil.coercecurve(id, -1, True) for id in curve_ids]
    brep = Rhino.Geometry.Brep.CreateEdgeSurface(curves)
    if brep is None: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddBrep(brep)
    if id==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return id


def AddNetworkSrf(curves, continuity=1, edge_tolerance=0, interior_tolerance=0, angle_tolerance=0):
    """Creates a surface from a network of crossing curves
    Parameters:
      curves ([guid, ...]): curves from which to create the surface
      continuity (number, optional): how the edges match the input geometry
                 0 = loose
                 1 = position
                 2 = tangency
                 3 = curvature
    Returns:
      guid: identifier of new object if successful
    Example:
      import rhinoscriptsyntax as  rs
      curve_ids = rs.GetObjects("Select  curves in network", 4, True, True)
      if len(curve_ids) > 0:
          rs.AddNetworkSrf(curve_ids)
    See Also:
      
    """
    curves = [rhutil.coercecurve(curve, -1, True) for curve in curves]
    surf, err = Rhino.Geometry.NurbsSurface.CreateNetworkSurface(curves, continuity, edge_tolerance, interior_tolerance, angle_tolerance)
    if surf:
        rc = scriptcontext.doc.Objects.AddSurface(surf)
        scriptcontext.doc.Views.Redraw()
        return rc


def AddNurbsSurface(point_count, points, knots_u, knots_v, degree, weights=None):
    """Adds a NURBS surface object to the document
    Parameters:
      point_count ([number, number]) number of control points in the u and v direction
      points ({point, ...]): list of 3D points
      knots_u ([number, ...]): knot values for the surface in the u direction.
                Must contain point_count[0]+degree[0]-1 elements
      knots_v ([number, ...]): knot values for the surface in the v direction.
                Must contain point_count[1]+degree[1]-1 elements
      degree ([number, number]): degree of the surface in the u and v directions.
      weights [(number, ...]): weight values for the surface. The number of elements in
        weights must equal the number of elements in points. Values must be
        greater than zero.
    Returns:
      guid: identifier of new object if successful
      None on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Pick a surface", rs.filter.surface)
      if obj:
          point_count = rs.SurfacePointCount(obj)
          points = rs.SurfacePoints(obj)
          knots = rs.SurfaceKnots(obj)
          degree = rs.SurfaceDegree(obj)
          if rs.IsSurfaceRational(obj):
              weights = rs.SurfaceWeights(obj)
              obj = rs.AddNurbsSurface(point_count, points, knots[0], knots[1], degree, weights)
          else:
              obj = rs.AddNurbsSurface(point_count, points, knots[0], knots[1], degree)
          if obj: rs.SelectObject(obj)
    See Also:
      IsSurfaceRational
      SurfaceDegree
      SurfaceKnotCount
      SurfaceKnots
      SurfacePointCount
      SurfacePoints
      SurfaceWeights
    """
    if len(points)<(point_count[0]*point_count[1]):
        return scriptcontext.errorhandler()
    ns = Rhino.Geometry.NurbsSurface.Create(3, weights!=None, degree[0]+1, degree[1]+1, point_count[0], point_count[1])
    #add the points and weights
    controlpoints = ns.Points
    index = 0
    for i in range(point_count[0]):
        for j in range(point_count[1]):
            if weights:
                cp = Rhino.Geometry.ControlPoint(points[index], weights[index])
                controlpoints.SetControlPoint(i,j,cp)
            else:
                cp = Rhino.Geometry.ControlPoint(points[index])
                controlpoints.SetControlPoint(i,j,cp)
            index += 1
    #add the knots
    for i in range(ns.KnotsU.Count): ns.KnotsU[i] = knots_u[i]
    for i in range(ns.KnotsV.Count): ns.KnotsV[i] = knots_v[i]
    if not ns.IsValid: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddSurface(ns)
    if id==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return id


def AddPatch(object_ids, uv_spans_tuple_OR_surface_object_id, tolerance=None, trim=True, point_spacing=0.1, flexibility=1.0, surface_pull=1.0, fix_edges=False):
    """Fits a surface through curve, point, point cloud, and mesh objects.
    Parameters:
      object_ids ({guid, ...]): a list of object identifiers that indicate the objects to use for the patch fitting.
          Acceptable object types include curves, points, point clouds, and meshes.
      uv_spans_tuple_OR_surface_object_id ([number, number]|guid):  the U and V direction span counts for the automatically generated surface OR
          The identifier of the starting surface.  It is best if you create a starting surface that is similar in shape 
          to the surface you are trying to create.
      tolerance (number, optional): The tolerance used by input analysis functions. If omitted, Rhino's document absolute tolerance is used.
      trim (bool, optional): Try to find an outside curve and trims the surface to it.  The default value is True.
      point_spacing (number, optional): The basic distance between points sampled from input curves.  The default value is 0.1.
      flexibility (number, optional): Determines the behavior of the surface in areas where its not otherwise controlled by the input.
          Lower numbers make the surface behave more like a stiff material, higher, more like a flexible material.  
          That is, each span is made to more closely match the spans adjacent to it if there is no input geometry 
          mapping to that area of the surface when the flexibility value is low.  The scale is logarithmic.  
          For example, numbers around 0.001 or 0.1 make the patch pretty stiff and numbers around 10 or 100 
          make the surface flexible.  The default value is 1.0.
      surface_pull (number, optional): Similar to stiffness, but applies to the starting surface. The bigger the pull, the closer
          the resulting surface shape will be to the starting surface.  The default value is 1.0.
      fix_edges (bool, optional): Clamps the edges of the starting surface in place. This option is useful if you are using a
          curve or points for deforming an existing surface, and you do not want the edges of the starting surface 
          to move.  The default if False.
    Returns:
      guid: Identifier of the new surface object if successful.
      None: on error.
    Example:
    See Also:
    """
    # System.Collections.List instead of Python list because IronPython is
    # having problems converting a list to an IEnumerable<GeometryBase> which
    # is the 1st argument for Brep.CreatePatch
    geometry = List[Rhino.Geometry.GeometryBase]()
    u_span = 10
    v_span = 10
    rc = None
    id = rhutil.coerceguid(object_ids, False)
    if id: object_ids = [id]
    for object_id in object_ids:
        rhobj = rhutil.coercerhinoobject(object_id, False, False)
        if not rhobj: return None
        geometry.Add( rhobj.Geometry )
    if not geometry: return None
    
    surface = None
    if uv_spans_tuple_OR_surface_object_id:
      if type(uv_spans_tuple_OR_surface_object_id) is tuple:
        u_span = uv_spans_tuple_OR_surface_object_id[0]
        v_span = uv_spans_tuple_OR_surface_object_id[1]
      else:
        surface = rhutil.coercesurface(uv_spans_tuple_OR_surface_object_id, False)

    if not tolerance: tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    b = System.Array.CreateInstance(bool, 4)
    for i in range(4): b[i] = fix_edges
    brep = Rhino.Geometry.Brep.CreatePatch(geometry, surface, u_span, v_span, trim, False, point_spacing, flexibility, surface_pull, b, tolerance)
    if brep:
      rc = scriptcontext.doc.Objects.AddBrep(brep)
      scriptcontext.doc.Views.Redraw()
    return rc


def AddPipe(curve_id, parameters, radii, blend_type=0, cap=0, fit=False):
    """Creates a single walled surface with a circular profile around a curve
    Parameters:
      curve_id (guid): identifier of rail curve
      parameters, radii ([number, ...]): list of radius values at normalized curve parameters
      blend_type (number, optional): 0(local) or 1(global)
      cap (number, optional): 0(none), 1(flat), 2(round)
      fit (bool, optional): attempt to fit a single surface
    Returns:
      list(guid, ...): identifiers of new objects created
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.GetObject("Select curve to create pipe around", rs.filter.curve, True)
      if curve:
          domain = rs.CurveDomain(curve)
          rs.AddPipe(curve, 0, 4)
    See Also:
      
    """
    rail = rhutil.coercecurve(curve_id, -1, True)
    abs_tol = scriptcontext.doc.ModelAbsoluteTolerance
    ang_tol = scriptcontext.doc.ModelAngleToleranceRadians
    if type(parameters) is int or type(parameters) is float: parameters = [parameters]
    if type(radii) is int or type(radii) is float: radii = [radii]
    parameters = compat.ITERATOR2LIST(map(float,parameters))
    radii = compat.ITERATOR2LIST(map(float,radii))
    cap = System.Enum.ToObject(Rhino.Geometry.PipeCapMode, cap)
    breps = Rhino.Geometry.Brep.CreatePipe(rail, parameters, radii, blend_type==0, cap, fit, abs_tol, ang_tol)
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
    scriptcontext.doc.Views.Redraw()
    return rc


def AddPlanarSrf(object_ids):
    """Creates one or more surfaces from planar curves
    Parameters:
      object_ids ({guid, ...]): curves to use for creating planar surfaces
    Returns:
      list(guid, ...): identifiers of surfaces created on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select planar curves to build surface", rs.filter.curve)
      if objs: rs.AddPlanarSrf(objs)
    See Also:
      AddEdgeSrf
      AddSrfControlPtGrid
      AddSrfPt
      AddSrfPtGrid
    """
    id = rhutil.coerceguid(object_ids, False)
    if id: object_ids = [id]
    curves = [rhutil.coercecurve(id,-1,True) for id in object_ids]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    breps = Rhino.Geometry.Brep.CreatePlanarBreps(curves, tolerance)
    if breps:
        rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
        scriptcontext.doc.Views.Redraw()
        return rc


def AddPlaneSurface(plane, u_dir, v_dir):
    """Create a plane surface and add it to the document.
    Parameters:
      plane (plane): The plane.
      u_dir (number): The magnitude in the U direction.
      v_dir (number): The magnitude in the V direction.
    Returns:
      guid: The identifier of the new object if successful.
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      rs.AddPlaneSurface( rs.WorldXYPlane(), 5.0, 3.0 )
    See Also:
      AddCutPlane
      AddEdgeSrf
      AddSrfControlPtGrid
      AddSrfPt
      AddSrfPtGrid
      IsPlaneSurface
    """
    plane = rhutil.coerceplane(plane, True)
    u_interval = Rhino.Geometry.Interval(0, u_dir)
    v_interval = Rhino.Geometry.Interval(0, v_dir)
    plane_surface = Rhino.Geometry.PlaneSurface(plane, u_interval, v_interval) 
    if plane_surface is None: return scriptcontext.errorhandler()
    rc = scriptcontext.doc.Objects.AddSurface(plane_surface)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def AddLoftSrf(object_ids, start=None, end=None, loft_type=0, simplify_method=0, value=0, closed=False):
    """Adds a surface created by lofting curves to the document.
    - no curve sorting performed. pass in curves in the order you want them sorted
    - directions of open curves not adjusted. Use CurveDirectionsMatch and
      ReverseCurve to adjust the directions of open curves
    - seams of closed curves are not adjusted. Use CurveSeam to adjust the seam
      of closed curves
    Parameters:
      object_ids ({guid, guid, ...]): ordered list of the curves to loft through
      start (point, optional): starting point of the loft
      end (point, optional): ending point of the loft
      loft_type (number, optional): type of loft. Possible options are:
        0 = Normal. Uses chord-length parameterization in the loft direction
        1 = Loose. The surface is allowed to move away from the original curves
            to make a smoother surface. The surface control points are created
            at the same locations as the control points of the loft input curves.
        2 = Straight. The sections between the curves are straight. This is
            also known as a ruled surface.
        3 = Tight. The surface sticks closely to the original curves. Uses square
            root of chord-length parameterization in the loft direction
        4 = Developable. Creates a separate developable surface or polysurface
            from each pair of curves.
      simplify_method (number, optional): Possible options are:
        0 = None. Does not simplify.
        1 = Rebuild. Rebuilds the shape curves before lofting. modified by `value` below
        2 = Refit. Refits the shape curves to a specified tolerance. modified by `value` below
      value (number, optional): Additional value based on the specified `simplify_method`:
        Simplify  -   Description
        Rebuild(1) - then value is the number of control point used to rebuild
        Rebuild(1) - is specified and this argument is omitted, then curves will be
                     rebuilt using 10 control points.
        Refit(2) - then value is the tolerance used to rebuild.
        Refit(2) - is specified and this argument is omitted, then the document's
                     absolute tolerance us used for refitting.
      closed (bool, optional): close the loft back to the first curve
    Returns:
      list(guid, ...):Array containing the identifiers of the new surface objects if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Pick curves to loft", rs.filter.curve)
      if objs: rs.AddLoftSrf(objs)
    See Also:
      CurveDirectionsMatch
      CurveSeam
      ReverseCurve
    """
    if loft_type<0 or loft_type>5: raise ValueError("loft_type must be 0-4")
    if simplify_method<0 or simplify_method>2: raise ValueError("simplify_method must be 0-2")

    # get set of curves from object_ids
    curves = [rhutil.coercecurve(id,-1,True) for id in object_ids]
    if len(curves)<2: return scriptcontext.errorhandler()
    if start is None: start = Rhino.Geometry.Point3d.Unset
    if end is None: end = Rhino.Geometry.Point3d.Unset
    start = rhutil.coerce3dpoint(start, True)
    end = rhutil.coerce3dpoint(end, True)
    
    lt = Rhino.Geometry.LoftType.Normal
    if loft_type==1: lt = Rhino.Geometry.LoftType.Loose
    elif loft_type==2: lt = Rhino.Geometry.LoftType.Straight
    elif loft_type==3: lt = Rhino.Geometry.LoftType.Tight
    elif loft_type==4: lt = Rhino.Geometry.LoftType.Developable

    breps = None
    if simplify_method==0:
        breps = Rhino.Geometry.Brep.CreateFromLoft(curves, start, end, lt, closed)
    elif simplify_method==1:
        value = abs(value)
        rebuild_count = int(value)
        breps = Rhino.Geometry.Brep.CreateFromLoftRebuild(curves, start, end, lt, closed, rebuild_count)
    elif simplify_method==2:
        refit = abs(value)
        if refit==0: refit = scriptcontext.doc.ModelAbsoluteTolerance
        breps = Rhino.Geometry.Brep.CreateFromLoftRefit(curves, start, end, lt, closed, refit)
    if not breps: return scriptcontext.errorhandler()

    idlist = []
    for brep in breps:
        id = scriptcontext.doc.Objects.AddBrep(brep)
        if id!=System.Guid.Empty: idlist.append(id)
    if idlist: scriptcontext.doc.Views.Redraw()
    return idlist


def AddRevSrf(curve_id, axis, start_angle=0.0, end_angle=360.0):
    """Create a surface by revolving a curve around an axis
    Parameters:
      curve_id (guid): identifier of profile curve
      axis (line): line for the rail revolve axis
      start_angle, end_angle (number, optional): start and end angles of revolve
    Returns:
      guid: identifier of new object if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.AddLine((5,0,0), (10,0,10))
      rs.AddRevSrf( curve, ((0,0,0), (0,0,1)) )
    See Also:
      
    """
    curve = rhutil.coercecurve(curve_id, -1, True)
    axis = rhutil.coerceline(axis, True)
    start_angle = math.radians(start_angle)
    end_angle = math.radians(end_angle)
    srf = Rhino.Geometry.RevSurface.Create(curve, axis, start_angle, end_angle)
    if not srf: return scriptcontext.errorhandler()
    ns = srf.ToNurbsSurface()
    if not ns: return scriptcontext.errorhandler()
    rc = scriptcontext.doc.Objects.AddSurface(ns)
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSphere(center_or_plane, radius):
    """Add a spherical surface to the document
    Parameters:
      center_or_plane (point|plane): center point of the sphere. If a plane is input,
        the origin of the plane will be the center of the sphere
      radius (number): radius of the sphere in the current model units
    Returns:
      guid: identifier of the new object on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      radius = 2
      center = rs.GetPoint("Center of sphere")
      if center: rs.AddSphere(center, radius)
    See Also:
      AddBox
      AddCone
      AddCylinder
      AddTorus
    """
    c_or_p = rhutil.coerce3dpoint(center_or_plane)
    if c_or_p is None:
        c_or_p = rhutil.coerceplane(center_or_plane)
    if c_or_p is None: return None
    sphere = Rhino.Geometry.Sphere(c_or_p, radius)
    rc = scriptcontext.doc.Objects.AddSphere(sphere)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSrfContourCrvs(object_id, points_or_plane, interval=None):
    """Adds a spaced series of planar curves resulting from the intersection of
    defined cutting planes through a surface or polysurface. For more
    information, see Rhino help for details on the Contour command
    Parameters:
      object_id (guid): object identifier to contour
      points_or_plane ([point,point]|plane): either a list/tuple of two points or a plane
        if two points, they define the start and end points of a center line
        if a plane, the plane defines the cutting plane
      interval (number, optional): distance between contour curves.
    Returns:
      guid: ids of new contour curves on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object", rs.filter.surface + rs.filter.polysurface)
      startpoint = rs.GetPoint("Base point of center line")
      endpoint = rs.GetPoint("Endpoint of center line", startpoint)
      rs.AddSrfContourCrvs( obj, (startpoint, endpoint) )
    See Also:
      CurveContourPoints
    """
    brep = rhutil.coercebrep(object_id)
    plane = rhutil.coerceplane(points_or_plane)
    curves = None
    if plane:
        curves = Rhino.Geometry.Brep.CreateContourCurves(brep, plane)
    else:
        start = rhutil.coerce3dpoint(points_or_plane[0], True)
        end = rhutil.coerce3dpoint(points_or_plane[1], True)
        if not interval:
            bbox = brep.GetBoundingBox(True)
            v = bbox.Max - bbox.Min
            interval = v.Length / 50.0
        curves = Rhino.Geometry.Brep.CreateContourCurves(brep, start, end, interval)
    rc = []
    for crv in curves:
        id = scriptcontext.doc.Objects.AddCurve(crv)
        if id!=System.Guid.Empty: rc.append(id)
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSrfControlPtGrid(count, points, degree=(3,3)):
    """Creates a surface from a grid of points
    Parameters:
      count ([number, number])tuple of two numbers defining number of points in the u,v directions
      points ([point, ...]): list of 3D points
      degree ([number, number]): two numbers defining degree of the surface in the u,v directions
    Returns:
      guid: The identifier of the new object if successful.
      None: if not successful, or on error.
    Example:
    See Also:
    """
    points = rhutil.coerce3dpointlist(points, True)
    surf = Rhino.Geometry.NurbsSurface.CreateFromPoints(points, count[0], count[1], degree[0], degree[1])
    if not surf: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddSurface(surf)
    if id!=System.Guid.Empty:
        scriptcontext.doc.Views.Redraw()
        return id


def AddSrfPt(points):
    """Creates a new surface from either 3 or 4 corner points.
    Parameters:
      points ([point, point, point, point]): list of either 3 or 4 corner points
    Returns:
      guid: The identifier of the new object if successful.
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      points = rs.GetPoints(True, message1="Pick 3 or 4 corner points")
      if points: rs.AddSrfPt(points)
    See Also:
      AddEdgeSrf
      AddSrfControlPtGrid
      AddSrfPtGrid
    """
    points = rhutil.coerce3dpointlist(points, True)
    surface=None
    if len(points)==3:
        surface = Rhino.Geometry.NurbsSurface.CreateFromCorners(points[0], points[1], points[2])
    elif len(points)==4:
        surface = Rhino.Geometry.NurbsSurface.CreateFromCorners(points[0], points[1], points[2], points[3])
    if surface is None: return scriptcontext.errorhandler()
    rc = scriptcontext.doc.Objects.AddSurface(surface)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSrfPtGrid(count, points, degree=(3,3), closed=(False,False)):
    """Creates a surface from a grid of points
    Parameters:
      count ([number, number}): tuple of two numbers defining number of points in the u,v directions
      points ([point, ...]): list of 3D points
      degree ([number, number], optional): two numbers defining degree of the surface in the u,v directions
      closed ([bool, bool], optional): two booleans defining if the surface is closed in the u,v directions
    Returns:
      guid: The identifier of the new object if successful.
      None: if not successful, or on error.
    Example:
    See Also:
    """
    points = rhutil.coerce3dpointlist(points, True)
    surf = Rhino.Geometry.NurbsSurface.CreateThroughPoints(points, count[0], count[1], degree[0], degree[1], closed[0], closed[1])
    if not surf: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddSurface(surf)
    if id!=System.Guid.Empty:
        scriptcontext.doc.Views.Redraw()
        return id


def AddSweep1(rail, shapes, closed=False):
    """Adds a surface created through profile curves that define the surface
    shape and one curve that defines a surface edge.
    Parameters:
      rail (guid): identifier of the rail curve
      shapes ([guid, ...]): one or more cross section shape curves
      closed (bool, optional): If True, then create a closed surface
    Returns:
      list(guid, ...): of new surface objects if successful
      None: if not successful, or on error
    Example:
      import rhinoscriptsyntax as rs
      rail = rs.GetObject("Select rail curve", rs.filter.curve)
      if rail:
          shapes = rs.GetObjects("Select cross-section curves", rs.filter.curve)
          if shapes: rs.AddSweep1( rail, shapes )
    See Also:
      AddSweep2
      CurveDirectionsMatch
      ReverseCurve
    """
    rail = rhutil.coercecurve(rail, -1, True)
    shapes = [rhutil.coercecurve(shape, -1, True) for shape in shapes]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    breps = Rhino.Geometry.Brep.CreateFromSweep(rail, shapes, closed, tolerance)
    if not breps: return scriptcontext.errorhandler()
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSweep2(rails, shapes, closed=False):
    """Adds a surface created through profile curves that define the surface
    shape and two curves that defines a surface edge.
    Parameters:
      rails ([guid, guid]): identifiers of the two rail curve
      shapes ([guid, ...]): one or more cross section shape curves
      closed (bool, optional): If True, then create a closed surface
    Returns:
      list(guid, ...): of new surface objects if successful
      None: if not successful, or on error
    Example:
      import rhinoscriptsyntax as rs
      rails = rs.GetObjects("Select two rail curve", rs.filter.curve)
      if rails and len(rails)==2:
          shapes = rs.GetObjects("Select cross-section curves", rs.filter.curve)
          if shapes: rs.AddSweep2(rails, shapes)
    See Also:
      AddSweep1
      CurveDirectionsMatch
      ReverseCurve
    """
    rail1 = rhutil.coercecurve(rails[0], -1, True)
    rail2 = rhutil.coercecurve(rails[1], -1, True)
    shapes = [rhutil.coercecurve(shape, -1, True) for shape in shapes]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    breps = Rhino.Geometry.Brep.CreateFromSweep(rail1, rail2, shapes, closed, tolerance)
    if not breps: return scriptcontext.errorhandler()
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
    scriptcontext.doc.Views.Redraw()
    return rc


def AddRailRevSrf(profile, rail, axis, scale_height=False):
    """Adds a surface created through profile curves that define the surface
    shape and two curves that defines a surface edge.
    Parameters:
      profile (guid): identifier of the profile curve
      rail (guid): identifier of the rail curve
      axis ([point, point]): A list of two 3-D points identifying the start point and end point of the rail revolve axis, or a Line
      scale_height (bool, optional): If True, surface will be locally scaled. Defaults to False
    Returns:
      guid: identifier of the new object if successful
      None: if not successful, or on error
    Example:
      import rhinoscriptsyntax as rs
      profile = rs.GetObject("Select a profile", rs.filter.curve)
      if profile:
          rail = rs.GetObject("Select a rail", rs.filter.curve)
          if rail:
              rs.AddRailRevSrf(profile, rail, ((0,0,0),(0,0,1)))
    See Also:
      AddSweep1
      CurveDirectionsMatch
      ReverseCurve
    """
    profile_inst = rhutil.coercecurve(profile, -1, True)
    rail_inst = rhutil.coercecurve(rail, -1, True)
    axis_start = rhutil.coerce3dpoint(axis[0], True)
    axis_end = rhutil.coerce3dpoint(axis[1], True)

    line = Rhino.Geometry.Line(axis_start, axis_end)
    surface = Rhino.Geometry.NurbsSurface.CreateRailRevolvedSurface(profile_inst, rail_inst, line, scale_height)

    if not surface: return scriptcontext.errorhandler()
    rc = scriptcontext.doc.Objects.AddSurface(surface)
    scriptcontext.doc.Views.Redraw()
    return rc


def AddTorus(base, major_radius, minor_radius, direction=None):
    """Adds a torus shaped revolved surface to the document
    Parameters:
      base (point): 3D origin point of the torus or the base plane of the torus
      major_radius, minor_radius (number): the two radii of the torus
      directions (point):  A point that defines the direction of the torus when base is a point.
        If omitted, a torus that is parallel to the world XY plane is created
    Returns:
      guid: The identifier of the new object if successful.
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      major_radius = 5.0
      minor_radius = major_radius - 2.0
      base = rs.GetPoint("Base of torus")
      if base:
          direction = rs.GetPoint("Direction of torus", base)
          if direction:
              rs.AddTorus( base, major_radius, minor_radius, direction )
    See Also:
      AddBox
      AddCone
      AddCylinder
      AddSphere
    """
    baseplane = None
    basepoint = rhutil.coerce3dpoint(base)
    if basepoint is None:
        baseplane = rhutil.coerceplane(base, True)
        if direction!=None: return scriptcontext.errorhandler()
    if baseplane is None:
        direction = rhutil.coerce3dpoint(direction, False)
        if direction: direction = direction-basepoint
        else: direction = Rhino.Geometry.Vector3d.ZAxis
        baseplane = Rhino.Geometry.Plane(basepoint, direction)
    torus = Rhino.Geometry.Torus(baseplane, major_radius, minor_radius)
    revsurf = torus.ToRevSurface()
    rc = scriptcontext.doc.Objects.AddSurface(revsurf)
    scriptcontext.doc.Views.Redraw()
    return rc


def BooleanDifference(input0, input1, delete_input=True):
    """Performs a boolean difference operation on two sets of input surfaces
    and polysurfaces. For more details, see the BooleanDifference command in
    the Rhino help file
    Parameters:
        input0 ([guid, ...]): list of surfaces to subtract from
        input1 ([guid, ...]): list of surfaces to be subtracted
        delete_input (bool, optional): delete all input objects
    Returns:
        list(guid, ...): of identifiers of newly created objects on success
        None: on error
    Example:
      import rhinoscriptsyntax as rs
      filter = rs.filter.surface | rs.filter.polysurface
      input0 = rs.GetObjects("Select first set of surfaces or polysurfaces", filter)
      if input0:
          input1 = rs.GetObjects("Select second set of surfaces or polysurfaces", filter)
          if input1: rs.BooleanDifference(input0, input1)
    See Also:
      BooleanIntersection
      BooleanUnion
    """
    if type(input0) is list or type(input0) is tuple: pass
    else: input0 = [input0]
    
    if type(input1) is list or type(input1) is tuple: pass
    else: input1 = [input1]

    breps0 = [rhutil.coercebrep(id, True) for id in input0]
    breps1 = [rhutil.coercebrep(id, True) for id in input1]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    newbreps = Rhino.Geometry.Brep.CreateBooleanDifference(breps0, breps1, tolerance)
    if newbreps is None: return scriptcontext.errorhandler()
    
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in newbreps]
    if delete_input:
        for id in input0: scriptcontext.doc.Objects.Delete(id, True)
        for id in input1: scriptcontext.doc.Objects.Delete(id, True)
    scriptcontext.doc.Views.Redraw()
    return rc


def BooleanIntersection(input0, input1, delete_input=True):
    """Performs a boolean intersection operation on two sets of input surfaces
    and polysurfaces. For more details, see the BooleanIntersection command in
    the Rhino help file
    Parameters:
        input0 ([guid, ...]): list of surfaces
        input1 ([guid, ...]): list of surfaces
        delete_input (bool, optional): delete all input objects
    Returns:
        list(guid, ...): of identifiers of newly created objects on success
        None: on error
    Example:
      import rhinoscriptsyntax as rs
      input0 = rs.GetObjects("Select first set of surfaces or polysurfaces", rs.filter.surface | rs.filter.polysurface)
      if input0:
          input1 = rs.GetObjects("Select second set of surfaces or polysurfaces", rs.filter.surface | rs.filter.polysurface)
          if input1: rs.BooleanIntersection( input0, input1 )
    See Also:
      BooleanDifference
      BooleanUnion
    """
    if type(input0) is list or type(input0) is tuple: pass
    else: input0 = [input0]
    
    if type(input1) is list or type(input1) is tuple: pass
    else: input1 = [input1]

    breps0 = [rhutil.coercebrep(id, True) for id in input0]
    breps1 = [rhutil.coercebrep(id, True) for id in input1]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    newbreps = Rhino.Geometry.Brep.CreateBooleanIntersection(breps0, breps1, tolerance)
    if newbreps is None: return scriptcontext.errorhandler()
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in newbreps]
    if delete_input:
        for id in input0: scriptcontext.doc.Objects.Delete(id, True)
        for id in input1: scriptcontext.doc.Objects.Delete(id, True)
    scriptcontext.doc.Views.Redraw()
    return rc


def BooleanUnion(input, delete_input=True):
    """Performs a boolean union operation on a set of input surfaces and
    polysurfaces. For more details, see the BooleanUnion command in the
    Rhino help file
    Parameters:
        input ([guid, ...]): list of surfaces to union
        delete_input (bool, optional):  delete all input objects
    Returns:
        list(guid, ...): of identifiers of newly created objects on success
        None on error
    Example:
      import rhinoscriptsyntax as rs
      input = rs.GetObjects("Select surfaces or polysurfaces to union", rs.filter.surface | rs.filter.polysurface)
      if input and len(input)>1: rs.BooleanUnion(input)
    See Also:
      BooleanDifference
      BooleanUnion
    """
    if len(input)<2: return scriptcontext.errorhandler()
    breps = [rhutil.coercebrep(id, True) for id in input]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    newbreps = Rhino.Geometry.Brep.CreateBooleanUnion(breps, tolerance)
    if newbreps is None: return scriptcontext.errorhandler()
    
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in newbreps]
    if delete_input:
        for id in input: scriptcontext.doc.Objects.Delete(id, True)
    scriptcontext.doc.Views.Redraw()
    return rc


def BrepClosestPoint(object_id, point):
    """Returns the point on a surface or polysurface that is closest to a test
    point. This function works on both untrimmed and trimmed surfaces.
    Parameters:
      object_id (guid): The object's identifier.
      point (point): The test, or sampling point.
    Returns:
      tuple(point, [number, number], [number, number], vector): of closest point information if successful. The list will
      contain the following information:
      Element     Type             Description
         0        Point3d          The 3-D point at the parameter value of the 
                                   closest point.
         1        (U, V)           Parameter values of closest point. Note, V 
                                   is 0 if the component index type is brep_edge
                                   or brep_vertex. 
         2        (type, index)    The type and index of the brep component that
                                   contains the closest point. Possible types are
                                   brep_face, brep_edge or brep_vertex.
         3        Vector3d         The normal to the brep_face, or the tangent
                                   to the brep_edge.  
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if obj:
          point = rs.GetPoint("Pick a test point")
          if point:
              arrCP = rs.BrepClosestPoint(obj, point)
              if arrCP:
                  rs.AddPoint(point)
                  rs.AddPoint( arrCP[0] )
    See Also:
      EvaluateSurface
      IsSurface
      SurfaceClosestPoint
    """
    brep = rhutil.coercebrep(object_id, True)
    point = rhutil.coerce3dpoint(point, True)
    rc = brep.ClosestPoint(point, 0.0)
    if rc[0]:
        type = int(rc[2].ComponentIndexType)
        index = rc[2].Index
        return rc[1], (rc[3], rc[4]), (type, index), rc[5]


def CapPlanarHoles(surface_id):
    """Caps planar holes in a surface or polysurface
    Parameters:
      surface_id (guid): The identifier of the surface or polysurface to cap.
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface or polysurface to cap", rs.filter.surface | rs.filter.polysurface)
      if surface: rs.CapPlanarHoles( surface )
    See Also:
      ExtrudeCurve
      ExtrudeCurvePoint
      ExtrudeCurveStraight
      ExtrudeSurface
    """
    brep = rhutil.coercebrep(surface_id, True)
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    newbrep = brep.CapPlanarHoles(tolerance)
    if newbrep:
        if newbrep.SolidOrientation == Rhino.Geometry.BrepSolidOrientation.Inward:
            newbrep.Flip()
        surface_id = rhutil.coerceguid(surface_id)
        if surface_id and scriptcontext.doc.Objects.Replace(surface_id, newbrep):
            scriptcontext.doc.Views.Redraw()
            return True
    return False


def DuplicateEdgeCurves(object_id, select=False):
    """Duplicates the edge curves of a surface or polysurface. For more
    information, see the Rhino help file for information on the DupEdge
    command.
    Parameters:
      object_id (guid): The identifier of the surface or polysurface object.
      select (bool, optional):  Select the duplicated edge curves. The default is not
      to select (False).
    Returns:
      list(guid, ..): identifying the newly created curve objects if successful.
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select surface or polysurface", rs.filter.surface | rs.filter.polysurface)
      if obj:
          rs.DuplicateEdgeCurves( obj, True )
          rs.DeleteObject( obj )
    See Also:
      IsPolysurface
      IsSurface
    """
    brep = rhutil.coercebrep(object_id, True)
    out_curves = brep.DuplicateEdgeCurves()
    curves = []
    for curve in out_curves:
        if curve.IsValid:
            rc = scriptcontext.doc.Objects.AddCurve(curve)
            curve.Dispose()
            if rc==System.Guid.Empty: return None
            curves.append(rc)
            if select: 
                rhobject = rhutil.coercerhinoobject(rc)
                rhobject.Select(True)
    if curves: scriptcontext.doc.Views.Redraw()
    return curves


def DuplicateSurfaceBorder(surface_id, type=0):
    """Create curves that duplicate a surface or polysurface border
    Parameters:
      surface_id (guid): identifier of a surface
      type (number, optional): the border curves to return
         0=both exterior and interior,
         1=exterior
         2=interior
    Returns:
      list(guid, ...): list of curve ids on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface or polysurface", rs.filter.surface | rs.filter.polysurface)
      if surface: rs.DuplicateSurfaceBorder( surface )
    See Also:
      DuplicateEdgeCurves
      DuplicateMeshBorder
    """
    brep = rhutil.coercebrep(surface_id, True)
    inner = type==0 or type==2
    outer = type==0 or type==1
    curves = brep.DuplicateNakedEdgeCurves(outer, inner)
    if curves is None: return scriptcontext.errorhandler()
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance * 2.1
    curves = Rhino.Geometry.Curve.JoinCurves(curves, tolerance)
    if curves is None: return scriptcontext.errorhandler()
    rc = [scriptcontext.doc.Objects.AddCurve(c) for c in curves]
    scriptcontext.doc.Views.Redraw()
    return rc


def EvaluateSurface(surface_id, u, v):
    """Evaluates a surface at a U,V parameter
    Parameters:
      surface_id (guid): the object's identifier.
      u, v ({number, number]): u, v parameters to evaluate.
    Returns:
      point: a 3-D point if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      objectId = rs.GetObject("Select a surface")
      if rs.IsSurface(objectId):
          domainU = rs.SurfaceDomain(objectId, 0)
          domainV = rs.SurfaceDomain(objectId, 1)
          u = domainU[1]/2.0
          v = domainV[1]/2.0
          point = rs.EvaluateSurface(objectId, u, v)
          rs.AddPoint( point )
    See Also:
      IsSurface
      SurfaceClosestPoint
    """
    surface = rhutil.coercesurface(surface_id, True)
    rc = surface.PointAt(u,v)
    if rc.IsValid: return rc
    return scriptcontext.errorhandler()


def ExtendSurface(surface_id, parameter, length, smooth=True):
    """Lengthens an untrimmed surface object
    Parameters:
      surface_id (guid): identifier of a surface
      parameter ([number, number}): tuple of two values definfing the U,V parameter to evaluate.
        The surface edge closest to the U,V parameter will be the edge that is
        extended
      length (number): amount to extend to surface
      smooth (bool, optional): If True, the surface is extended smoothly curving from the
        edge. If False, the surface is extended in a straight line from the edge
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      pick = rs.GetObjectEx("Select surface to extend", rs.filter.surface)
      if pick:
          parameter = rs.SurfaceClosestPoint(pick[0], pick[3])
          rs.ExtendSurface(pick[0], parameter, 5.0)
    See Also:
      IsSurface
    """
    surface = rhutil.coercesurface(surface_id, True)
    edge = surface.ClosestSide(parameter[0], parameter[1])
    newsrf = surface.Extend(edge, length, smooth)
    if newsrf:
        surface_id = rhutil.coerceguid(surface_id)
        if surface_id: scriptcontext.doc.Objects.Replace(surface_id, newsrf)
        scriptcontext.doc.Views.Redraw()
    return newsrf is not None


def ExplodePolysurfaces(object_ids, delete_input=False):
    """Explodes, or unjoins, one or more polysurface objects. Polysurfaces
    will be exploded into separate surfaces
    Parameters:
      object_ids ([guid, ...]): identifiers of polysurfaces to explode
      delete_input 9bool, optional): delete input objects after exploding
    Returns:
      list(guid, ...): of identifiers of exploded pieces on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select polysurface to explode", rs.filter.polysurface)
      if rs.IsPolysurface(obj):
          rs.ExplodePolysurfaces( obj )
    See Also:
      IsPolysurface
      IsSurface
    """
    id = rhutil.coerceguid(object_ids, False)
    if id: object_ids = [id]
    ids = []
    for id in object_ids:
        brep = rhutil.coercebrep(id, True)
        if brep.Faces.Count>1:
            for i in range(brep.Faces.Count):
                copyface = brep.Faces[i].DuplicateFace(False)
                face_id = scriptcontext.doc.Objects.AddBrep(copyface)
                if face_id!=System.Guid.Empty: ids.append(face_id)
            if delete_input: scriptcontext.doc.Objects.Delete(id, True)
    scriptcontext.doc.Views.Redraw()
    return ids


def ExtractIsoCurve(surface_id, parameter, direction):
    """Extracts isoparametric curves from a surface
    Parameters:
      surface_id (guid): identifier of a surface
      parameter ([number, number]): u,v parameter of the surface to evaluate
      direction (number): Direction to evaluate
        0 = u
        1 = v
        2 = both
    Returns:
      list(guid, ...): of curve ids on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select surface for isocurve extraction", rs.filter.surface)
      point = rs.GetPointOnSurface(obj, "Select location for extraction")
      parameter = rs.SurfaceClosestPoint(obj, point)
      rs.ExtractIsoCurve( obj, parameter, 2 )
    See Also:
      IsSurface
    """
    surface = rhutil.coercesurface(surface_id, True)
    ids = []
    if direction==0 or direction==2:
        curves = None
        if type(surface) is Rhino.Geometry.BrepFace:
            curves = surface.TrimAwareIsoCurve(0, parameter[1])
        else:
            curves = [surface.IsoCurve(0,parameter[1])]
        if curves:
            for curve in curves:
                id = scriptcontext.doc.Objects.AddCurve(curve)
                if id!=System.Guid.Empty: ids.append(id)
    if direction==1 or direction==2:
        curves = None
        if type(surface) is Rhino.Geometry.BrepFace:
            curves = surface.TrimAwareIsoCurve(1, parameter[0])
        else:
            curves = [surface.IsoCurve(1,parameter[0])]
        if curves:
            for curve in curves:
                id = scriptcontext.doc.Objects.AddCurve(curve)
                if id!=System.Guid.Empty: ids.append(id)
    scriptcontext.doc.Views.Redraw()
    return ids


def ExtractSurface(object_id, face_indices, copy=False):
    """Separates or copies a surface or a copy of a surface from a polysurface
    Parameters:
      object_id (guid): polysurface identifier
      face_indices (number, ...): one or more numbers representing faces
      copy (bool, optional): If True the faces are copied. If False, the faces are extracted
    Returns:
      list(guid, ...): identifiers of extracted surface objects on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select polysurface", rs.filter.polysurface, True)
      if obj: rs.ExtractSurface(obj, 0)
    See Also:
      BrepClosestPoint
      IsSurface
      IsPolysurface
    """
    brep = rhutil.coercebrep(object_id, True)
    if hasattr(face_indices, "__getitem__"): pass
    else: face_indices = [face_indices]
    rc = []
    face_indices = sorted(face_indices, reverse=True)
    for index in face_indices:
        face = brep.Faces[index]
        newbrep = face.DuplicateFace(True)
        id = scriptcontext.doc.Objects.AddBrep(newbrep)
        rc.append(id)
    if not copy:
        for index in face_indices: brep.Faces.RemoveAt(index)
        id = rhutil.coerceguid(object_id)
        scriptcontext.doc.Objects.Replace(id, brep)
    scriptcontext.doc.Views.Redraw()
    return rc


def ExtrudeCurve(curve_id, path_id):
    """Creates a surface by extruding a curve along a path
    Parameters:
      curve_id (guid): identifier of the curve to extrude
      path_id (guid): identifier of the path curve
    Returns:
      guid: identifier of new surface on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.AddCircle(rs.WorldXYPlane(), 5)
      path = rs.AddLine([5,0,0], [10,0,10])
      rs.ExtrudeCurve( curve, path )
    See Also:
      ExtrudeCurvePoint
      ExtrudeCurveStraight
      ExtrudeSurface
    """
    curve1 = rhutil.coercecurve(curve_id, -1, True)
    curve2 = rhutil.coercecurve(path_id, -1, True)
    srf = Rhino.Geometry.SumSurface.Create(curve1, curve2)
    rc = scriptcontext.doc.Objects.AddSurface(srf)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def ExtrudeCurvePoint(curve_id, point):
    """Creates a surface by extruding a curve to a point
    Parameters:
      curve_id (guid): identifier of the curve to extrude
      point (point): 3D point
    Returns:
      guid: identifier of new surface on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.AddCircle(rs.WorldXYPlane(), 5)
      point = (0,0,10)
      rs.ExtrudeCurvePoint( curve, point )
    See Also:
      ExtrudeCurve
      ExtrudeCurveStraight
      ExtrudeSurface
    """
    curve = rhutil.coercecurve(curve_id, -1, True)
    point = rhutil.coerce3dpoint(point, True)
    srf = Rhino.Geometry.Surface.CreateExtrusionToPoint(curve, point)
    rc = scriptcontext.doc.Objects.AddSurface(srf)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def ExtrudeCurveStraight(curve_id, start_point, end_point):
    """Create surface by extruding a curve along two points that define a line
    Parameters:
      curve_id (guid): identifier of the curve to extrude
      start_point, end_point (point): 3D points that specify distance and direction
    Returns:
      guid: identifier of new surface on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.AddCircle(rs.WorldXYPlane(), 5)
      rs.ExtrudeCurveStraight( curve, (0,0,0), (0, 10, 10) )
    See Also:
      ExtrudeCurve
      ExtrudeCurvePoint
      ExtrudeSurface
    """
    curve = rhutil.coercecurve(curve_id, -1, True)
    start_point = rhutil.coerce3dpoint(start_point, True)
    end_point = rhutil.coerce3dpoint(end_point, True)
    vec = end_point - start_point
    srf = Rhino.Geometry.Surface.CreateExtrusion(curve, vec)
    rc = scriptcontext.doc.Objects.AddSurface(srf)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def ExtrudeSurface(surface, curve, cap=True):
    """Create surface by extruding along a path curve
    Parameters:
      surface (guid): identifier of the surface to extrude
      curve (guid): identifier of the path curve
      cap (bool, optional): extrusion is capped at both ends
    Returns:
      guid: identifier of new surface on success
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.AddSrfPt([(0,0,0), (5,0,0), (5,5,0), (0,5,0)])
      curve = rs.AddLine((5,0,0), (10,0,10))
      rs.ExtrudeSurface(surface, curve)
    See Also:
      ExtrudeCurve
      ExtrudeCurvePoint
      ExtrudeCurveStraight
    """
    brep = rhutil.coercebrep(surface, True)
    curve = rhutil.coercecurve(curve, -1, True)
    newbrep = brep.Faces[0].CreateExtrusion(curve, cap)
    if newbrep:
        rc = scriptcontext.doc.Objects.AddBrep(newbrep)
        scriptcontext.doc.Views.Redraw()
        return rc


def FilletSurfaces(surface0, surface1, radius, uvparam0=None, uvparam1=None):
    """Create constant radius rolling ball fillets between two surfaces. Note,
    this function does not trim the original surfaces of the fillets
    Parameters:
      surface0, surface1 (guid): identifiers of first and second surface
      radius (number): a positive fillet radius
      uvparam0 ([number, number], optional): a u,v surface parameter of surface0 near where the fillet
        is expected to hit the surface
      uvparam1([number, number], optional): same as uvparam0, but for surface1
    Returns:
      guid: ids of surfaces created on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface0 = rs.GetObject("First surface", rs.filter.surface)
      surface1 = rs.GetObject("Second surface", rs.filter.surface)
      rs.FilletSurfaces(surface0, surface1, 2.0)
    See Also:
      IsSurface
    """
    surface0 = rhutil.coercesurface(surface0, True)
    surface1 = rhutil.coercesurface(surface1, True)
    if uvparam0 is not None and uvparam1 is not None:   #SR9 error: "Could not convert None to a Point2d"
        uvparam0 = rhutil.coerce2dpoint(uvparam0, True)
        uvparam1 = rhutil.coerce2dpoint(uvparam1, True)
    surfaces = None
    tol = scriptcontext.doc.ModelAbsoluteTolerance
    if uvparam0 and uvparam1:
        surfaces = Rhino.Geometry.Surface.CreateRollingBallFillet(surface0, uvparam0, surface1, uvparam1, radius, tol)
    else:
        surfaces = Rhino.Geometry.Surface.CreateRollingBallFillet(surface0, surface1, radius, tol)
    if not surfaces: return scriptcontext.errorhandler()
    rc = []
    for surf in surfaces:
        rc.append( scriptcontext.doc.Objects.AddSurface(surf) )
    scriptcontext.doc.Views.Redraw()
    return rc


def FlipSurface(surface_id, flip=None):
    """Returns or changes the normal direction of a surface. This feature can
    also be found in Rhino's Dir command
    Parameters:
      surface_id (guid): identifier of a surface object
      flip (bool, optional) new normal orientation, either flipped(True) or not flipped (False).
    Returns:
      vector: if flipped is not specified, the current normal orientation
      vector: if flipped is specified, the previous normal orientation
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surf = rs.GetObject("Select object", rs.filter.surface)
      if surf:
          flip = rs.FlipSurface(surf)
          if flip: rs.FlipSurface(surf, False)
    See Also:
      IsSurface
    """
    brep = rhutil.coercebrep(surface_id, True)
    if brep.Faces.Count>1: return scriptcontext.errorhandler()
    face = brep.Faces[0]
    old_reverse = face.OrientationIsReversed
    if flip!=None and brep.IsSolid==False and old_reverse!=flip:
        brep.Flip()
        surface_id = rhutil.coerceguid(surface_id)
        if surface_id: scriptcontext.doc.Objects.Replace(surface_id, brep)
        scriptcontext.doc.Views.Redraw()
    return old_reverse


def IntersectBreps(brep1, brep2, tolerance=None):
    """Intersects a brep object with another brep object. Note, unlike the
    SurfaceSurfaceIntersection function this function works on trimmed surfaces.
    Parameters:
      brep1 (guid): identifier of first brep object
      brep2 (guid): identifier of second brep object
      tolerance (number): Distance tolerance at segment midpoints. If omitted,
                  the current absolute tolerance is used.
    Returns:
      list(guid, ...): identifying the newly created intersection curve and point objects if successful.
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      brep1 = rs.GetObject("Select the first brep", rs.filter.surface | rs.filter.polysurface)
      if brep1:
          brep2 = rs.GetObject("Select the second", rs.filter.surface | rs.filter.polysurface)
          if brep2: rs.IntersectBreps( brep1, brep2)
    See Also:
      
    """
    brep1 = rhutil.coercebrep(brep1, True)
    brep2 = rhutil.coercebrep(brep2, True)
    if tolerance is None or tolerance < 0.0:
        tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    rc = Rhino.Geometry.Intersect.Intersection.BrepBrep(brep1, brep2, tolerance)
    if not rc[0]: return None
    out_curves = rc[1]
    out_points = rc[2]
    merged_curves = Rhino.Geometry.Curve.JoinCurves(out_curves, 2.1 * tolerance)
    
    ids = []
    if merged_curves:
        for curve in merged_curves:
            if curve.IsValid:
                rc = scriptcontext.doc.Objects.AddCurve(curve)
                curve.Dispose()
                if rc==System.Guid.Empty: return scriptcontext.errorhandler()
                ids.append(rc)
    else:
        for curve in out_curves:
            if curve.IsValid:
                rc = scriptcontext.doc.Objects.AddCurve(curve)
                curve.Dispose()
                if rc==System.Guid.Empty: return scriptcontext.errorhandler()
                ids.append(rc)
    for point in out_points:
        rc = scriptcontext.doc.Objects.AddPoint(point)
        if rc==System.Guid.Empty: return scriptcontext.errorhandler()
        ids.append(rc)
    if ids:
        scriptcontext.doc.Views.Redraw()
        return ids


def IntersectSpheres(sphere_plane0, sphere_radius0, sphere_plane1, sphere_radius1):
    """Calculates intersections of two spheres
    Parameters:
      sphere_plane0 (plane): an equatorial plane of the first sphere. The origin of the
        plane will be the center point of the sphere
      sphere_radius0 (number): radius of the first sphere
      sphere_plane1 (plane): plane for second sphere
      sphere_radius1 (number): radius for second sphere
    Returns:
      list(number, point, number): of intersection results
        [0] = type of intersection (0=point, 1=circle, 2=spheres are identical)
        [1] = Point of intersection or plane of circle intersection
        [2] = radius of circle if circle intersection
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      plane0 = rs.WorldXYPlane()
      plane1 = rs.MovePlane(plane0, (10,0,0))
      radius = 10
      results = rs.IntersectSpheres(plane0, radius, plane1, radius)
      if results:
          if results[0] == 0: rs.AddPoint(results[1])
          else: rs.AddCircle( results[1], results[2])
    See Also:
      IntersectBreps
      IntersectPlanes
    """
    plane0 = rhutil.coerceplane(sphere_plane0, True)
    plane1 = rhutil.coerceplane(sphere_plane1, True)
    sphere0 = Rhino.Geometry.Sphere(plane0, sphere_radius0)
    sphere1 = Rhino.Geometry.Sphere(plane1, sphere_radius1)
    rc, circle = Rhino.Geometry.Intersect.Intersection.SphereSphere(sphere0, sphere1)
    if rc==Rhino.Geometry.Intersect.SphereSphereIntersection.Point:
        return [0, circle.Center]
    if rc==Rhino.Geometry.Intersect.SphereSphereIntersection.Circle:
        return [1, circle.Plane, circle.Radius]
    if rc==Rhino.Geometry.Intersect.SphereSphereIntersection.Overlap:
        return [2]
    return scriptcontext.errorhandler()


def IsBrep(object_id):
    """Verifies an object is a Brep, or a boundary representation model, object.
    Parameters:
      object_id (guid): The object's identifier.
    Returns:
      bool: True if successful, otherwise False.
      None: on error.
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a Brep")
      if rs.IsBrep(obj):
          print("The object is a Brep.")
      else:
          print("The object is not a Brep.")
    See Also:
      IsPolysurface
      IsPolysurfaceClosed
      IsSurface
    """
    return rhutil.coercebrep(object_id)!=None


def IsCone(object_id):
    """Determines if a surface is a portion of a cone
    Parameters:
      object_id (guid): the surface object's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if surface:
          if rs.IsCone(surface):
              print("The surface is a portion of a cone.")
          else:
              print("The surface is not a portion of a cone.")
    See Also:
      IsCylinder
      IsSphere
      IsSurface
      IsTorus
    """
    surface = rhutil.coercesurface(object_id, True)
    return surface.IsCone()


def IsCylinder(object_id):
    """Determines if a surface is a portion of a cone
    Parameters:
      object_id (guid): the cylinder object's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if surface:
          if rs.IsCylinder(surface):
              print("The surface is a portion of a cylinder.")
          else:
              print("The surface is not a portion of a cylinder.")
    See Also:
      IsCone
      IsSphere
      IsSurface
      IsTorus
    """
    surface = rhutil.coercesurface(object_id, True)
    return surface.IsCylinder()


def IsPlaneSurface(object_id):
    """Verifies an object is a plane surface. Plane surfaces can be created by
    the Plane command. Note, a plane surface is not a planar NURBS surface
    Parameters:
      object_id (guid): the object's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface to trim", rs.filter.surface)
      if surface and rs.IsPlaneSurface(surface):
          print("got a plane surface")
      else:
          print("not a plane surface")
    See Also:
      IsBrep
      IsPolysurface
      IsSurface
    """
    face = rhutil.coercesurface(object_id, True)
    if type(face) is Rhino.Geometry.BrepFace and face.IsSurface:
        return type(face.UnderlyingSurface()) is Rhino.Geometry.PlaneSurface
    return False
    

def IsPointInSurface(object_id, point, strictly_in=False, tolerance=None):
    """Verifies that a point is inside a closed surface or polysurface
    Parameters:
      object_id (guid): the object's identifier
      point (point): The test, or sampling point
      strictly_in (bool, optional): If true, the test point must be inside by at least tolerance
      tolerance (number, optional): distance tolerance used for intersection and determining
        strict inclusion. If omitted, Rhino's internal tolerance is used
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a polysurface", rs.filter.polysurface)
      if rs.IsPolysurfaceClosed(obj):
          point = rs.GetPoint("Pick a test point")
          if point:
              if rs.IsPointInSurface(obj, point):
                  print("The point is inside the polysurface.")
              else:
                  print("The point is not inside the polysurface.")
    See Also:
      IsPointOnSurface
    """
    object_id = rhutil.coerceguid(object_id, True)
    point = rhutil.coerce3dpoint(point, True)
    if object_id==None or point==None: return scriptcontext.errorhandler()
    obj = scriptcontext.doc.Objects.Find(object_id)
    if tolerance is None: tolerance = Rhino.RhinoMath.SqrtEpsilon
    brep = None
    if type(obj)==Rhino.DocObjects.ExtrusionObject:
        brep = obj.ExtrusionGeometry.ToBrep(False)
    elif type(obj)==Rhino.DocObjects.BrepObject:
        brep = obj.BrepGeometry
    elif hasattr(obj, "Geometry"):
        brep = obj.Geometry
    return brep.IsPointInside(point, tolerance, strictly_in)


def IsPointOnSurface(object_id, point):
    """Verifies that a point lies on a surface
    Parameters:
      object_id (guid): the object's identifier
      point (point): The test, or sampling point
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surf = rs.GetObject("Select a surface")
      if rs.IsSurface(surf):
          point = rs.GetPoint("Pick a test point")
          if point:
              if rs.IsPointOnSurface(surf, point):
                  print("The point is on the surface.")
              else:
                  print("The point is not on the surface.")
    See Also:
      IsPointInSurface
    """
    surf = rhutil.coercesurface(object_id, True)
    point = rhutil.coerce3dpoint(point, True)
    rc, u, v = surf.ClosestPoint(point)
    if rc:
        srf_pt = surf.PointAt(u,v)
        if srf_pt.DistanceTo(point)>scriptcontext.doc.ModelAbsoluteTolerance:
            rc = False
        else:
            rc = surf.IsPointOnFace(u,v) != Rhino.Geometry.PointFaceRelation.Exterior
    return rc


def IsPolysurface(object_id):
    """Verifies an object is a polysurface. Polysurfaces consist of two or more
    surfaces joined together. If the polysurface fully encloses a volume, it is
    considered a solid.
    Parameters:
      object_id (guid): the object's identifier
    Returns:
      bool: True is successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a polysurface")
      if rs.IsPolysurface(obj):
          print("The object is a polysurface.")
      else:
          print("The object is not a polysurface.")
    See Also:
      IsBrep
      IsPolysurfaceClosed
    """
    brep = rhutil.coercebrep(object_id)
    if brep is None: return False
    return brep.Faces.Count>1


def IsPolysurfaceClosed(object_id):
    """Verifies a polysurface object is closed. If the polysurface fully encloses
    a volume, it is considered a solid.
    Parameters:
      object_id (guid): the object's identifier
    Returns:
      bool: True is successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a polysurface", rs.filter.polysurface)
      if rs.IsPolysurfaceClosed(obj):
          print("The polysurface is closed.")
      else:
          print("The polysurface is not closed.")
    See Also:
      IsBrep
      IsPolysurface
    """
    brep = rhutil.coercebrep(object_id, True)
    return brep.IsSolid


def IsSphere(object_id):
    """Determines if a surface is a portion of a sphere
    Parameters:
      object_id (guid): the object's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if surface:
          if rs.IsSphere(surface):
              print("The surface is a portion of a sphere.")
          else:
              print("The surface is not a portion of a sphere.")
    See Also:
      IsCone
      IsCylinder
      IsSurface
      IsTorus
    """
    surface = rhutil.coercesurface(object_id, True)
    return surface.IsSphere()


def IsSurface(object_id):
    """Verifies an object is a surface. Brep objects with only one face are
    also considered surfaces.
    Parameters:
      object_id (guid): the object's identifier.
    Returns:
      bool: True if successful, otherwise False.
    Example:
      import rhinoscriptsyntax as rs
      objectId = rs.GetObject("Select a surface")
      if rs.IsSurface(objectId):
          print("The object is a surface.")
      else:
          print("The object is not a surface.")
    See Also:
      IsPointOnSurface
      IsSurfaceClosed
      IsSurfacePlanar
      IsSurfaceSingular
      IsSurfaceTrimmed
    """
    brep = rhutil.coercebrep(object_id)
    if brep and brep.Faces.Count==1: return True
    surface = rhutil.coercesurface(object_id)
    return (surface!=None)


def IsSurfaceClosed( surface_id, direction ):
    """Verifies a surface object is closed in the specified direction.  If the
    surface fully encloses a volume, it is considered a solid
    Parameters:
      surface_id (guid): identifier of a surface
      direction (number): 0=U direction check, 1=V direction check
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfaceClosed(obj, 0):
          print("The surface is closed in the U direction.")
      else:
          print("The surface is not closed in the U direction.")
    See Also:
      IsSurface
      IsSurfacePlanar
      IsSurfaceSingular
      IsSurfaceTrimmed
    """
    surface = rhutil.coercesurface(surface_id, True)
    return surface.IsClosed(direction)


def IsSurfacePeriodic(surface_id, direction):
    """Verifies a surface object is periodic in the specified direction.
    Parameters:
      surface_id (guid): identifier of a surface
      direction (number): 0=U direction check, 1=V direction check
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfacePeriodic(obj, 0):
          print("The surface is periodic in the U direction.")
      else:
          print("The surface is not periodic in the U direction.")
    See Also:
      IsSurface
      IsSurfaceClosed
      IsSurfacePlanar
      IsSurfaceSingular
      IsSurfaceTrimmed
    """
    surface = rhutil.coercesurface(surface_id, True)
    return surface.IsPeriodic(direction)


def IsSurfacePlanar(surface_id, tolerance=None):
    """Verifies a surface object is planar
    Parameters:
      surface_id (guid): identifier of a surface
      tolerance (number): tolerance used when checked. If omitted, the current absolute
        tolerance is used
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfacePlanar(obj):
          print("The surface is planar.")
      else:
          print("The surface is not planar.")
    See Also:
      IsSurface
      IsSurfaceClosed
      IsSurfaceSingular
      IsSurfaceTrimmed
    """
    surface = rhutil.coercesurface(surface_id, True)
    if tolerance is None:
        tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    return surface.IsPlanar(tolerance)


def IsSurfaceRational(surface_id):
    """Verifies a surface object is rational
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfaceRational(obj):
          print("The surface is rational.")
      else:
          print("The surface is not rational.")
    See Also:
      IsSurface
      IsSurfaceClosed
      IsSurfacePlanar
      IsSurfaceTrimmed
    """
    surface = rhutil.coercesurface(surface_id, True)
    ns = surface.ToNurbsSurface()
    if ns is None: return False
    return ns.IsRational


def IsSurfaceSingular(surface_id, direction):
    """Verifies a surface object is singular in the specified direction.
    Surfaces are considered singular if a side collapses to a point.
    Parameters:
      surface_id (guid): the surface's identifier
      direction (number):
        0=south
        1=east
        2=north
        3=west
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfaceSingular(obj, 0):
          print("The surface is singular.")
      else:
          print("The surface is not singular.")
    See Also:
      IsSurface
      IsSurfaceClosed
      IsSurfacePlanar
      IsSurfaceTrimmed
    """
    surface = rhutil.coercesurface(surface_id, True)
    return surface.IsSingular(direction)


def IsSurfaceTrimmed(surface_id):
    """Verifies a surface object has been trimmed
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurfaceTrimmed(obj):
          print("The surface is trimmed.")
      else:
          print("The surface is not trimmed.")
    See Also:
      IsSurface
      IsSurfaceClosed
      IsSurfacePlanar
      IsSurfaceSingular
    """
    brep = rhutil.coercebrep(surface_id, True)
    return not brep.IsSurface


def IsTorus(surface_id):
    """Determines if a surface is a portion of a torus
    Parameters:
      surface_id (guid): the surface object's identifier
    Returns:
      bool: True if successful, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if surface:
          if rs.IsTorus(surface):
              print("The surface is a portion of a torus.")
          else:
              print("The surface is not a portion of a torus.")
    See Also:
      IsCone
      IsCylinder
      IsSphere
      IsSurface
    """
    surface = rhutil.coercesurface(surface_id, True)
    return surface.IsTorus()


def SurfaceSphere(surface_id):
    """Gets the sphere definition from a surface, if possible.
    Parameters:
      surface_id (guid): the identifier of the surface object
    Returns:
      (plane, number): The equatorial plane of the sphere, and its radius.
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if surface:
          result = rs.SurfaceSphere(surface)
          if result:
              print("The sphere radius is: " + str(result[1]))
    See Also:
      SurfaceCylinder
    """
    surface = rhutil.coercesurface(surface_id, True)
    tol = scriptcontext.doc.ModelAbsoluteTolerance
    is_sphere, sphere = surface.TryGetSphere(tol)
    rc = None
    if is_sphere: rc = (sphere.EquatorialPlane, sphere.Radius)
    return rc


def JoinSurfaces(object_ids, delete_input=False, return_all=False):
    """Joins two or more surface or polysurface objects together to form one
    polysurface object
    Parameters:
      object_ids ([guid, ...]) list of object identifiers
      delete_input (bool, optional): Delete the original surfaces
      return_all (bool, optional): Return all surfaces in result
    Returns:
      guid or guid list: identifier, or list of identifiers if return_all == True, of newly created object(s) on success
      None: on failure
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select surfaces in order", rs.filter.surface)
      if objs and len(objs)>1: rs.JoinSurfaces(objs)
    See Also:
      ExplodePolysurfaces
      IsPolysurface
      IsPolysurfaceClosed
      IsSurface
      IsSurfaceClosed
    """
    breps = [rhutil.coercebrep(id, True) for id in object_ids]
    if len(breps)<2: return scriptcontext.errorhandler()
    tol = scriptcontext.doc.ModelAbsoluteTolerance * 2.1
    joinedbreps = Rhino.Geometry.Brep.JoinBreps(breps, tol)
    if joinedbreps is None or (len(joinedbreps)!=1 and return_all == False):
        return scriptcontext.errorhandler()
    rc = []
    for brep in joinedbreps:
        id = scriptcontext.doc.Objects.AddBrep(brep)
        if id==System.Guid.Empty: return scriptcontext.errorhandler()
        rc.append(id)
    if delete_input:
        for id in object_ids:
            id = rhutil.coerceguid(id)
            scriptcontext.doc.Objects.Delete(id, True)
    scriptcontext.doc.Views.Redraw()
    return rc if return_all else rc[0]


def MakeSurfacePeriodic(surface_id, direction, delete_input=False):
    """Makes an existing surface a periodic NURBS surface
    Parameters:
      surface_id (guid): the surface's identifier
      direction (number): The direction to make periodic, either 0=U or 1=V
      delete_input (bool, optional): delete the input surface
    Returns:
      guid: if delete_input is False, identifier of the new surface
      guid: if delete_input is True, identifier of the modifier surface
      None: on error
    Example:
      import rhinoscriptsyntax as  rs
      obj = rs.GetObject("Select  a surface", rs.filter.surface)
      if not rs.IsSurfacePeriodic(obj,  0):
          rs.MakeSurfacePeriodic(obj,  0)
    See Also:
      IsSurfacePeriodic
    """
    surface = rhutil.coercesurface(surface_id, True)
    newsurf = Rhino.Geometry.Surface.CreatePeriodicSurface(surface, direction)
    if newsurf is None: return scriptcontext.errorhandler()
    id = rhutil.coerceguid(surface_id)
    if delete_input:
        scriptcontext.doc.Objects.Replace(id, newsurf)
    else:
        id = scriptcontext.doc.Objects.AddSurface(newsurf)
    scriptcontext.doc.Views.Redraw()
    return id


def OffsetSurface(surface_id, distance, tolerance=None, both_sides=False, create_solid=False):
    """Offsets a trimmed or untrimmed surface by a distance. The offset surface
    will be added to Rhino.
    Parameters:
      surface_id (guid): the surface's identifier
      distance (number): the distance to offset
      tolerance (number, optional): The offset tolerance. Use 0.0 to make a loose offset. Otherwise, the
        document's absolute tolerance is usually sufficient.
      both_sides (bool, optional): Offset to both sides of the input surface
      create_solid (bool, optional): Make a solid object
    Returns:
      guid: identifier of the new object if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurface(surface):
          rs.OffsetSurface( surface, 10.0 )
    See Also:
      OffsetCurve
    """
    brep = rhutil.coercebrep(surface_id, True)
    face = None
    if (1 == brep.Faces.Count): face = brep.Faces[0]
    if face is None: return scriptcontext.errorhandler()
    if tolerance is None: tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    newbrep = Rhino.Geometry.Brep.CreateFromOffsetFace(face, distance, tolerance, both_sides, create_solid)
    if newbrep is None: return scriptcontext.errorhandler()
    rc = scriptcontext.doc.Objects.AddBrep(newbrep)
    if rc==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return rc


def PullCurve(surface, curve, delete_input=False):
    """Pulls a curve object to a surface object
    Parameters:
      surface (guid): the surface's identifier
      curve (guid): the curve's identifier
      delete_input (bool, optional) should the input items be deleted
    Returns:
      list(guid, ...): of new curves if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.GetObject("Select curve to pull", rs.filter.curve )
      surface = rs.GetObject("Select surface that pulls", rs.filter.surface )
      rs.PullCurve(surface, curve)
    See Also:
      IsSurface
    """
    crvobj = rhutil.coercerhinoobject(curve, True, True)
    brep = rhutil.coercebrep(surface, True)
    curve = rhutil.coercecurve(curve, -1, True)
    tol = scriptcontext.doc.ModelAbsoluteTolerance
    curves = Rhino.Geometry.Curve.PullToBrepFace(curve, brep.Faces[0], tol)
    rc = [scriptcontext.doc.Objects.AddCurve(curve) for curve in curves]
    if rc:
        if delete_input and crvobj:
            scriptcontext.doc.Objects.Delete(crvobj, True)
        scriptcontext.doc.Views.Redraw()
        return rc


def RebuildSurface(object_id, degree=(3,3), pointcount=(10,10)):
    """Rebuilds a surface to a given degree and control point count. For more
    information see the Rhino help file for the Rebuild command
    Parameters:
      object_id (guid): the surface's identifier
      degree ([number, number], optional): two numbers that identify surface degree in both U and V directions
      pointcount ([number, number], optional): two numbers that identify the surface point count in both the U and V directions
    Returns:
      bool: True of False indicating success or failure
    Example:
    See Also:
    """
    surface = rhutil.coercesurface(object_id, True)
    newsurf = surface.Rebuild( degree[0], degree[1], pointcount[0], pointcount[1] )
    if newsurf is None: return False
    object_id = rhutil.coerceguid(object_id)
    rc = scriptcontext.doc.Objects.Replace(object_id, newsurf)
    if rc: scriptcontext.doc.Views.Redraw()
    return rc


def RemoveSurfaceKnot(surface, uv_parameter, v_direction):
    """Deletes a knot from a surface object.
    Parameters:
      surface (guid): The reference of the surface object
      uv_parameter (list(number, number)): An indexable item containing a U,V parameter on the surface. List, tuples and UVIntervals will work.
        Note, if the parameter is not equal to one of the existing knots, then the knot closest to the specified parameter will be removed.
      v_direction (bool): if True, or 1, the V direction will be addressed. If False, or 0, the U direction.
    Returns:
      bool: True of False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs

      srf_info = rs.GetSurfaceObject()
      if srf_info:
          srf_id = srf_info[0]
          srf_param = srf_info[4]
          rs.RemoveSurfaceKnot(srf_id, srf_param, 1)
    See Also:
      RemoveSurfaceKnot
    """
    srf_inst = rhutil.coercesurface(surface, True)
    u_param = uv_parameter[0]
    v_param = uv_parameter[1]
    success, n_u_param, n_v_param = srf_inst.GetSurfaceParameterFromNurbsFormParameter(u_param, v_param)
    if not success: return False
    n_srf = srf_inst.ToNurbsSurface()
    if not n_srf: return False
    knots = n_srf.KnotsV if v_direction else n_srf.KnotsU
    success = knots.RemoveKnotsAt(n_u_param, n_v_param)
    if not success: return False
    scriptcontext.doc.Objects.Replace(surface, n_srf)
    scriptcontext.doc.Views.Redraw()
    return True


def ReverseSurface(surface_id, direction):
    """Reverses U or V directions of a surface, or swaps (transposes) U and V
    directions.
    Parameters:
      surface_id (guid): identifier of a surface object
      direction (number): as a bit coded flag to swap
            1 = reverse U
            2 = reverse V
            4 = transpose U and V (values can be combined)
    Returns:
      bool: indicating success or failure
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface to reverse")
      if rs.IsSurface(obj):
          rs.ReverseSurface( obj, 1 )
    See Also:
      FlipSurface
      IsSurface
    """
    brep = rhutil.coercebrep(surface_id, True)
    if not brep.Faces.Count==1: return scriptcontext.errorhandler()
    face = brep.Faces[0]
    if direction & 1:
        face.Reverse(0, True)
    if direction & 2:
        face.Reverse(1, True)
    if direction & 4:
        face.Transpose(True)
    scriptcontext.doc.Objects.Replace(surface_id, brep)
    scriptcontext.doc.Views.Redraw()
    return True


def ShootRay(surface_ids, start_point, direction, reflections=10):
    """Shoots a ray at a collection of surfaces
    Parameters:
      surface_ids ([guid, ...]): one of more surface identifiers
      start_point (point): starting point of the ray
      direction (vector):  vector identifying the direction of the ray
      reflections (number, optional): the maximum number of times the ray will be reflected
    Returns:
      list(point, ...): of reflection points on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      def TestRayShooter():
          corners = []
          corners.append((0,0,0))
          corners.append((10,0,0))
          corners.append((10,10,0))
          corners.append((0,10,0))
          corners.append((0,0,10))
          corners.append((10,0,10))
          corners.append((10,10,10))
          corners.append((0,10,10))
          box = rs.AddBox(corners)
          dir = 10,7.5,7
          reflections = rs.ShootRay(box, (0,0,0), dir)
          rs.AddPolyline( reflections )
          rs.AddPoints( reflections )
      TestRayShooter()
    See Also:
      IsPolysurface
      IsSurface
    """
    start_point = rhutil.coerce3dpoint(start_point, True)
    direction = rhutil.coerce3dvector(direction, True)
    id = rhutil.coerceguid(surface_ids, False)
    if id: surface_ids = [id]
    ray = Rhino.Geometry.Ray3d(start_point, direction)
    breps = []
    for id in surface_ids:
        brep = rhutil.coercebrep(id)
        if brep: breps.append(brep)
        else:
            surface = rhutil.coercesurface(id, True)
            breps.append(surface)
    if not breps: return scriptcontext.errorhandler()
    points = Rhino.Geometry.Intersect.Intersection.RayShoot(ray, breps, reflections)
    if points:
        rc = []
        rc.append(start_point)
        rc = rc + list(points)
        return rc
    return scriptcontext.errorhandler()


def ShortPath(surface_id, start_point, end_point):
    """Creates the shortest possible curve(geodesic) between two points on a
    surface. For more details, see the ShortPath command in Rhino help
    Parameters:
      surface_id (guid): identifier of a surface
      start_point, end_point (point): start/end points of the short curve
    Returns:
      guid: identifier of the new surface on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface for short path", rs.filter.surface + rs.filter.surface)
      if surface:
          start = rs.GetPointOnSurface(surface, "First point")
          end = rs.GetPointOnSurface(surface, "Second point")
          rs.ShortPath(surface, start, end)
    See Also:
      EvaluateSurface
      SurfaceClosestPoint
    """
    surface = rhutil.coercesurface(surface_id, True)
    start = rhutil.coerce3dpoint(start_point, True)
    end = rhutil.coerce3dpoint(end_point, True)
    rc_start, u_start, v_start = surface.ClosestPoint(start)
    rc_end, u_end, v_end = surface.ClosestPoint(end)
    if not rc_start or not rc_end: return scriptcontext.errorhandler()
    start = Rhino.Geometry.Point2d(u_start, v_start)
    end = Rhino.Geometry.Point2d(u_end, v_end)
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    curve = surface.ShortPath(start, end, tolerance)
    if curve is None: return scriptcontext.errorhandler()
    id = scriptcontext.doc.Objects.AddCurve(curve)
    if id==System.Guid.Empty: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return id


def ShrinkTrimmedSurface(object_id, create_copy=False):
    """Shrinks the underlying untrimmed surfaces near to the trimming
    boundaries. See the ShrinkTrimmedSrf command in the Rhino help.
    Parameters:
      object_id (guid): the surface's identifier
      create_copy (bool, optional): If True, the original surface is not deleted
    Returns:
      bool: If create_copy is False, True or False indicating success or failure
      bool: If create_copy is True, the identifier of the new surface
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      filter = rs.filter.surface | rs.filter.polysurface
      surface = rs.GetObject("Select surface or polysurface to shrink", filter )
      if surface: rs.ShrinkTrimmedSurface( surface )
    See Also:
      IsSurfaceTrimmed
    """
    brep = rhutil.coercebrep(object_id, True)
    if not brep.Faces.ShrinkFaces(): return scriptcontext.errorhandler()
    rc = None
    object_id = rhutil.coerceguid(object_id)
    if create_copy:
        oldobj = scriptcontext.doc.Objects.Find(object_id)
        attr = oldobj.Attributes
        rc = scriptcontext.doc.Objects.AddBrep(brep, attr)
    else:
        rc = scriptcontext.doc.Objects.Replace(object_id, brep)
    scriptcontext.doc.Views.Redraw()
    return rc


def __GetMassProperties(object_id, area):
    surface = rhutil.coercebrep(object_id)
    if surface is None:
        surface = rhutil.coercesurface(object_id)
        if surface is None: return None
    if area==True: return Rhino.Geometry.AreaMassProperties.Compute(surface)
    if not surface.IsSolid: return None
    return Rhino.Geometry.VolumeMassProperties.Compute(surface)


def SplitBrep(brep_id, cutter_id, delete_input=False):
    """Splits a brep
    Parameters:
      brep (guid): identifier of the brep to split
      cutter (guid): identifier of the brep to split with
    Returns:
      list(guid, ...): identifiers of split pieces on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      filter = rs.filter.surface + rs.filter.polysurface
      brep = rs.GetObject("Select brep to split", filter)
      cutter = rs.GetObject("Select cutting brep", filter)
      rs.SplitBrep ( brep, cutter )
    See Also:
      IsBrep
    """
    brep = rhutil.coercebrep(brep_id, True)
    cutter = rhutil.coercebrep(cutter_id, True)
    tol = scriptcontext.doc.ModelAbsoluteTolerance
    pieces = brep.Split(cutter, tol)
    if not pieces: return scriptcontext.errorhandler()
    if delete_input:
        brep_id = rhutil.coerceguid(brep_id)
        scriptcontext.doc.Objects.Delete(brep_id, True)
    rc = [scriptcontext.doc.Objects.AddBrep(piece) for piece in pieces]
    scriptcontext.doc.Views.Redraw()
    return rc


def SurfaceArea(object_id):
    """Calculate the area of a surface or polysurface object. The results are
    based on the current drawing units
    Parameters:
      object_id (guid): the surface's identifier
    Returns:
      list(number, number): of area information on success (area, absolute error bound)
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if obj:
          massprop = rs.SurfaceArea( obj )
          if massprop:
              print("The surface area is: {}".format(massprop[0]))
    See Also:
      SurfaceAreaCentroid
      SurfaceAreaMoments
    """
    amp = __GetMassProperties(object_id, True)
    if amp: return amp.Area, amp.AreaError


def SurfaceAreaCentroid(object_id):
    """Calculates the area centroid of a surface or polysurface
    Parameters:
      object_id (guid): the surface's identifier
    Returns:
      list(point, tuple(number, number, number)): Area centroid information (Area Centroid, Error bound in X, Y, Z)
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if obj:
          massprop = rs.SurfaceAreaCentroid(obj)
          if massprop: rs.AddPoint( massprop[0] )
    See Also:
      SurfaceArea
      SurfaceAreaMoments
    """
    amp = __GetMassProperties(object_id, True)
    if amp is None: return scriptcontext.errorhandler()
    return amp.Centroid, amp.CentroidError


def __AreaMomentsHelper(surface_id, area):
    mp = __GetMassProperties(surface_id, area)
    if mp is None: return scriptcontext.errorhandler()
    a = (mp.WorldCoordinatesFirstMoments.X, mp.WorldCoordinatesFirstMoments.Y, mp.WorldCoordinatesFirstMoments.Z)
    b = (mp.WorldCoordinatesFirstMomentsError.X, mp.WorldCoordinatesFirstMomentsError.Y, mp.WorldCoordinatesFirstMomentsError.Z)
    c = (mp.WorldCoordinatesSecondMoments.X, mp.WorldCoordinatesSecondMoments.Y, mp.WorldCoordinatesSecondMoments.Z)
    d = (mp.WorldCoordinatesSecondMomentsError.X, mp.WorldCoordinatesSecondMomentsError.Y, mp.WorldCoordinatesSecondMomentsError.Z)
    e = (mp.WorldCoordinatesProductMoments.X, mp.WorldCoordinatesProductMoments.Y, mp.WorldCoordinatesProductMoments.Z)
    f = (mp.WorldCoordinatesProductMomentsError.X, mp.WorldCoordinatesProductMomentsError.Y, mp.WorldCoordinatesProductMomentsError.Z)
    g = (mp.WorldCoordinatesMomentsOfInertia.X, mp.WorldCoordinatesMomentsOfInertia.Y, mp.WorldCoordinatesMomentsOfInertia.Z)
    h = (mp.WorldCoordinatesMomentsOfInertiaError.X, mp.WorldCoordinatesMomentsOfInertiaError.Y, mp.WorldCoordinatesMomentsOfInertiaError.Z)
    i = (mp.WorldCoordinatesRadiiOfGyration.X, mp.WorldCoordinatesRadiiOfGyration.Y, mp.WorldCoordinatesRadiiOfGyration.Z)
    j = (0,0,0) # need to add error calc to RhinoCommon
    k = (mp.CentroidCoordinatesMomentsOfInertia.X, mp.CentroidCoordinatesMomentsOfInertia.Y, mp.CentroidCoordinatesMomentsOfInertia.Z)
    l = (mp.CentroidCoordinatesMomentsOfInertiaError.X, mp.CentroidCoordinatesMomentsOfInertiaError.Y, mp.CentroidCoordinatesMomentsOfInertiaError.Z)
    m = (mp.CentroidCoordinatesRadiiOfGyration.X, mp.CentroidCoordinatesRadiiOfGyration.Y, mp.CentroidCoordinatesRadiiOfGyration.Z)
    n = (0,0,0) #need to add error calc to RhinoCommon
    return (a,b,c,d,e,f,g,h,i,j,k,l,m,n)


def SurfaceAreaMoments(surface_id):
    """Calculates area moments of inertia of a surface or polysurface object.
    See the Rhino help for "Mass Properties calculation details"
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      list(tuple(number, number,number), ...): of moments and error bounds in tuple(X, Y, Z) - see help topic
        Index   Description
        [0]     First Moments.
        [1]     The absolute (+/-) error bound for the First Moments.
        [2]     Second Moments.
        [3]     The absolute (+/-) error bound for the Second Moments.
        [4]     Product Moments.
        [5]     The absolute (+/-) error bound for the Product Moments.
        [6]     Area Moments of Inertia about the World Coordinate Axes.
        [7]     The absolute (+/-) error bound for the Area Moments of Inertia about World Coordinate Axes.
        [8]     Area Radii of Gyration about the World Coordinate Axes.
        [9]     The absolute (+/-) error bound for the Area Radii of Gyration about World Coordinate Axes.
        [10]    Area Moments of Inertia about the Centroid Coordinate Axes.
        [11]    The absolute (+/-) error bound for the Area Moments of Inertia about the Centroid Coordinate Axes.
        [12]    Area Radii of Gyration about the Centroid Coordinate Axes.
        [13]    The absolute (+/-) error bound for the Area Radii of Gyration about the Centroid Coordinate Axes.
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if obj:
          massprop= rs.SurfaceAreaMoments(obj)
          if massprop:
              print("Area Moments of Inertia about the World Coordinate Axes: {}".format(massprop[6]))
    See Also:
      SurfaceArea
      SurfaceAreaCentroid
    """
    return __AreaMomentsHelper(surface_id, True)


def SurfaceClosestPoint(surface_id, test_point):
    """Returns U,V parameters of point on a surface that is closest to a test point
    Parameters:
      surface_id (guid): identifier of a surface object
      test_point (point): sampling point
    Returns:
      list(number, number): The U,V parameters of the closest point on the surface if successful.
      None: on error.
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurface(obj):
          point = rs.GetPointOnSurface(obj, "Pick a test point")
          if point:
              param = rs.SurfaceClosestPoint(obj, point)
              if param:
                  print("Surface U parameter: {}".format(str(param[0])))
                  print("Surface V parameter: {}".format(str(param[1])))
    See Also:
      BrepClosestPoint
      EvaluateSurface
      IsSurface
    """
    surface = rhutil.coercesurface(surface_id, True)
    point = rhutil.coerce3dpoint(test_point, True)
    rc, u, v = surface.ClosestPoint(point)
    if not rc: return None
    return u,v


def SurfaceCone(surface_id):
    """Returns the definition of a surface cone
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      tuple(plane, number, number): containing the definition of the cone if successful
        [0]   the plane of the cone. The apex of the cone is at the
              plane's origin and the axis of the cone is the plane's z-axis
        [1]   the height of the cone
        [2]   the radius of the cone
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      cone = rs.AddCone(rs.WorldXYPlane(), 6, 2, False)
      if rs.IsCone(cone):
          cone_def = rs.SurfaceCone(cone)
          rs.AddCone( cone_def[0], cone_def[1], cone_def[2], False )
    See Also:
      
    """
    surface = rhutil.coercesurface(surface_id, True)
    rc, cone = surface.TryGetCone()
    if not rc: return scriptcontext.errorhandler()
    return cone.Plane, cone.Height, cone.Radius


def SurfaceCurvature(surface_id, parameter):
    """Returns the curvature of a surface at a U,V parameter. See Rhino help
    for details of surface curvature
    Parameters:
      surface_id (guid): the surface's identifier
      parameter (number, number): u,v parameter
    Returns:
      tuple(point, vector, number, number, number, number, number): of curvature information
        [0]   point at specified U,V parameter
        [1]   normal direction
        [2]   maximum principal curvature
        [3]   maximum principal curvature direction
        [4]   minimum principal curvature
        [5]   minimum principal curvature direction
        [6]   gaussian curvature
        [7]   mean curvature
      None: if not successful, or on error
    Example:
      import rhinoscriptsyntax as rs
      srf = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurface(srf):
          point = rs.GetPointOnSurface(srf, "Pick a test point")
          if point:
              param = rs.SurfaceClosestPoint(srf, point)
              if param:
                  data = rs.SurfaceCurvature(srf, param)
                  if data:
                      print("Surface curvature evaluation at parameter {}:".format(param))
                      print(" 3-D Point:{}".format(data[0]))
                      print(" 3-D Normal:{}".format(data[1]))
                      print(" Maximum principal curvature: {} {}".format(data[2], data[3]))
                      print(" Minimum principal curvature: {} {}".format(data[4], data[5]))
                      print(" Gaussian curvature:{}".format(data[6]))
                      print(" Mean curvature:{}".format(data[7]))
    See Also:
      CurveCurvature
    """
    surface = rhutil.coercesurface(surface_id, True)
    if len(parameter)<2: return scriptcontext.errorhandler()
    c = surface.CurvatureAt(parameter[0], parameter[1])
    if c is None: return scriptcontext.errorhandler()
    return c.Point, c.Normal, c.Kappa(0), c.Direction(0), c.Kappa(1), c.Direction(1), c.Gaussian, c.Mean


def SurfaceCylinder(surface_id):
    """Returns the definition of a cylinder surface
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      tuple(plane, number, number): of the cylinder plane, height, radius on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      cylinder = rs.AddCylinder(rs.WorldXYPlane(), 6, 2, False)
      if rs.IsCylinder(cylinder):
          plane, height, radius = rs.SurfaceCylinder(cylinder)
          rs.AddCylinder(plane, height, radius, False)
    See Also:
      SurfaceSphere
    """
    surface = rhutil.coercesurface(surface_id, True)
    tol = scriptcontext.doc.ModelAbsoluteTolerance
    rc, cylinder = surface.TryGetFiniteCylinder(tol)
    if rc:
        return cylinder.BasePlane, cylinder.TotalHeight, cylinder.Radius


def SurfaceDegree(surface_id, direction=2):
    """Returns the degree of a surface object in the specified direction
    Parameters:
      surface_id (guid): the surface's identifier
      direction (number, optional): The degree U, V direction
                0 = U
                1 = V
                2 = both
    Returns:
      number: Single number if `direction` = 0 or 1
      tuple(number, number): of two values if `direction` = 2
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurface(obj):
          print("Degree in U direction: {}".format(rs.SurfaceDegree(obj, 0)))
          print("Degree in V direction: {}".format(rs.SurfaceDegree(obj, 1)))
    See Also:
      IsSurface
      SurfaceDomain
    """
    surface = rhutil.coercesurface(surface_id, True)
    if direction==0 or direction==1: return surface.Degree(direction)
    if direction==2: return surface.Degree(0), surface.Degree(1)
    return scriptcontext.errorhandler()


def SurfaceDomain(surface_id, direction):
    """Returns the domain of a surface object in the specified direction.
    Parameters:
      surface_id (guid): the surface's identifier
      direction (number): domain direction 0 = U, or 1 = V
    Returns:
      list(number, number): containing the domain interval in the specified direction
      None: if not successful, or on error
    Example:
      import rhinoscriptsyntax as rs
      object = rs.GetObject("Select a surface", rs.filter.surface)
      if rs.IsSurface(object):
          domainU = rs.SurfaceDomain(object, 0)
          domainV = rs.SurfaceDomain(object, 1)
          print("Domain in U direction: {}".format(domainU))
          print("Domain in V direction: {}".format(domainV))
    See Also:
      IsSurface
      SurfaceDegree
    """
    if direction!=0 and direction!=1: return scriptcontext.errorhandler()
    surface = rhutil.coercesurface(surface_id, True)
    domain = surface.Domain(direction)
    return domain.T0, domain.T1


def SurfaceEditPoints(surface_id, return_parameters=False, return_all=True):
    """Returns the edit, or Greville points of a surface object. For each
    surface control point, there is a corresponding edit point
    Parameters:
      surface_id (guid): the surface's identifier
      return_parameters (bool, optional): If False, edit points are returned as a list of
        3D points. If True, edit points are returned as a list of U,V surface
        parameters
      return_all (bool, options): If True, all surface edit points are returned. If False,
        the function will return surface edit points based on whether or not the
        surface is closed or periodic
    Returns:
      list(point, ...): if return_parameters is False, a list of 3D points
      list((number, number), ...): if return_parameters is True, a list of U,V parameters
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface")
      if rs.IsSurface(obj):
          points = rs.SurfaceEditPoints(obj)
          if points: rs.AddPointCloud(points)
    See Also:
      IsSurface
      SurfacePointCount
      SurfacePoints
    """
    surface = rhutil.coercesurface(surface_id, True)
    nurb = surface.ToNurbsSurface()
    if not nurb: return scriptcontext.errorhandler()
    ufirst = 0
    ulast = nurb.Points.CountU
    vfirst = 0
    vlast = nurb.Points.CountV
    if not return_all:
        if nurb.IsClosed(0): ulast = nurb.Points.CountU-1
        if nurb.IsPeriodic(0):
            degree = nurb.Degree(0)
            ufirst = degree/2
            ulast = nurb.Points.CountU-degree+ufirst
        if nurb.IsClosed(1): vlast = nurb.Points.CountV-1
        if nurb.IsPeriodic(1):
            degree = nurb.Degree(1)
            vfirst = degree/2
            vlast = nurb.Points.CountV-degree+vfirst
    rc = []
    for u in range(ufirst, ulast):
        for v in range(vfirst, vlast):
            pt = nurb.Points.GetGrevillePoint(u,v)
            if not return_parameters: pt = nurb.PointAt(pt.X, pt.Y)
            rc.append(pt)
    return rc


def SurfaceEvaluate(surface_id, parameter, derivative):
    """A general purpose surface evaluator
    Parameters:
      surface_id (guid): the surface's identifier
      parameter ([number, number]): u,v parameter to evaluate
      derivative (number): number of derivatives to evaluate
    Returns:
      list((point, vector, ...), ...): list length (derivative+1)*(derivative+2)/2 if successful.  The elements are as follows:
      Element  Description
      [0]      The 3-D point.
      [1]      The first derivative.
      [2]      The first derivative.
      [3]      The second derivative.
      [4]      The second derivative.
      [5]      The second derivative.
      [6]      etc...
    None: If not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      def TestSurfaceEvaluate():
          srf = rs.GetObject("Select surface to evaluate", rs.filter.surface, True)
          if srf is None: return
          point = rs.GetPointOnSurface(srf, "Point to evaluate")
          if point is None: return
          der = rs.GetInteger("Number of derivatives to evaluate", 1, 1)
          if der is None: return
          uv = rs.SurfaceClosestPoint(srf, point)
          res = rs.SurfaceEvaluate(srf, uv, der)
          if res is None:
              print("Failed to evaluate surface.")
              return
          for i,r in enumerate(res):
              print("{} = {}".format(i, r))
      TestSurfaceEvaluate()
    See Also:
      EvaluateSurface
    """
    surface = rhutil.coercesurface(surface_id, True)
    success, point, der = surface.Evaluate(parameter[0], parameter[1], derivative)
    if not success: return scriptcontext.errorhandler()
    rc = [point]
    if der:
      for d in der: rc.append(d)
    return rc


def SurfaceFrame(surface_id, uv_parameter):
    """Returns a plane based on the normal, u, and v directions at a surface
    U,V parameter
    Parameters:
      surface_id (guid): the surface's identifier
      uv_parameter ([number, number]): u,v parameter to evaluate
    Returns:
      plane: plane on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetSurfaceObject("Select a surface")
      if surface:
          plane = rs.SurfaceFrame(surface[0], surface[4])
          rs.ViewCPlane(None, plane)
    See Also:
      EvaluateSurface
      SurfaceClosestPoint
      SurfaceNormal
    """
    surface = rhutil.coercesurface(surface_id, True)
    rc, frame = surface.FrameAt(uv_parameter[0], uv_parameter[1])
    if rc: return frame


def SurfaceIsocurveDensity(surface_id, density=None):
    """Returns or sets the isocurve density of a surface or polysurface object.
    An isoparametric curve is a curve of constant U or V value on a surface.
    Rhino uses isocurves and surface edge curves to visualize the shape of a
    NURBS surface
    Parameters:
      surface_id (guid): the surface's identifier
      density (number, optional): the isocurve wireframe density. The possible values are
          -1: Hides the surface isocurves
           0: Display boundary and knot wires
           1: Display boundary and knot wires and one interior wire if there
              are no interior knots
         >=2: Display boundary and knot wires and (N+1) interior wires
    Returns:
      number: If density is not specified, then the current isocurve density if successful
      number: If density is specified, the the previous isocurve density if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface | rs.filter.polysurface)
      if obj: rs.SurfaceIsocurveDensity( obj, 8 )
    See Also:
      IsPolysurface
      IsSurface
    """
    rhino_object = rhutil.coercerhinoobject(surface_id, True, True)
    if not isinstance(rhino_object, Rhino.DocObjects.BrepObject):
        return scriptcontext.errorhandler()
    rc = rhino_object.Attributes.WireDensity
    if density is not None:
        if density<0: density = -1
        rhino_object.Attributes.WireDensity = density
        rhino_object.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def SurfaceKnotCount(surface_id):
    """Returns the control point count of a surface
      surface_id = the surface's identifier
    Parameters:
      surface_id (guid): the surface object's identifier
    Returns:
      list(number, number): a list containing (U count, V count) on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface")
      if rs.IsSurface(obj):
          count = rs.SurfaceKnotCount(obj)
          print("Knot count in U direction: {}".format(count[0]))
          print("Knot count in V direction: {}".format(count[1]))
    See Also:
      IsSurface
      SurfaceKnots
    """
    surface = rhutil.coercesurface(surface_id, True)
    ns = surface.ToNurbsSurface()
    return ns.KnotsU.Count, ns.KnotsV.Count


def SurfaceKnots(surface_id):
    """Returns the knots, or knot vector, of a surface object.
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
     list(number, number): knot values of the surface if successful. The list will
      contain the following information:
      Element   Description
        [0]     Knot vector in U direction
        [1]     Knot vector in V direction
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface")
      if rs.IsSurface(obj):
          knots = rs.SurfaceKnots(obj)
          if knots:
              vector = knots[0]
              print("Knot vector in U direction")
              for item in vector: print("Surface knot value: {}".format(item))
              vector = knots[1]
              print("Knot vector in V direction")
              for item in vector: print("Surface knot value: {}".format(item))
    See Also:
      IsSurface
      SurfaceKnotCount
    """
    surface = rhutil.coercesurface(surface_id, True)
    nurb_surf = surface.ToNurbsSurface()
    if nurb_surf is None: return scriptcontext.errorhandler()
    s_knots = [knot for knot in nurb_surf.KnotsU]
    t_knots = [knot for knot in nurb_surf.KnotsV]
    if not s_knots or not t_knots: return scriptcontext.errorhandler()
    return s_knots, t_knots


def SurfaceNormal(surface_id, uv_parameter):
    """Returns 3D vector that is the normal to a surface at a parameter
    Parameters:
      surface_id (guid): the surface's identifier
      uv_parameter  ([number, number]): the uv parameter to evaluate
    Returns:
      vector: Normal vector on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.surface)
      if obj:
          point = rs.GetPointOnSurface(obj)
          if point:
              param = rs.SurfaceClosestPoint(obj, point)
              normal = rs.SurfaceNormal(obj, param)
              rs.AddPoints( [point, point + normal] )
    See Also:
      SurfaceClosestPoint
      SurfaceDomain
    """
    surface = rhutil.coercesurface(surface_id, True)
    return surface.NormalAt(uv_parameter[0], uv_parameter[1])


def SurfaceNormalizedParameter(surface_id, parameter):
    """Converts surface parameter to a normalized surface parameter; one that
    ranges between 0.0 and 1.0 in both the U and V directions
    Parameters:
      surface_id (guid) the surface's identifier
      parameter ([number, number]): the surface parameter to convert
    Returns:
      list(number, number): normalized surface parameter if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select surface")
      if rs.IsSurface(obj):
          domain_u = rs.SurfaceDomain(obj, 0)
          domain_v = rs.SurfaceDomain(obj, 1)
          parameter = (domain_u[1] + domain_u[0]) / 2.0, (domain_v[1] + domain_v[0]) / 2.0
          print("Surface parameter: {}".format(parameter))
          normalized = rs.SurfaceNormalizedParameter(obj, parameter)
          print("Normalized parameter: {}".format(normalized))
    See Also:
      SurfaceDomain
      SurfaceParameter
    """
    surface = rhutil.coercesurface(surface_id, True)
    u_domain = surface.Domain(0)
    v_domain = surface.Domain(1)
    if parameter[0]<u_domain.Min or parameter[0]>u_domain.Max:
        return scriptcontext.errorhandler()
    if parameter[1]<v_domain.Min or parameter[1]>v_domain.Max:
        return scriptcontext.errorhandler()
    u = u_domain.NormalizedParameterAt(parameter[0])
    v = v_domain.NormalizedParameterAt(parameter[1])
    return u,v


def SurfaceParameter(surface_id, parameter):
    """Converts normalized surface parameter to a surface parameter; or
    within the surface's domain
    Parameters:
      surface_id (guid): the surface's identifier
      parameter ([number, number]): the normalized parameter to convert
    Returns:
      tuple(number, number): surface parameter on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select surface")
      if obj:
          normalized = (0.5, 0.5)
          print("Normalized parameter: {}".format(normalized))
          parameter = rs.SurfaceParameter(obj, normalized)
          print("Surface parameter: {}".format(parameter))
    See Also:
      SurfaceDomain
      SurfaceNormalizedParameter
    """
    surface = rhutil.coercesurface(surface_id, True)
    x = surface.Domain(0).ParameterAt(parameter[0])
    y = surface.Domain(1).ParameterAt(parameter[1])
    return x, y


def SurfacePointCount(surface_id):
    """Returns the control point count of a surface
      surface_id = the surface's identifier
    Parameters:
      surface_id (guid): the surface object's identifier
    Returns:
      list(number, number): THe number of control points in UV direction. (U count, V count)
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface")
      if rs.IsSurface(obj):
          count = rs.SurfacePointCount(obj)
          print("Point count in U direction: {}".format(count[0]))
          print("Point count in V direction: {}".format(count[1]))
    See Also:
      IsSurface
      SurfacePoints
    """
    surface = rhutil.coercesurface(surface_id, True)
    ns = surface.ToNurbsSurface()
    return ns.Points.CountU, ns.Points.CountV


def SurfacePoints(surface_id, return_all=True):
    """Returns the control points, or control vertices, of a surface object
    Parameters:
      surface_id (guid): the surface's identifier
      return_all (bool, optional): If True all surface edit points are returned. If False,
        the function will return surface edit points based on whether or not
        the surface is closed or periodic
    Returns:
      list(point, ...): the control points if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      def PrintControlPoints():
          surface = rs.GetObject("Select surface", rs.filter.surface)
          points = rs.SurfacePoints(surface)
          if points is None: return
          count = rs.SurfacePointCount(surface)
          i = 0
          for u in range(count[0]):
              for v in range(count[1]):
                  print("CV[{}".format(u, ",", v, "] = ", points[i]))
                  i += 1
      PrintControlPoints()
    See Also:
      IsSurface
      SurfacePointCount
    """
    surface = rhutil.coercesurface(surface_id, True)
    ns = surface.ToNurbsSurface()
    if ns is None: return scriptcontext.errorhandler()
    rc = []
    for u in range(ns.Points.CountU):
        for v in range(ns.Points.CountV):
            pt = ns.Points.GetControlPoint(u,v)
            rc.append(pt.Location)
    return rc


def SurfaceTorus(surface_id):
    """Returns the definition of a surface torus
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      tuple(plane, number, number): containing the definition of the torus if successful
        [0]   the base plane of the torus
        [1]   the major radius of the torus
        [2]   the minor radius of the torus
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      torus = rs.AddTorus(rs.WorldXYPlane(), 6, 2)
      if rs.IsTorus(torus):
          torus_def = rs.SurfaceTorus(torus)
          rs.AddTorus( torus_def[0], torus_def[1], torus_def[2] )
    See Also:
      
    """
    surface = rhutil.coercesurface(surface_id, True)
    rc, torus = surface.TryGetTorus()
    if rc: return torus.Plane, torus.MajorRadius, torus.MinorRadius


def SurfaceVolume(object_id):
    """Calculates volume of a closed surface or polysurface
    Parameters:
      object_id (guid): the surface's identifier
    Returns:
      list(number, tuple(X, Y, Z): volume data returned (Volume, Error bound) on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.polysurface)
      if rs.IsPolysurfaceClosed(obj):
          massprop = rs.SurfaceVolume(obj)
          if massprop:
              print("The polysurface volume is: {}".format(massprop[0]))
    See Also:
      SurfaceVolume
      SurfaceVolumeCentroid
      SurfaceVolumeMoments
    """
    vmp = __GetMassProperties(object_id, False)
    if vmp: return vmp.Volume, vmp.VolumeError


def SurfaceVolumeCentroid(object_id):
    """Calculates volume centroid of a closed surface or polysurface
    Parameters:
      object_id (guid): the surface's identifier
    Returns:
      list(point, tuple(X, Y, Z): volume data returned (Volume Centriod, Error bound) on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.polysurface)
      if rs.IsPolysurfaceClosed(obj):
          massprop= rs.SurfaceVolumeCentroid(obj)
          if massprop: rs.AddPoint( massprop[0] )
    See Also:
      SurfaceVolume
      SurfaceVolumeMoments
    """
    vmp = __GetMassProperties(object_id, False)
    if vmp: return vmp.Centroid, vmp.CentroidError


def SurfaceVolumeMoments(surface_id):
    """Calculates volume moments of inertia of a surface or polysurface object.
    For more information, see Rhino help for "Mass Properties calculation details"
    Parameters:
      surface_id (guid): the surface's identifier
    Returns:
      list(tuple(number, number,number), ...): of moments and error bounds in tuple(X, Y, Z) - see help topic
        Index   Description
        [0]     First Moments.
        [1]     The absolute (+/-) error bound for the First Moments.
        [2]     Second Moments.
        [3]     The absolute (+/-) error bound for the Second Moments.
        [4]     Product Moments.
        [5]     The absolute (+/-) error bound for the Product Moments.
        [6]     Area Moments of Inertia about the World Coordinate Axes.
        [7]     The absolute (+/-) error bound for the Area Moments of Inertia about World Coordinate Axes.
        [8]     Area Radii of Gyration about the World Coordinate Axes.
        [9]     The absolute (+/-) error bound for the Area Radii of Gyration about World Coordinate Axes.
        [10]    Area Moments of Inertia about the Centroid Coordinate Axes.
        [11]    The absolute (+/-) error bound for the Area Moments of Inertia about the Centroid Coordinate Axes.
        [12]    Area Radii of Gyration about the Centroid Coordinate Axes.
        [13]    The absolute (+/-) error bound for the Area Radii of Gyration about the Centroid Coordinate Axes.
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select a surface", rs.filter.polysurface)
      if rs.IsPolysurfaceClosed(obj):
          massprop = rs.SurfaceVolumeMoments(obj)
          if massprop:
              print("Volume Moments of Inertia about the World Coordinate Axes: {}".format(massprop[6]))
    See Also:
      SurfaceVolume
      SurfaceVolumeCentroid
    """
    return __AreaMomentsHelper(surface_id, False)


def SurfaceWeights(object_id):
    """Returns list of weight values assigned to the control points of a surface.
    The number of weights returned will be equal to the number of control points
    in the U and V directions.
    Parameters:
      object_id (guid): the surface's identifier
    Returns:
      list(number, ...): point weights.
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      surf = rs.GetObject("Select a surface")
      if rs.IsSurface(surf):
          weights = rs.SurfaceWeights(surf)
          if weights:
              for w in weights:
                  print("Surface control point weight value:{}".format(w))
    See Also:
      IsSurface
      SurfacePointCount
      SurfacePoints
    """
    surface = rhutil.coercesurface(object_id, True)
    ns = surface.ToNurbsSurface()
    if ns is None: return scriptcontext.errorhandler()
    rc = []
    for u in range(ns.Points.CountU):
        for v in range(ns.Points.CountV):
            pt = ns.Points.GetControlPoint(u,v)
            rc.append(pt.Weight)
    return rc


def TrimBrep(object_id, cutter, tolerance=None):
    """Trims a surface using an oriented cutter
    Parameters:
      object_id (guid): surface or polysurface identifier
      cutter (guid|plane): surface, polysurface, or plane performing the trim
      tolerance (number, optional): trimming tolerance. If omitted, the document's absolute
        tolerance is used
    Returns:
      list(guid, ...): identifiers of retained components on success
    Example:
      import rhinoscriptsyntax as rs
      filter = rs.filter.surface + rs.filter.polysurface
      obj = rs.GetObject("Select surface or polysurface to trim", filter)
      if obj:
          cutter = rs.GetObject("Select cutting surface or polysurface", filter)
          if cutter:
              rs.TrimBrep(obj,cutter)
    See Also:
      TrimSurface
    """
    brep = rhutil.coercebrep(object_id, True)
    brep_cutter = rhutil.coercebrep(cutter, False)
    if brep_cutter: cutter = brep_cutter
    else: cutter = rhutil.coerceplane(cutter, True)
    if tolerance is None: tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    breps = brep.Trim(cutter, tolerance)
    rhid = rhutil.coerceguid(object_id, False)

    attrs = None
    if len(breps) > 1:
      rho = rhutil.coercerhinoobject(object_id, False)
      if rho: attrs = rho.Attributes

    if rhid:
        rc = []
        for i in range(len(breps)):
            if i==0:
                scriptcontext.doc.Objects.Replace(rhid, breps[i])
                rc.append(rhid)
            else:
                rc.append(scriptcontext.doc.Objects.AddBrep(breps[i], attrs))
    else:
        rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
    scriptcontext.doc.Views.Redraw()
    return rc


def TrimSurface( surface_id, direction, interval, delete_input=False):
    """Remove portions of the surface outside of the specified interval
    Parameters:
      surface_id (guid): surface identifier
      direction (number, optional): 0(U), 1(V), or 2(U and V)
      interval (interval): sub section of the surface to keep.
        If both U and V then a list or tuple of 2 intervals
      delete_input (bool, optional): should the input surface be deleted
    Returns:
      guid: new surface identifier on success
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface to split", rs.filter.surface)
      if surface:
          domain_u = rs.SurfaceDomain(surface, 0)
          domain_u[0] = (domain_u[1] - domain_u[0]) * 0.25
          rs.TrimSurface( surface, 0, domain_u, True )
    See Also:
      
    """
    surface = rhutil.coercesurface(surface_id, True)
    u = surface.Domain(0)
    v = surface.Domain(1)
    if direction==0:
        u[0] = interval[0]
        u[1] = interval[1]
    elif direction==1:
        v[0] = interval[0]
        v[1] = interval[1]
    else:
        u[0] = interval[0][0]
        u[1] = interval[0][1]
        v[0] = interval[1][0]
        v[1] = interval[1][1]
    new_surface = surface.Trim(u,v)
    if new_surface:
        rc = scriptcontext.doc.Objects.AddSurface(new_surface)
        if delete_input: scriptcontext.doc.Objects.Delete(rhutil.coerceguid(surface_id), True)
        scriptcontext.doc.Views.Redraw()
        return rc


def UnrollSurface(surface_id, explode=False, following_geometry=None, absolute_tolerance=None, relative_tolerance=None):
    """Flattens a developable surface or polysurface
    Parameters:
      surface_id (guid): the surface's identifier
      explode (bool, optional): If True, the resulting surfaces ar not joined
      following_geometry ({guid, ...]): List of curves, dots, and points which
        should be unrolled with the surface
    Returns:
      list(guid, ...): of unrolled surface ids
      tuple((guid, ...),(guid, ...)): if following_geometry is not None, a tuple
        [1] is the list of unrolled surface ids
        [2] is the list of unrolled following geometry
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface or polysurface to unroll", rs.filter.surface + rs.filter.polysurface)
      if surface: rs.UnrollSurface(surface)
    See Also:
      
    """
    brep = rhutil.coercebrep(surface_id, True)
    unroll = Rhino.Geometry.Unroller(brep)
    unroll.ExplodeOutput = explode
    if relative_tolerance is None: relative_tolerance = scriptcontext.doc.ModelRelativeTolerance
    if absolute_tolerance is None: absolute_tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    unroll.AbsoluteTolerance = absolute_tolerance
    unroll.RelativeTolerance = relative_tolerance
    if following_geometry:
        for id in following_geometry:
            geom = rhutil.coercegeometry(id)
            unroll.AddFollowingGeometry(geom)
    breps, curves, points, dots = unroll.PerformUnroll()
    if not breps: return None
    rc = [scriptcontext.doc.Objects.AddBrep(brep) for brep in breps]
    new_following = []
    for curve in curves:
        id = scriptcontext.doc.Objects.AddCurve(curve)
        new_following.append(id)
    for point in points:
        id = scriptcontext.doc.Objects.AddPoint(point)
        new_following.append(id)
    for dot in dots:
        id = scriptcontext.doc.Objects.AddTextDot(dot)
        new_following.append(id)
    scriptcontext.doc.Views.Redraw()
    if following_geometry: return rc, new_following
    return rc


def ChangeSurfaceDegree(object_id, degree):
  """Changes the degree of a surface object.  For more information see the Rhino help file for the ChangeDegree command.
  Parameters:
    object_id (guid): the object's identifier.
    degree ([number, number]) two integers, specifying the degrees for the U  V directions
  Returns:
    bool: True of False indicating success or failure.
    None: on failure.
  Example:
    
  See Also:
    IsSurface
  """
  object = rhutil.coercerhinoobject(object_id)
  if not object: return None
  obj_ref = Rhino.DocObjects.ObjRef(object)
  
  surface = obj_ref.Surface()
  if not surface: return None

  if not isinstance(surface, Rhino.Geometry.NurbsSurface):
    surface = surface.ToNurbsSurface() # could be a Surface or BrepFace

  max_nurbs_degree = 11
  if degree[0] < 1 or degree[0] > max_nurbs_degree or \
      degree[1] < 1 or degree[1] > max_nurbs_degree or \
      (surface.Degree(0) == degree[0] and surface.Degree(1) == degree[1]):
    return None

  r = False
  if surface.IncreaseDegreeU(degree[0]):
    if surface.IncreaseDegreeV(degree[1]):
      r = scriptcontext.doc.Objects.Replace(object_id, surface)
  return r

```
Page 6/7FirstPrevNextLast