#
tokens: 42821/50000 8/82 files (page 2/7)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 7. Use http://codebase.md/jingcheng-chen/rhinomcp?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/material.py:
--------------------------------------------------------------------------------

```python
import Rhino
import Rhino.DocObjects

import scriptcontext

from rhinoscript import utility as rhutil
from rhinoscript.layer import __getlayer


def AddMaterialToLayer(layer):
    """Add material to a layer and returns the new material's index. If the
    layer already has a material, then the layer's current material index is
    returned
    Parameters:
      layer (str): name of an existing layer.
    Returns:
      number: Material index of the layer if successful
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.CurrentLayer()
      index = rs.LayerMaterialIndex(layer)
      if index==-1: index = rs.AddMaterialToLayer(layer)
    See Also:
      LayerMaterialIndex
      IsMaterialDefault
    """
    layer = __getlayer(layer, True)
    if layer.RenderMaterialIndex>-1: return layer.RenderMaterialIndex
    material_index = scriptcontext.doc.Materials.Add()
    layer.RenderMaterialIndex = material_index
    scriptcontext.doc.Views.Redraw()
    return material_index
    #return scriptcontext.errorhandler()


def AddMaterialToObject(object_id):
    """Adds material to an object and returns the new material's index. If the
    object already has a material, the the object's current material index is
    returned.
    Parameters:
      object_id (guid): identifier of an object
    Returns:
      number: material index of the object
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject()
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index==-1: index = rs.AddMaterialToObject(obj)
    See Also:
      IsMaterialDefault
      ObjectMaterialIndex
      ObjectMaterialSource
    """
    rhino_object = rhutil.coercerhinoobject(object_id, True, True)
    attr = rhino_object.Attributes
    if attr.MaterialSource!=Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject:
        attr.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject
        scriptcontext.doc.Objects.ModifyAttributes(rhino_object, attr, True)
        attr = rhino_object.Attributes
    material_index = attr.MaterialIndex
    if material_index>-1: return material_index
    material_index = scriptcontext.doc.Materials.Add()
    attr.MaterialIndex = material_index
    scriptcontext.doc.Objects.ModifyAttributes(rhino_object, attr, True)
    return material_index

    
def CopyMaterial(source_index, destination_index):
    """Copies definition of a source material to a destination material
    Parameters:
      source_index, destination_index (number): indices of materials to copy
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      src = rs.LayerMaterialIndex("Default")
      dest = rs.LayerMaterialIndex(rs.CurrentLayer())
      if src>=0 and dest>=0 and src!=dest:
          rs.CopyMaterial( src, dest )
    See Also:
      LayerMaterialIndex
      ObjectMaterialIndex
    """
    if source_index==destination_index: return False
    source = scriptcontext.doc.Materials[source_index]
    if source is None: return False
    rc = scriptcontext.doc.Materials.Modify(source, destination_index, True)
    if rc: scriptcontext.doc.Views.Redraw()
    return rc


def IsMaterialDefault(material_index):
    """Verifies a material is a copy of Rhino's built-in "default" material.
    The default material is used by objects and layers that have not been
    assigned a material.
    Parameters:
      material_index (number): the zero-based material index
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject()
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if rs.IsMaterialDefault(index):
              print("Object is assigned default material.")
          else:
              print("Object is not assigned default material.")
    See Also:
      LayerMaterialIndex
      ObjectMaterialIndex
    """
    mat = scriptcontext.doc.Materials[material_index]
    return mat and mat.IsDefaultMaterial


def IsMaterialReference(material_index):
    """Verifies a material is referenced from another file
    Parameters:
      material_index (number): the zero-based material index
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject()
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if rs.IsMaterialReference(index):
              print("The material is referenced from another file.")
          else:
              print("The material is not referenced from another file.")
    See Also:
      IsLayerReference
      IsLightReference
      IsObjectReference
    """
    mat = scriptcontext.doc.Materials[material_index]
    return mat and mat.IsReference


def MatchMaterial(source, destination):
    """Copies the material definition from one material to one or more objects
    Parameters:
      source (number|guid): source material index -or- identifier of the source object.
        The object must have a material assigned
      destination ([guid, ...]) identifiers(s) of the destination object(s)
    Returns:
      number: number of objects that were modified if successful
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select source object")
      if obj and rs.ObjectMaterialIndex(obj)>-1:
          objects = rs.GetObjects("Select destination objects")
          if objects: rs.MatchMaterial( obj, objects )
    See Also:
      CopyMaterial
      LayerMaterialIndex
      ObjectMaterialIndex
    """
    source_id = rhutil.coerceguid(source)
    source_mat = None
    if source_id:
        rhobj = rhutil.coercerhinoobject(source_id, True, True)
        source = rhobj.Attributes.MaterialIndex
    mat = scriptcontext.doc.Materials[source]
    if not mat: return scriptcontext.errorhandler()
    destination_id = rhutil.coerceguid(destination)
    if destination_id: destination = [destination]
    ids = [rhutil.coerceguid(d) for d in destination]
    rc = 0
    for id in ids:
        rhobj = scriptcontext.doc.Objects.Find(id)
        if rhobj:
            rhobj.Attributes.MaterialIndex = source
            rhobj.Attributes.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject
            rhobj.CommitChanges()
            rc += 1
    if rc>0: scriptcontext.doc.Views.Redraw()
    return rc


def MaterialBump(material_index, filename=None):
    """Returns or modifies a material's bump bitmap filename
    Parameters:
      material_index (number): zero based material index
      filename (str, optional): the bump bitmap filename
    Returns:
      str: if filename is not specified, the current bump bitmap filename
      str: if filename is specified, the previous bump bitmap filename
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialBump( index, "C:\\Users\\Steve\\Desktop\\bumpimage.png" )
    See Also:
      MaterialColor
      MaterialName
      MaterialReflectiveColor
      MaterialShine
      MaterialTexture
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    texture = mat.GetBumpTexture()
    rc = texture.FileName if texture else ""
    if filename:
        mat.SetBumpTexture(filename)
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialColor(material_index, color=None):
    """Returns or modifies a material's diffuse color.
    Parameters:
      material_index (number): zero based material index
      color (color, optional): the new color value
    Returns:
      color: if color is not specified, the current material color
      color: if color is specified, the previous material color
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialColor( index, (127, 255, 191) )
    See Also:
      MaterialBump
      MaterialName
      MaterialReflectiveColor
      MaterialShine
      MaterialTexture
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    rc = mat.DiffuseColor
    color = rhutil.coercecolor(color)
    if color:
        mat.DiffuseColor = color
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialEnvironmentMap(material_index, filename=None):
    """Returns or modifies a material's environment bitmap filename.
    Parameters:
      material_index (number): zero based material index
      filename (str, optional): the environment bitmap filename
    Returns:
      str: if filename is not specified, the current environment bitmap filename
      str: if filename is specified, the previous environment bitmap filename
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialEnvironmentMap( index, "C:\\Users\\Steve\\Desktop\\emapimage.png" )
    See Also:
      MaterialBump
      MaterialTexture
      MaterialTransparencyMap
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    texture = mat.GetEnvironmentTexture()
    rc = texture.FileName if texture else ""
    if filename:
        mat.SetEnvironmentTexture(filename)
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialName(material_index, name=None):
    """Returns or modifies a material's user defined name
    Parameters:
      material_index (number): zero based material index
      name (str, optional): the new name
    Returns:
      str: if name is not specified, the current material name
      str: if name is specified, the previous material name
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialName( index, "Fancy_Material" )
    See Also:
      MaterialBump
      MaterialColor
      MaterialReflectiveColor
      MaterialShine
      MaterialTexture
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    rc = mat.Name
    if name:
        mat.Name = name
        mat.CommitChanges()
    return rc


def MaterialReflectiveColor(material_index, color=None):
    """Returns or modifies a material's reflective color.
    Parameters:
      material_index (number): zero based material index
      color (color, optional): the new color value
    Returns:
      color: if color is not specified, the current material reflective color
      color: if color is specified, the previous material reflective color
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialReflectiveColor( index, (191, 191, 255) )
    See Also:
      MaterialBump
      MaterialColor
      MaterialName
      MaterialShine
      MaterialTexture
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    rc = mat.ReflectionColor
    color = rhutil.coercecolor(color)
    if color:
        mat.ReflectionColor = color
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialShine(material_index, shine=None):
    """Returns or modifies a material's shine value
    Parameters:
      material_index (number): zero based material index
      shine (number, optional): the new shine value. A material's shine value ranges from 0.0 to 255.0, with
        0.0 being matte and 255.0 being glossy
    Returns:
      number: if shine is not specified, the current material shine value
      number: if shine is specified, the previous material shine value
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      MAX_SHINE = 255.0
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialShine( index, MAX_SHINE/2 )
    See Also:
      MaterialBump
      MaterialColor
      MaterialName
      MaterialReflectiveColor
      MaterialTexture
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    rc = mat.Shine
    if shine:
        mat.Shine = shine
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialTexture(material_index, filename=None):
    """Returns or modifies a material's texture bitmap filename
    Parameters:
      material_index (number): zero based material index
      filename (str, optional): the texture bitmap filename
    Returns:
      str: if filename is not specified, the current texture bitmap filename
      str: if filename is specified, the previous texture bitmap filename
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialTexture( index, "C:\\Users\\Steve\\Desktop\\textureimage.png" )
    See Also:
      MaterialBump
      MaterialColor
      MaterialName
      MaterialReflectiveColor
      MaterialShine
      MaterialTransparency
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    texture = mat.GetBitmapTexture()
    rc = texture.FileName if texture else ""
    if filename:
        mat.SetBitmapTexture(filename)
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialTransparency(material_index, transparency=None):
    """Returns or modifies a material's transparency value
    Parameters:
      material_index (number): zero based material index
      transparency (number, optional): the new transparency value. A material's transparency value ranges from 0.0 to 1.0, with
        0.0 being opaque and 1.0 being transparent
    Returns:
      number: if transparency is not specified, the current material transparency value
      number: if transparency is specified, the previous material transparency value
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialTransparency( index, 0.50 )
    See Also:
      MaterialBump
      MaterialColor
      MaterialName
      MaterialReflectiveColor
      MaterialShine
      MaterialTexture
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    rc = mat.Transparency
    if transparency:
        mat.Transparency = transparency
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def MaterialTransparencyMap(material_index, filename=None):
    """Returns or modifies a material's transparency bitmap filename
    Parameters:
      material_index (number): zero based material index
      filename (str, optional): the transparency bitmap filename
    Returns:
      str: if filename is not specified, the current transparency bitmap filename
      str: if filename is specified, the previous transparency bitmap filename
      None: if not successful or on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1:
              rs.MaterialTransparencyMap( index, "C:\\Users\\Steve\\Desktop\\texture.png" )
    See Also:
      MaterialBump
      MaterialEnvironmentMap
      MaterialTexture
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return scriptcontext.errorhandler()
    texture = mat.GetTransparencyTexture()
    rc = texture.FileName if texture else ""
    if filename:
        mat.SetTransparencyTexture(filename)
        mat.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def ResetMaterial(material_index):
    """Resets a material to Rhino's default material
    Parameters:
      material_index (number) zero based material index
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if obj:
          index = rs.ObjectMaterialIndex(obj)
          if index>-1: rs.ResetMaterial(index)
    See Also:
      LayerMaterialIndex
      ObjectMaterialIndex
    """
    mat = scriptcontext.doc.Materials[material_index]
    if mat is None: return False
    rc = scriptcontext.doc.Materials.ResetMaterial(material_index)
    scriptcontext.doc.Views.Redraw()
    return rc

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/plane.py:
--------------------------------------------------------------------------------

```python
import math

import Rhino.Geometry

import scriptcontext

from rhinoscript import utility as rhutil


def DistanceToPlane(plane, point):
    """Returns the distance from a 3D point to a plane
    Parameters:
      plane (plane): the plane
      point (point): List of 3 numbers or Point3d
    Returns:
      number: The distance if successful, otherwise None
    Example:
      import rhinoscriptsyntax as rs
      point = rs.GetPoint("Point to test")
      if point:
          plane = rs.ViewCPlane()
          if plane:
              distance = rs.DistanceToPlane(plane, point)
              if distance is not None:
                  print("Distance to plane: {}".format(distance))
    See Also:
      Distance
      PlaneClosestPoint
    """
    plane = rhutil.coerceplane(plane, True)
    point = rhutil.coerce3dpoint(point, True)
    return plane.DistanceTo(point)


def EvaluatePlane(plane, parameter):
    """Evaluates a plane at a U,V parameter
    Parameters:
      plane (plane): the plane to evaluate
      parameter ([number, number]): list of two numbers defining the U,V parameter to evaluate
    Returns:
      point: Point3d on success
    Example:
      import rhinoscriptsyntax as rs
      view = rs.CurrentView()
      plane = rs.ViewCPlane(view)
      point = rs.EvaluatePlane(plane, (5,5))
      rs.AddPoint( point )
    See Also:
      PlaneClosestPoint
    """
    plane = rhutil.coerceplane(plane, True)
    return plane.PointAt(parameter[0], parameter[1])


def IntersectPlanes(plane1, plane2, plane3):
    """Calculates the intersection of three planes
    Parameters:
      plane1 (plane): the 1st plane to intersect
      plane2 (plane): the 2nd plane to intersect
      plane3 (plane): the 3rd plane to intersect
    Returns:
      point: the intersection point between the 3 planes on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      plane1 = rs.WorldXYPlane()
      plane2 = rs.WorldYZPlane()
      plane3 = rs.WorldZXPlane()
      point = rs.IntersectPlanes(plane1, plane2, plane3)
      if point: rs.AddPoint(point)
    See Also:
      LineLineIntersection
      LinePlaneIntersection
      PlanePlaneIntersection
    """
    plane1 = rhutil.coerceplane(plane1, True)
    plane2 = rhutil.coerceplane(plane2, True)
    plane3 = rhutil.coerceplane(plane3, True)
    rc, point = Rhino.Geometry.Intersect.Intersection.PlanePlanePlane(plane1, plane2, plane3)
    if rc: return point


def MovePlane(plane, origin):
    """Moves the origin of a plane
    Parameters:
      plane (plane): Plane or ConstructionPlane
      origin (point): Point3d or list of three numbers
    Returns:
      plane: moved plane
    Example:
      import rhinoscriptsyntax as rs
      origin = rs.GetPoint("CPlane origin")
      if origin:
          plane = rs.ViewCPlane()
          plane = rs.MovePlane(plane,origin)
          rs.ViewCplane(plane)
    See Also:
      PlaneFromFrame
      PlaneFromNormal
      RotatePlane
    """
    plane = rhutil.coerceplane(plane, True)
    origin = rhutil.coerce3dpoint(origin, True)
    rc = Rhino.Geometry.Plane(plane)
    rc.Origin = origin
    return rc


def PlaneClosestPoint(plane, point, return_point=True):
    """Returns the point on a plane that is closest to a test point.
    Parameters:
      plane (plane): The plane
      point (point): The 3-D point to test.
      return_point (bool, optional): If omitted or True, then the point on the plane
         that is closest to the test point is returned. If False, then the
         parameter of the point on the plane that is closest to the test
         point is returned.
    Returns:
      point: If return_point is omitted or True, then the 3-D point
      point: If return_point is False, then an array containing the U,V parameters
      of the point
      None: if not successful, or on error.
    Example:
      import rhinoscriptsyntax as rs
      point = rs.GetPoint("Point to test")
      if point:
          plane = rs.ViewCPlane()
          if plane:
              print(rs.PlaneClosestPoint(plane, point))
    See Also:
      DistanceToPlane
      EvaluatePlane
    """
    plane = rhutil.coerceplane(plane, True)
    point = rhutil.coerce3dpoint(point, True)
    if return_point:
        return plane.ClosestPoint(point)
    else:
        rc, s, t = plane.ClosestParameter(point)
        if rc: return s, t


def PlaneCurveIntersection(plane, curve, tolerance=None):
    """Intersect an infinite plane and a curve object
    Parameters:
      plane (plane): The plane to intersect.
      curve (guid): The identifier of the curve object
      torerance (number, optional): The intersection tolerance. If omitted, the document's absolute tolerance is used.
    Returns:
      A list of intersection information tuple if successful.  The list will contain one or more of the following tuple:

        Element Type        Description

        [0]       Number      The intersection event type, either Point (1) or Overlap (2).

        [1]       Point3d     If the event type is Point (1), then the intersection point on the curve.
                            If the event type is Overlap (2), then intersection start point on the curve.

        [2]       Point3d     If the event type is Point (1), then the intersection point on the curve.
                            If the event type is Overlap (2), then intersection end point on the curve.

        [3]       Point3d     If the event type is Point (1), then the intersection point on the plane.
                            If the event type is Overlap (2), then intersection start point on the plane.

        [4]       Point3d     If the event type is Point (1), then the intersection point on the plane.

                            If the event type is Overlap (2), then intersection end point on the plane.

        [5]       Number      If the event type is Point (1), then the curve parameter.
                            If the event type is Overlap (2), then the start value of the curve parameter range.
                            
        [6]       Number      If the event type is Point (1), then the curve parameter.
                            If the event type is Overlap (2),  then the end value of the curve parameter range.

        [7]       Number      If the event type is Point (1), then the U plane parameter.
                            If the event type is Overlap (2), then the U plane parameter for curve at (n, 5).

        [8]       Number      If the event type is Point (1), then the V plane parameter.
                            If the event type is Overlap (2), then the V plane parameter for curve at (n, 5).

        [9]       Number      If the event type is Point (1), then the U plane parameter.
                            If the event type is Overlap (2), then the U plane parameter for curve at (n, 6).
                            
        [10]      Number      If the event type is Point (1), then the V plane parameter.
                            If the event type is Overlap (2), then the V plane parameter for curve at (n, 6).

      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curve = rs.GetObject("Select curve", rs.filter.curve)
      if curve:
          plane = rs.WorldXYPlane()
          intersections = rs.PlaneCurveIntersection(plane, curve)
          if intersections:
              for intersection in intersections:
                  rs.AddPoint(intersection[1])
    See Also:
      IntersectPlanes
      PlanePlaneIntersection
      PlaneSphereIntersection
    """
    plane = rhutil.coerceplane(plane, True)
    curve = rhutil.coercecurve(curve, -1, True)
    if tolerance is None: tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    intersections = Rhino.Geometry.Intersect.Intersection.CurvePlane(curve, plane, tolerance)
    if intersections:
        rc = []
        for intersection in intersections:
            a = 1
            if intersection.IsOverlap: a = 2
            b = intersection.PointA
            c = intersection.PointA2
            d = intersection.PointB
            e = intersection.PointB2
            f = intersection.ParameterA
            g = intersection.ParameterB
            h = intersection.OverlapA[0]
            i = intersection.OverlapA[1]
            j = intersection.OverlapB[0]
            k = intersection.OverlapB[1]
            rc.append( (a,b,c,d,e,f,g,h,i,j,k) )
        return rc


def PlaneEquation(plane):
    """Returns the equation of a plane as a tuple of four numbers. The standard
    equation of a plane with a non-zero vector is Ax+By+Cz+D=0
    Parameters:
      plane (plane): the plane to deconstruct
    Returns:
      tuple(number, number, number, number): containing four numbers that represent the coefficients of the equation  (A, B, C, D) if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.ViewCPlane()
      equation = rs.PlaneEquation(plane)
      print("A = {}".format(equation[0]))
      print("B = {}".format(equation[1]))
      print("C = {}".format(equation[2]))
      print("D = {}".format(equation[3]))
    See Also:
      PlaneFromFrame
      PlaneFromNormal
      PlaneFromPoints
    """
    plane = rhutil.coerceplane(plane, True)
    rc = plane.GetPlaneEquation()
    return rc[0], rc[1], rc[2], rc[3]


def PlaneFitFromPoints(points):
    """Returns a plane that was fit through an array of 3D points.
    Parameters:
    points (point): An array of 3D points.
    Returns: 
      plane: The plane if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      points = rs.GetPoints()
      if points:
          plane = rs.PlaneFitFromPoints(points)
          if plane:
              magX = plane.XAxis.Length
              magY = plane.YAxis.Length
              rs.AddPlaneSurface( plane, magX, magY )
    See Also:
      PlaneFromFrame
      PlaneFromNormal
      PlaneFromPoints
    """
    points = rhutil.coerce3dpointlist(points, True)
    rc, plane = Rhino.Geometry.Plane.FitPlaneToPoints(points)
    if rc==Rhino.Geometry.PlaneFitResult.Success: return plane


def PlaneFromFrame(origin, x_axis, y_axis):
    """Construct a plane from a point, and two vectors in the plane.
    Parameters:
      origin (point): A 3D point identifying the origin of the plane.
      x_axis (vector): A non-zero 3D vector in the plane that determines the X axis
               direction.
      y_axis (vector): A non-zero 3D vector not parallel to x_axis that is used
               to determine the Y axis direction. Note, y_axis does not
               have to be perpendicular to x_axis.
    Returns:
      plane: The plane if successful.
    Example:
      import rhinoscriptsyntax as rs
      origin = rs.GetPoint("CPlane origin")
      if origin:
          xaxis = (1,0,0)
          yaxis = (0,0,1)
          plane = rs.PlaneFromFrame( origin, xaxis, yaxis )
          rs.ViewCPlane(None, plane)
    See Also:
      MovePlane
      PlaneFromNormal
      PlaneFromPoints
      RotatePlane
    """
    origin = rhutil.coerce3dpoint(origin, True)
    x_axis = rhutil.coerce3dvector(x_axis, True)
    y_axis = rhutil.coerce3dvector(y_axis, True)
    return Rhino.Geometry.Plane(origin, x_axis, y_axis)


def PlaneFromNormal(origin, normal, xaxis=None):
    """Creates a plane from an origin point and a normal direction vector.
    Parameters:
      origin (point): A 3D point identifying the origin of the plane.
      normal (vector): A 3D vector identifying the normal direction of the plane.
      xaxis (vector, optional): optional vector defining the plane's x-axis
    Returns:
      plane: The plane if successful.
    Example:
      import rhinoscriptsyntax as rs
      origin = rs.GetPoint("CPlane origin")
      if origin:
          direction = rs.GetPoint("CPlane direction")
          if direction:
              normal = direction - origin
              normal = rs.VectorUnitize(normal)
              rs.ViewCPlane( None, rs.PlaneFromNormal(origin, normal) )
    See Also:
      MovePlane
      PlaneFromFrame
      PlaneFromPoints
      RotatePlane
    """
    origin = rhutil.coerce3dpoint(origin, True)
    normal = rhutil.coerce3dvector(normal, True)
    rc = Rhino.Geometry.Plane(origin, normal)
    if xaxis:
        xaxis = rhutil.coerce3dvector(xaxis, True)
        xaxis = Rhino.Geometry.Vector3d(xaxis)#prevent original xaxis parameter from being unitized too
        xaxis.Unitize()
        yaxis = Rhino.Geometry.Vector3d.CrossProduct(rc.Normal, xaxis)
        rc = Rhino.Geometry.Plane(origin, xaxis, yaxis)
    return rc


def PlaneFromPoints(origin, x, y):
    """Creates a plane from three non-colinear points
    Parameters:
      origin (point): origin point of the plane
      x, y (point): points on the plane's x and y axes
    Returns:
      plane: The plane if successful, otherwise None
    Example:
      import rhinoscriptsyntax as rs
      corners = rs.GetRectangle()
      if corners:
          rs.ViewCPlane( rs.PlaneFromPoints(corners[0], corners[1], corners[3]))
    See Also:
      PlaneFromFrame
      PlaneFromNormal
    """
    origin = rhutil.coerce3dpoint(origin, True)
    x = rhutil.coerce3dpoint(x, True)
    y = rhutil.coerce3dpoint(y, True)
    plane = Rhino.Geometry.Plane(origin, x, y)
    if plane.IsValid: return plane


def PlanePlaneIntersection(plane1, plane2):
    """Calculates the intersection of two planes
    Parameters:
      plane1 (plane): the 1st plane to intersect
      plane2 (plane): the 2nd plane to intersect
    Returns:
      line:  a line with two 3d points identifying the starting/ending points of the intersection
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      plane1 = rs.WorldXYPlane()
      plane2 = rs.WorldYZPlane()
      line = rs.PlanePlaneIntersection(plane1, plane2)
      if line: rs.AddLine(line[0], line[1])
    See Also:
      IntersectPlanes
      LineLineIntersection
      LinePlaneIntersection
    """
    plane1 = rhutil.coerceplane(plane1, True)
    plane2 = rhutil.coerceplane(plane2, True)
    rc, line = Rhino.Geometry.Intersect.Intersection.PlanePlane(plane1, plane2)
    if rc: return line.From, line.To


def PlaneSphereIntersection(plane, sphere_plane, sphere_radius):
    """Calculates the intersection of a plane and a sphere
    Parameters:
      plane (plane): the plane to intersect
      sphere_plane (plane): equatorial plane of the sphere. origin of the plane is
        the center of the sphere
      sphere_radius (number): radius of the sphere
    Returns:
      list(number, point|plane, number): of intersection results
          Element    Type      Description
          [0]       number     The type of intersection, where 0 = point and 1 = circle.
          [1]   point or plane If a point intersection, the a Point3d identifying the 3-D intersection location.
                               If a circle intersection, then the circle's plane. The origin of the plane will be the center point of the circle
          [2]       number     If a circle intersection, then the radius of the circle.
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.WorldXYPlane()
      radius = 10
      results = rs.PlaneSphereIntersection(plane, plane, radius)
      if results:
          if results[0]==0:
              rs.AddPoint(results[1])
          else:
              rs.AddCircle(results[1], results[2])
    See Also:
      IntersectPlanes
      LinePlaneIntersection
      PlanePlaneIntersection
    """
    plane = rhutil.coerceplane(plane, True)
    sphere_plane = rhutil.coerceplane(sphere_plane, True)
    sphere = Rhino.Geometry.Sphere(sphere_plane, sphere_radius)
    rc, circle = Rhino.Geometry.Intersect.Intersection.PlaneSphere(plane, sphere)
    if rc==Rhino.Geometry.Intersect.PlaneSphereIntersection.Point:
        return 0, circle.Center
    if rc==Rhino.Geometry.Intersect.PlaneSphereIntersection.Circle:
        return 1, circle.Plane, circle.Radius


def PlaneTransform(plane, xform):
    """Transforms a plane
    Parameters:
      plane (plane): Plane to transform
      xform (transform): Transformation to apply
    Returns:
      plane:the resulting plane if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.ViewCPlane()
      xform = rs.XformRotation(45.0, plane.Zaxis, plane.Origin)
      plane = rs.PlaneTransform(plane, xform)
      rs.ViewCPlane(None, plane)
    See Also:
      PlaneFromFrame
      PlaneFromNormal
      PlaneFromPoints
    """
    plane = rhutil.coerceplane(plane, True)
    xform = rhutil.coercexform(xform, True)
    rc = Rhino.Geometry.Plane(plane)
    if rc.Transform(xform): return rc


def RotatePlane(plane, angle_degrees, axis):
    """Rotates a plane
    Parameters:
      plane (plane): Plane to rotate
      angle_degrees (number): rotation angle in degrees
      axis (vector): Axis of rotation or list of three numbers
    Returns:
      plane: rotated plane on success
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.ViewCPlane()
      rotated = rs.RotatePlane(plane, 45.0, plane.XAxis)
      rs.ViewCPlane( None, rotated )
    See Also:
      MovePlane
      PlaneFromFrame
      PlaneFromNormal
    """
    plane = rhutil.coerceplane(plane, True)
    axis = rhutil.coerce3dvector(axis, True)
    angle_radians = math.radians(angle_degrees)
    rc = Rhino.Geometry.Plane(plane)
    if rc.Rotate(angle_radians, axis): return rc


def WorldXYPlane():
    """Returns Rhino's world XY plane
    Returns:
      plane: Rhino's world XY plane
    Example:
      import rhinoscriptsyntax as rs
      view = rs.CurrentView()
      rs.ViewCPlane( view, rs.WorldXYPlane() )
    See Also:
      WorldYZPlane
      WorldZXPlane
    """
    return Rhino.Geometry.Plane.WorldXY


def WorldYZPlane():
    """Returns Rhino's world YZ plane
    Returns:
      plane: Rhino's world YZ plane
    Example:
      import rhinoscriptsyntax as rs
      view = rs.CurrentView()
      rs.ViewCPlane( view, rs.WorldYZPlane() )
    See Also:
      WorldXYPlane
      WorldZXPlane
    """
    return Rhino.Geometry.Plane.WorldYZ


def WorldZXPlane():
    """Returns Rhino's world ZX plane
    Returns:
      plane: Rhino's world ZX plane
    Example:
      import rhinoscriptsyntax as rs
      view = rs.CurrentView()
      rs.ViewCPlane( view, rs.WorldZXPlane() )
    See Also:
      WorldXYPlane
      WorldYZPlane
    """
    return Rhino.Geometry.Plane.WorldZX
```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/hatch.py:
--------------------------------------------------------------------------------

```python
import System

import Rhino

import scriptcontext

from rhinoscript import utility as rhutil


def __initHatchPatterns():
    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Solid.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Solid)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch1.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch1)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch2.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch2)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch3.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch3)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Dash.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Dash)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Grid.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Grid)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Grid60.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Grid60)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Plus.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Plus)

    if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Squares.Name) is None:
        scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Squares)


def AddHatch(curve_id, hatch_pattern=None, scale=1.0, rotation=0.0):
    """Creates a new hatch object from a closed planar curve object
    Parameters:
      curve_id (guid): identifier of the closed planar curve that defines the
          boundary of the hatch object
      hatch_pattern (str, optional): name of the hatch pattern to be used by the hatch
          object. If omitted, the current hatch pattern will be used
      scale (number, optional): hatch pattern scale factor
      rotation (number, optional): hatch pattern rotation angle in degrees.
    Returns:
      guid:identifier of the newly created hatch on success
      None on error
    Example:
      import rhinoscriptsyntax as rs
      circle = rs.AddCircle(rs.WorldXYPlane(), 10.0)
      if rs.IsHatchPattern("Grid"):
          rs.AddHatch( circle, "Grid" )
      else:
          rs.AddHatch( circle, rs.CurrentHatchPattern() )
    See Also:
      AddHatches
      CurrentHatchPattern
      HatchPatternNames
    """
    rc = AddHatches(curve_id, hatch_pattern, scale, rotation)
    if rc: return rc[0]
    return scriptcontext.errorhandler()


def AddHatches(curve_ids, hatch_pattern=None, scale=1.0, rotation=0.0, tolerance=None):
    """Creates one or more new hatch objects a list of closed planar curves
    Parameters:
      curve_ids ([guid, ...]): identifiers of the closed planar curves that defines the
          boundary of the hatch objects
      hatch_pattern (str, optional):  name of the hatch pattern to be used by the hatch
          object. If omitted, the current hatch pattern will be used
      scale (number, optional): hatch pattern scale factor
      rotation (number, optional): hatch pattern rotation angle in degrees.
      tolerance (number, optional): tolerance for hatch fills.
    Returns:
      list(guid, ...): identifiers of the newly created hatch on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      curves = rs.GetObjects("Select closed planar curves", rs.filter.curve)
      if curves:
          if rs.IsHatchPattern("Grid"):
              rs.AddHatches( curves, "Grid" )
          else:
              rs.AddHatches( curves, rs.CurrentHatchPattern() )
    See Also:
      AddHatch
      CurrentHatchPattern
      HatchPatternNames
    """
    __initHatchPatterns()
    id = rhutil.coerceguid(curve_ids, False)
    if id: curve_ids = [id]
    index = scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex
    if hatch_pattern is None:
        hatch_pattern = CurrentHatchPattern()
    if isinstance(hatch_pattern, int) and hatch_pattern != index:
        index = hatch_pattern
    else:
        pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
        index = Rhino.RhinoMath.UnsetIntIndex if pattern_instance is None else pattern_instance.Index
    if index<0: return scriptcontext.errorhandler()
    curves = [rhutil.coercecurve(id, -1, True) for id in curve_ids]
    rotation = Rhino.RhinoMath.ToRadians(rotation)
    if tolerance is None or tolerance < 0:
        tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    hatches = Rhino.Geometry.Hatch.Create(curves, index, rotation, scale, tolerance)
    if not hatches: return scriptcontext.errorhandler()
    ids = []
    for hatch in hatches:
        id = scriptcontext.doc.Objects.AddHatch(hatch)
        if id==System.Guid.Empty: continue
        ids.append(id)
    if not ids: return scriptcontext.errorhandler()
    scriptcontext.doc.Views.Redraw()
    return ids


def AddHatchPatterns(filename, replace=False):
    """Adds hatch patterns to the document by importing hatch pattern definitions
    from a pattern file.
    Parameters:
      filename (str): name of the hatch pattern file
      replace (bool, optional): If hatch pattern names already in the document match hatch
          pattern names in the pattern definition file, then the existing hatch
          patterns will be redefined
    Returns:
      list(str, ...): Names of the newly added hatch patterns if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      filename = rs.OpenFileName("Import", "Pattern Files (*.pat)|*.pat||")
      if filename:
          patterns = rs.AddHatchPatterns(filename)
          if patterns:
              for pattern in patterns: print(pattern)
    See Also:
      HatchPatternCount
      HatchPatternNames
    """
    patterns = Rhino.DocObjects.HatchPattern.ReadFromFile(filename, True)
    if not patterns: return scriptcontext.errorhandler()
    rc = []
    for pattern in patterns:
         index = scriptcontext.doc.HatchPatterns.Add(pattern)
         if index>=0:
             pattern = scriptcontext.doc.HatchPatterns[index]
             rc.append(pattern.Name)
    if not rc: return scriptcontext.errorhandler()
    return rc


def CurrentHatchPattern(hatch_pattern=None):
    """Returns or sets the current hatch pattern file
    Parameters:
      hatch_pattern(str, optional):  name of an existing hatch pattern to make current
    Returns:
      str: if hatch_pattern is not specified, the current hatch pattern
      str: if hatch_pattern is specified, the previous hatch pattern
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      if rs.IsHatchPattern("Hatch2"): rs.CurrentHatchPattern("Hatch2")
    See Also:
      HatchPatternCount
      HatchPatternNames
    """
    i = scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex
    rc = scriptcontext.doc.HatchPatterns[i].Name
    if hatch_pattern:
        __initHatchPatterns()
        pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
        if pattern_instance is None: return scriptcontext.errorhandler()
        scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex = pattern_instance.Index
    return rc


def ExplodeHatch(hatch_id, delete=False):
    """Explodes a hatch object into its component objects. The exploded objects
    will be added to the document. If the hatch object uses a solid pattern,
    then planar face Brep objects will be created. Otherwise, line curve objects
    will be created
    Parameters:
      hatch_id (guid): identifier of a hatch object
      delete (bool, optional): delete the hatch object
    Returns:
      list(guid, ...): list of identifiers for the newly created objects
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select object")
      if rs.IsHatch(id): rs.ExplodeHatch(id, True)
    See Also:
      IsHatch
      HatchPattern
      HatchRotation
      HatchScale
    """
    rhobj = rhutil.coercerhinoobject(hatch_id, True, True)
    pieces = rhobj.HatchGeometry.Explode()
    if not pieces: return scriptcontext.errorhandler()
    attr = rhobj.Attributes
    rc = []
    for piece in pieces:
        id = None
        if isinstance(piece, Rhino.Geometry.Curve):
            id = scriptcontext.doc.Objects.AddCurve(piece, attr)
        elif isinstance(piece, Rhino.Geometry.Brep):
            id = scriptcontext.doc.Objects.AddBrep(piece, attr)
        if id: rc.append(id)
    if delete: scriptcontext.doc.Objects.Delete(rhobj)
    return rc


def HatchPattern(hatch_id, hatch_pattern=None):
    """Returns or changes a hatch object's hatch pattern
    Parameters:
      hatch_id (guid): identifier of a hatch object
      hatch_pattern (str, optional): name of an existing hatch pattern to replace the
          current hatch pattern
    Returns:
      str: if hatch_pattern is not specified, the current hatch pattern
      str: if hatch_pattern is specified, the previous hatch pattern
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objects = rs.AllObjects()
      if objects is not None:
          for obj in objects:
              if rs.IsHatch(obj) and rs.HatchPattern(obj)=="Solid":
                  rs.SelectObject(obj)
    See Also:
      AddHatch
      AddHatches
      HatchRotation
      HatchScale
      IsHatch
    """
    hatchobj = rhutil.coercerhinoobject(hatch_id, True, True)
    if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
        return scriptcontext.errorhandler()
    old_index = hatchobj.HatchGeometry.PatternIndex
    if hatch_pattern:
        __initHatchPatterns()
        new_patt = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
        if new_patt is None: return scriptcontext.errorhandler()
        hatchobj.HatchGeometry.PatternIndex = new_patt.Index
        hatchobj.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return scriptcontext.doc.HatchPatterns[old_index].Name


def HatchPatternCount():
    """Returns the number of hatch patterns in the document
    Returns:
      number: the number of hatch patterns in the document
    Example:
      import rhinoscriptsyntax as rs
      print("There are {} hatch patterns.".format(rs.HatchPatternCount()))
    See Also:
      HatchPatternNames
    """
    __initHatchPatterns()
    return scriptcontext.doc.HatchPatterns.Count


def HatchPatternDescription(hatch_pattern):
    """Returns the description of a hatch pattern. Note, not all hatch patterns
    have descriptions
    Parameters:
      hatch_pattern (str): name of an existing hatch pattern
    Returns:
      str: description of the hatch pattern on success otherwise None
    Example:
      import rhinoscriptsyntax as rs
      patterns = rs.HatchPatternNames()
      for pattern in patterns:
          description = rs.HatchPatternDescription(pattern)
          if description: print("{} - {}".format(pattern, description))
          else: print(pattern)
    See Also:
      HatchPatternCount
      HatchPatternNames
    """
    __initHatchPatterns()
    pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
    if pattern_instance is None: return scriptcontext.errorhandler()
    return pattern_instance.Description


def HatchPatternFillType(hatch_pattern):
    """Returns the fill type of a hatch pattern.
    Parameters:
      hatch_pattern (str): name of an existing hatch pattern
    Returns:
      number: hatch pattern's fill type if successful
              0 = solid, uses object color
              1 = lines, uses pattern file definition
              2 = gradient, uses fill color definition
      None: if unsuccessful
    Example:
      import rhinoscriptsyntax as rs
      patterns = rs.HatchPatternNames()
      for pattern in patterns:
          fill = rs.HatchPatternFillType(pattern)
          print("{} - {}".format(pattern, fill))
    See Also:
      HatchPatternCount
      HatchPatternNames
    """
    __initHatchPatterns()
    pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
    if pattern_instance is None: return scriptcontext.errorhandler()
    return int(pattern_instance.FillType)


def HatchPatternNames():
    """Returns the names of all of the hatch patterns in the document
    Returns:
      list(str, ...): the names of all of the hatch patterns in the document
    Example:
      import rhinoscriptsyntax as rs
      patterns = rs.HatchPatternNames()
      for pattern in patterns:
          description = rs.HatchPatternDescription(pattern)
          if description: print("{} - {}".format(pattern, description))
          else: print(pattern)
    See Also:
      HatchPatternCount
    """
    __initHatchPatterns()
    rc = []
    for i in range(scriptcontext.doc.HatchPatterns.Count):
        hatchpattern = scriptcontext.doc.HatchPatterns[i]
        if hatchpattern.IsDeleted: continue
        rc.append(hatchpattern.Name)
    return rc


def HatchRotation(hatch_id, rotation=None):
    """Returns or modifies the rotation applied to the hatch pattern when
    it is mapped to the hatch's plane
    Parameters:
      hatch_id (guid): identifier of a hatch object
      rotation (number, optional): rotation angle in degrees
    Returns:
      number: if rotation is not defined, the current rotation angle
      number: if rotation is specified, the previous rotation angle
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objects = rs.AllObjects()
      if objects:
          for obj in objects:
              if rs.IsHatch(obj) and rs.HatchRotation(obj)>0:
                  rs.HatchRotation(obj,0)
    See Also:
      AddHatch
      AddHatches
      HatchPattern
      HatchScale
      IsHatch
    """
    hatchobj = rhutil.coercerhinoobject(hatch_id, True, True)
    if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
        return scriptcontext.errorhandler()
    rc = hatchobj.HatchGeometry.PatternRotation
    rc = Rhino.RhinoMath.ToDegrees(rc)
    if rotation is not None and rotation!=rc:
        rotation = Rhino.RhinoMath.ToRadians(rotation)
        hatchobj.HatchGeometry.PatternRotation = rotation
        hatchobj.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def HatchScale(hatch_id, scale=None):
    """Returns or modifies the scale applied to the hatch pattern when it is
    mapped to the hatch's plane
    Parameters:
      hatch_id (guid): identifier of a hatch object
      scale (number, optional):  scale factor
    Returns:
      number: if scale is not defined, the current scale factor
      number: if scale is defined, the previous scale factor
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objects = rs.NormalObjects()
      if objects:
          for obj in objects:
              if rs.IsHatch(obj) and rs.HatchScale(obj)>1.0:
                  rs.HatchScale(obj, 1.0)
    See Also:
      HatchPattern
      HatchRotation
      IsHatch
    """
    hatchobj = rhutil.coercerhinoobject(hatch_id)
    if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
        return scriptcontext.errorhandler()
    rc = hatchobj.HatchGeometry.PatternScale
    if scale and scale!=rc:
        hatchobj.HatchGeometry.PatternScale = scale
        hatchobj.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc


def IsHatch(object_id):
    """Verifies the existence of a hatch object in the document
    Parameters:
      object_id (guid): identifier of an object
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      if rs.IsHatch(obj): print("Object is a hatch")
      else: print("Object is not a hatch")
    See Also:
      HatchPattern
      HatchRotation
      HatchScale
    """
    rhobj = rhutil.coercerhinoobject(object_id, True, False)
    return isinstance(rhobj, Rhino.DocObjects.HatchObject)


def IsHatchPattern(name):
    """Verifies the existence of a hatch pattern in the document
    Parameters:
      name (str): the name of a hatch pattern
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      hatch = rs.GetString("Hatch pattern name")
      if rs.IsHatchPattern(hatch): print("The hatch pattern exists.")
      else: print("The hatch pattern does not exist.")
    See Also:
      IsHatchPatternCurrent
      IsHatchPatternReference
    """
    __initHatchPatterns()
    return scriptcontext.doc.HatchPatterns.FindName(name) is not None


def IsHatchPatternCurrent(hatch_pattern):
    """Verifies that a hatch pattern is the current hatch pattern
    Parameters:
      hatch_pattern (str): name of an existing hatch pattern
    Returns:
      bool: True or False
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      hatch = rs.GetString("Hatch pattern name")
      if rs.IsHatchPattern(hatch):
          if rs.IsHatchPatternCurrent(hatch):
              print("The hatch pattern is current.")
          else:
              print("The hatch pattern is not current.")
      else: print("The hatch pattern does not exist.")
    See Also:
      IsHatchPattern
      IsHatchPatternReference
    """
    __initHatchPatterns()
    pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
    if pattern_instance is None: return scriptcontext.errorhandler()
    return pattern_instance.Index==scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex


def IsHatchPatternReference(hatch_pattern):
    """Verifies that a hatch pattern is from a reference file
    Parameters:
      hatch_pattern (str): name of an existing hatch pattern
    Returns:
      bool: True or False
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      hatch = rs.GetString("Hatch pattern name")
      if rs.IsHatchPattern(hatch):
          if rs.IsHatchPatternReference(hatch):
              print("The hatch pattern is reference.")
          else:
              print("The hatch pattern is not reference.")
      else:
          print("The hatch pattern does not exist.")
    See Also:
      IsHatchPattern
      IsHatchPatternCurrent
    """
    __initHatchPatterns()
    pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
    if pattern_instance is None: return scriptcontext.errorhandler()
    return pattern_instance.IsReference

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/transformation.py:
--------------------------------------------------------------------------------

```python
import math

import Rhino

import scriptcontext

from rhinoscript import utility as rhutil
from rhinoscript.view import __viewhelper


def IsXformIdentity(xform):
    """Verifies a matrix is the identity matrix
    Parameters:
      xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
    Returns:
      bool: True or False indicating success or failure.
    Example:
      import rhinoscriptsyntax as rs
      xform = rs.XformIdentity()
      print(rs.IsXformIdentity(xform))
    See Also:
      IsXformSimilarity
      IsXformZero
      XformIdentity
    """
    xform = rhutil.coercexform(xform, True)
    return xform==Rhino.Geometry.Transform.Identity


def IsXformSimilarity(xform):
    """Verifies a matrix is a similarity transformation. A similarity
    transformation can be broken into a sequence of dilations, translations,
    rotations, and reflections
    Parameters:
      xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
    Returns:
      bool: True if this transformation is an orientation preserving similarity, otherwise False.
    Example:
      import rhinoscriptsyntax as rs
      xform = rs.BlockInstanceXform(block)
      print(rs.IsXformSimilarity(xform))
    See Also:
      IsXformIdentity
      IsXformZero
    """
    xform = rhutil.coercexform(xform, True)
    return xform.SimilarityType!=Rhino.Geometry.TransformSimilarityType.NotSimilarity


def IsXformZero(xform):
    """verifies that a matrix is a zero transformation matrix
    Parameters:
      xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
    Returns:
      bool: True or False indicating success or failure.
    Example:
      import rhinoscriptsyntax as rs
      xform = rs.XformZero()
      print(rs.IsXformZero(xform))
    See Also:
      IsXformIdentity
      IsXformSimilarity
      XformZero
    """
    xform = rhutil.coercexform(xform, True)
    for i in range(4):
        for j in range(4):
            if xform[i,j]!=0: return False
    return True


def XformChangeBasis(initial_plane, final_plane):
    """Returns a change of basis transformation matrix or None on error
    Parameters:
      initial_plane (plane): the initial plane
      final_plane (plane): the final plane
    Returns:
      transform: The 4x4 transformation matrix if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      import math
      objs = rs.GetObjects("Select objects to shear")
      if objs:
          cplane = rs.ViewCPlane()
          cob = rs.XformChangeBasis(rs.WorldXYPlane(), cplane)
          shear2d = rs.XformIdentity()
          shear2d[0,2] = math.tan(math.radians(45.0))
          cob_inverse = rs.XformChangeBasis(cplane, rs.WorldXYPlane())
          temp = rs.XformMultiply(shear2d, cob)
          xform = rs.XformMultiply(cob_inverse, temp)
          rs.TransformObjects( objs, xform, True )
    See Also:
      XformCPlaneToWorld
      XformWorldToCPlane
    """
    initial_plane = rhutil.coerceplane(initial_plane, True)
    final_plane = rhutil.coerceplane(final_plane, True)
    xform = Rhino.Geometry.Transform.ChangeBasis(initial_plane, final_plane)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformChangeBasis2(x0,y0,z0,x1,y1,z1):
    """Returns a change of basis transformation matrix of None on error
    Parameters:
      x0,y0,z0 (vector): initial basis
      x1,y1,z1 (vector): final basis
    Returns:
      transform: The 4x4 transformation matrix if successful
      None: if not successful
    Example:
    See Also:
    """
    x0 = rhutil.coerce3dvector(x0, True)
    y0 = rhutil.coerce3dvector(y0, True)
    z0 = rhutil.coerce3dvector(z0, True)
    x1 = rhutil.coerce3dvector(x1, True)
    y1 = rhutil.coerce3dvector(y1, True)
    z1 = rhutil.coerce3dvector(z1, True)
    xform = Rhino.Geometry.Transform.ChangeBasis(x0,y0,z0,x1,y1,z1)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformCompare(xform1, xform2):
    """Compares two transformation matrices
    Parameters:
      xform1, xform2 = matrices to compare
    Returns:
        number:
        -1 if xform1<xform2
         1 if xform1>xform2
         0 if xform1=xform2
    Example:
      import rhinoscriptsyntax as rs
      xform0 = rs.XformZero()
      xform1 = rs.XformIdentity()
      print(rs.XformCompare(xform0, xform1))
    See Also:
      IsXformIdentity
      IsXformSimilarity
      IsXformZero
    """
    xform1 = rhutil.coercexform(xform1, True)
    xform2 = rhutil.coercexform(xform2, True)
    return xform1.CompareTo(xform2)


def XformCPlaneToWorld(point, plane):
    """Transform point from construction plane coordinates to world coordinates
    Parameters:
      point (point): A 3D point in construction plane coordinates.
      plane (plane): The construction plane
    Returns:
      point: A 3D point in world coordinates
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.ViewCPlane()
      point = rs.XFormCPlaneToWorld([0,0,0], plane)
      if point: print("World point: {}".format(point))
    See Also:
      XformWorldToCPlane
    """
    point = rhutil.coerce3dpoint(point, True)
    plane = rhutil.coerceplane(plane, True)
    return plane.Origin + point.X*plane.XAxis + point.Y*plane.YAxis + point.Z*plane.ZAxis


def XformDeterminant(xform):
    """Returns the determinant of a transformation matrix. If the determinant
    of a transformation matrix is 0, the matrix is said to be singular. Singular
    matrices do not have inverses.
    Parameters:
      xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
    Returns:
      number: The determinant if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      xform = rs.BlockInstanceXform(obj)
      if xform: print(rs.XformDeterminant(xform))
    See Also:
      XformInverse
    """
    xform = rhutil.coercexform(xform, True)
    return xform.Determinant


def XformDiagonal(diagonal_value):
    """Returns a diagonal transformation matrix. Diagonal matrices are 3x3 with
    the bottom row [0,0,0,1]
    Parameters:
      diagonal_value (number): the diagonal value
    Returns:
      transform: The 4x4 transformation matrix if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      def printmatrix(xform):
          for i in range(4):
              print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
      printmatrix(rs.XformDiagonal(3))
    See Also:
      XformIdentity
      XformZero
    """
    return Rhino.Geometry.Transform(diagonal_value)


def XformIdentity():
    """returns the identity transformation matrix
    Returns:
      transform: The 4x4 transformation matrix
    Example:
      import rhinoscriptsyntax as rs
      def printmatrix(xform):
          for i in range(4):
              print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
      printmatrix(rs.XformIdentity())
    See Also:
      XformDiagonal
      XformZero
    """
    return Rhino.Geometry.Transform.Identity


def XformInverse(xform):
    """Returns the inverse of a non-singular transformation matrix
    Parameters:
      xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
    Returns:
      transform: The inverted 4x4 transformation matrix if successful.
      None: if matrix is non-singular or on error.
    Example:
      import rhinoscriptsyntax as rs
      xform = rs.BlockInstanceXform(obj)
      if xform:
          rs.TransformObject( obj, rs.XformInverse(xform) )
    See Also:
      XformDeterminant
    """
    xform = rhutil.coercexform(xform, True)
    rc, inverse = xform.TryGetInverse()
    if not rc: return scriptcontext.errorhandler()
    return inverse


def XformMirror(mirror_plane_point, mirror_plane_normal):
    """Creates a mirror transformation matrix
    Parameters:
      mirror_plane_point (point): point on the mirror plane
      mirror_plane_normal (vector): a 3D vector that is normal to the mirror plane
    Returns:
      transform: mirror Transform matrix
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select objects to mirror")
      if objs:
          plane = rs.ViewCPlane()
          xform = rs.XformMirror(plane.Origin, plane.Normal)
          rs.TransformObjects( objs, xform, True )
    See Also:
      XformPlanarProjection
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformScale
      XformShear
      XformTranslation
    """
    point = rhutil.coerce3dpoint(mirror_plane_point, True)
    normal = rhutil.coerce3dvector(mirror_plane_normal, True)
    return Rhino.Geometry.Transform.Mirror(point, normal)


def XformMultiply(xform1, xform2):
    """Multiplies two transformation matrices, where result = xform1 * xform2
    Parameters:
      xform1 (transform): List or Rhino.Geometry.Transform.  The first 4x4 transformation matrix to multiply.
      xform2 (transform): List or Rhino.Geometry.Transform.  The second 4x4 transformation matrix to multiply.
    Returns:
      transform: result transformation on success
    Example:
      import rhinoscriptsyntax as rs
      import math
      objs = rs.GetObjects("Select objects to shear")
      if objs:
          cplane = rs.ViewCPlane()
          cob = rs.XformChangeBasis(rs.WorldXYPlane(), cplane)
          shear2d = rs.XformIdentity()
          shear2d[0,2] = math.tan(math.radians(45.0))
          cob_inv = rs.XformChangeBasis(cplane, rs.WorldXYPlane())
          temp = rs.XformMultiply(shear2d, cob)
          xform = rs.XformMultiply(cob_inv, temp)
          rs.TransformObjects( objs, xform, True )
    See Also:
      XformPlanarProjection
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformScale
      XformShear
      XformTranslation
    """
    xform1 = rhutil.coercexform(xform1, True)
    xform2 = rhutil.coercexform(xform2, True)
    return xform1*xform2


def XformPlanarProjection(plane):
    """Returns a transformation matrix that projects to a plane.
    Parameters:
      plane (plane): The plane to project to.
    Returns:
      transform: The 4x4 transformation matrix.
    Example:
      import rhinoscriptsyntax as rs
      objects = rs.GetObjects("Select objects to project")
      if objects:
          cplane = rs.ViewCPlane()
          xform = rs.XformPlanarProjection(cplane)
          rs.TransformObjects( objects, xform, True )
    See Also:
      XformMirror
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformScale
      XformShear
      XformTranslation
    """
    plane = rhutil.coerceplane(plane, True)
    return Rhino.Geometry.Transform.PlanarProjection(plane)


def XformRotation1(initial_plane, final_plane):
    """Returns a rotation transformation that maps initial_plane to final_plane.
    The planes should be right hand orthonormal planes.
    Parameters:
      initial_plane (plane): plane to rotate from
      final_plane (plane): plane to rotate to
    Returns:
      transform: The 4x4 transformation matrix.
      None: on error.
    Example:
    See Also:
    """
    initial_plane = rhutil.coerceplane(initial_plane, True)
    final_plane = rhutil.coerceplane(final_plane, True)
    xform = Rhino.Geometry.Transform.PlaneToPlane(initial_plane, final_plane)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformRotation2(angle_degrees, rotation_axis, center_point):
    """Returns a rotation transformation around an axis
    Parameters:
      angle_degrees (number): rotation angle in degrees
      rotation_axis (vector): rotation axis
      center_point (point): rotation center
    Returns:
      transform: The 4x4 transformation matrix.
      None: on error.
    Example:
    See Also:
    """
    axis = rhutil.coerce3dvector(rotation_axis, True)
    center = rhutil.coerce3dpoint(center_point, True)
    angle_rad = math.radians(angle_degrees)
    xform = Rhino.Geometry.Transform.Rotation(angle_rad, axis, center)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformRotation3( start_direction, end_direction, center_point ):
    """Calculate the minimal transformation that rotates start_direction to
    end_direction while fixing center_point
    Parameters:
      start_direction, end_direction (vector): 3d vectors
      center_point (point): the rotation center
    Returns:
      transform: The 4x4 transformation matrix.
      None: on error.
    Example:
    See Also:
    """
    start = rhutil.coerce3dvector(start_direction, True)
    end = rhutil.coerce3dvector(end_direction, True)
    center = rhutil.coerce3dpoint(center_point, True)
    xform = Rhino.Geometry.Transform.Rotation(start, end, center)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformRotation4(x0, y0, z0, x1, y1, z1):
    """Returns a rotation transformation.
    Parameters:
      x0,y0,z0 (vector): Vectors defining the initial orthonormal frame
      x1,y1,z1 (vector): Vectors defining the final orthonormal frame
    Returns:
      transform: The 4x4 transformation matrix.
      None: on error.
    Example:
    See Also:
    """
    x0 = rhutil.coerce3dvector(x0, True)
    y0 = rhutil.coerce3dvector(y0, True)
    z0 = rhutil.coerce3dvector(z0, True)
    x1 = rhutil.coerce3dvector(x1, True)
    y1 = rhutil.coerce3dvector(y1, True)
    z1 = rhutil.coerce3dvector(z1, True)
    xform = Rhino.Geometry.Transform.Rotation(x0,y0,z0,x1,y1,z1)
    if not xform.IsValid: return scriptcontext.errorhandler()
    return xform


def XformScale(scale, point=None):
    """Creates a scale transformation
    Parameters:
      scale (number|point|vector|[number, number, number]): single number, list of 3 numbers, Point3d, or Vector3d
      point (point, optional): center of scale. If omitted, world origin is used
    Returns:
      transform: The 4x4 transformation matrix on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select objects to scale")
      if objs:
          xform = rs.XformScale( (3.0,1.0,1.0) )
          rs.TransformObjects( objs, xform, True)
    See Also:
      XformMirror
      XformPlanarProjection
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformShear
      XformTranslation
    """
    factor = rhutil.coerce3dpoint(scale)
    if factor is None:
        if type(scale) is int or type(scale) is float:
            factor = (scale,scale,scale)
        if factor is None: return scriptcontext.errorhandler()
    if point: point = rhutil.coerce3dpoint(point, True)
    else: point = Rhino.Geometry.Point3d.Origin
    plane = Rhino.Geometry.Plane(point, Rhino.Geometry.Vector3d.ZAxis);
    xf = Rhino.Geometry.Transform.Scale(plane, factor[0], factor[1], factor[2])
    return xf


def XformScreenToWorld(point, view=None, screen_coordinates=False):
    """Transforms a point from either client-area coordinates of the specified view
    or screen coordinates to world coordinates. The resulting coordinates are represented
    as a 3-D point
    Parameters:
      point (point): 2D point
      view (str, optional): title or identifier of a view. If omitted, the active view is used
      screen_coordinates (bool, optional): if False, point is in client-area coordinates. If True,
      point is in screen-area coordinates
    Returns:
      point: on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      point2d = 200,100
      view = rs.CurrentView()
      point = rs.XformScreenToWorld(point2d, view)
      print(point)
    See Also:
      XformWorldToScreen
    """
    point = rhutil.coerce2dpoint(point, True)
    view = __viewhelper(view)
    viewport = view.MainViewport
    xform = viewport.GetTransform(Rhino.DocObjects.CoordinateSystem.Screen, Rhino.DocObjects.CoordinateSystem.World)
    point3d = Rhino.Geometry.Point3d(point.X, point.Y, 0)
    if screen_coordinates:
        screen = view.ScreenRectangle
        point3d.X = point.X - screen.Left
        point3d.Y = point.Y - screen.Top
    point3d = xform * point3d
    return point3d


def XformShear(plane, x, y, z):
    """Returns a shear transformation matrix
    Parameters:
      plane (plane): plane[0] is the fixed point
      x,y,z (number): each axis scale factor
    Returns:
      transform: The 4x4 transformation matrix on success
    Example:
      import rhinoscriptsyntax as rs
      objects = rs.GetObjects("Select objects to shear")
      if objects:
          cplane = rs.ViewCPlane()
          xform = rs.XformShear(cplane, (1,1,0), (-1,1,0), (0,0,1))
          rs.TransformObjects(objects, xform, True)
    See Also:
      XformMirror
      XformPlanarProjection
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformScale
      XformTranslation
    """
    plane = rhutil.coerceplane(plane, True)
    x = rhutil.coerce3dvector(x, True)
    y = rhutil.coerce3dvector(y, True)
    z = rhutil.coerce3dvector(z, True)
    return Rhino.Geometry.Transform.Shear(plane,x,y,z)


def XformTranslation(vector):
    """Creates a translation transformation matrix
    Parameters:
      vector (vector): List of 3 numbers, Point3d, or Vector3d.  A 3-D translation vector.
    Returns:
      transform: The 4x4 transformation matrix is successful, otherwise None
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select objects to copy")
      if objs:
          xform = rs.XformTranslation([1,0,0])
          rs.TransformObjects( objs, xform, True )
    See Also:
      XformMirror
      XformPlanarProjection
      XformRotation1
      XformRotation2
      XformRotation3
      XformRotation4
      XformScale
      XformShear
    """
    vector = rhutil.coerce3dvector(vector, True)
    return Rhino.Geometry.Transform.Translation(vector)


def XformWorldToCPlane(point, plane):
    """Transforms a point from world coordinates to construction plane coordinates.
    Parameters:
      point (point): A 3D point in world coordinates.
      plane (plane): The construction plane
    Returns:
      (point): 3D point in construction plane coordinates
    Example:
      import rhinoscriptsyntax as rs
      plane = rs.ViewCPlane()
      point = rs.XformWorldToCPlane([0,0,0], plane)
      if point: print("CPlane point:{}".format(point))
    See Also:
      XformCPlaneToWorld
    """
    point = rhutil.coerce3dpoint(point, True)
    plane = rhutil.coerceplane(plane, True)
    v = point - plane.Origin;
    return Rhino.Geometry.Point3d(v*plane.XAxis, v*plane.YAxis, v*plane.ZAxis)


def XformWorldToScreen(point, view=None, screen_coordinates=False):
    """Transforms a point from world coordinates to either client-area coordinates of
    the specified view or screen coordinates. The resulting coordinates are represented
    as a 2D point
    Parameters:
      point (point): 3D point in world coordinates
      view (str, optional): title or identifier of a view. If omitted, the active view is used
      screen_coordinates (bool, optional): if False, the function returns the results as
        client-area coordinates. If True, the result is in screen-area coordinates
    Returns:
      (point): 2D point on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      point = (0.0, 0.0, 0.0)
      view = rs.CurrentView()
      point2d = rs.XformWorldToScreen(point, view)
      print(point2d)
    See Also:
      XformScreenToWorld
    """
    point = rhutil.coerce3dpoint(point, True)
    view = __viewhelper(view)
    viewport = view.MainViewport
    xform = viewport.GetTransform(Rhino.DocObjects.CoordinateSystem.World, Rhino.DocObjects.CoordinateSystem.Screen)
    point = xform * point
    point = Rhino.Geometry.Point2d(point.X, point.Y)
    if screen_coordinates:
        screen = view.ScreenRectangle
        point.X = point.X + screen.Left
        point.Y = point.Y + screen.Top
    return point


def XformZero():
    """Returns a zero transformation matrix
    Returns:
      transform: a zero transformation matrix
    Example:
      import rhinoscriptsyntax as rs
      def printmatrix(xform):
          for i in range(4):
              print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
      printmatrix( rs.XformZero() )
    See Also:
      XformDiagonal
      XformIdentity
    """
    return Rhino.Geometry.Transform()

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/light.py:
--------------------------------------------------------------------------------

```python
import math

import Rhino.Geometry

import scriptcontext

import rhinocompat as compat
from rhinoscript import utility as rhutil


def __coercelight(id, raise_if_missing=False):
    light = rhutil.coercegeometry(id)
    if isinstance(light, Rhino.Geometry.Light): return light
    if raise_if_missing: raise ValueError("unable to retrieve light from %s"%id)


def AddDirectionalLight(start_point, end_point):
    """Adds a new directional light object to the document
    Parameters:
      start_point(point): starting point of the light
      end_point (point): ending point and direction of the light
    Returns:
      (guid): identifier of the new object if successful
    Example:
      import rhinoscriptsyntax as rs
      end = rs.GetPoint("End of light vector direction")
      if end:
          start = rs.GetPoint("Start of light vector direction", end)
          if start: rs.AddDirectionalLight( start, end )
    See Also:
      IsDirectionalLight
    """
    start = rhutil.coerce3dpoint(start_point, True)
    end = rhutil.coerce3dpoint(end_point, True)
    light = Rhino.Geometry.Light()
    light.LightStyle = Rhino.Geometry.LightStyle.WorldDirectional
    light.Location = start
    light.Direction = end-start
    index = scriptcontext.doc.Lights.Add(light)
    if index<0: raise Exception("unable to add light to LightTable")
    rc = scriptcontext.doc.Lights[index].Id
    scriptcontext.doc.Views.Redraw()
    return rc


def AddLinearLight(start_point, end_point, width=None):
    """Adds a new linear light object to the document
    Parameters:
      start_point (point): starting point of the light
      end_point (point): ending point and direction of the light
      width (number): width of the light
    Returns:
      guid: identifier of the new object if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      start = rs.GetPoint("Light origin")
      if start:
          end = rs.GetPoint("Light length and direction", start)
          if end: rs.AddLinearLight(start, end)
    See Also:
      IsLinearLight
    """
    start = rhutil.coerce3dpoint(start_point, True)
    end = rhutil.coerce3dpoint(end_point, True)
    if width is None:
        radius=0.5
        units = scriptcontext.doc.ModelUnitSystem
        if units!=compat.ENUM_NONE(Rhino.UnitSystem):
            scale = Rhino.RhinoMath.UnitScale(Rhino.UnitSystem.Inches, units)
            radius *= scale
        width = radius
    light = Rhino.Geometry.Light()
    light.LightStyle = Rhino.Geometry.LightStyle.WorldLinear
    light.Location = start
    v = end-start
    light.Direction = v
    light.Length = light.Direction
    light.Width = -light.Width
    plane = Rhino.Geometry.Plane(light.Location, light.Direction)
    xaxis = plane.XAxis
    xaxis.Unitize()
    plane.XAxis = xaxis
    light.Width = xaxis * min(width, v.Length/20)
    #light.Location = start - light.Direction
    index = scriptcontext.doc.Lights.Add(light)
    if index<0: raise Exception("unable to add light to LightTable")
    rc = scriptcontext.doc.Lights[index].Id
    scriptcontext.doc.Views.Redraw()
    return rc


def AddPointLight(point):
    """Adds a new point light object to the document
    Parameters:
      point (point): the 3d location of the point
    Returns:
      guid: identifier of the new object if successful
    Example:
      import rhinoscriptsyntax as rs
      point = rs.GetPoint("Point light location")
      if point: rs.AddPointLight(point)
    See Also:
      IsPointLight
    """
    point = rhutil.coerce3dpoint(point, True)
    light = Rhino.Geometry.Light()
    light.LightStyle = Rhino.Geometry.LightStyle.WorldPoint
    light.Location = point
    index = scriptcontext.doc.Lights.Add(light)
    if index<0: raise Exception("unable to add light to LightTable")
    rc = scriptcontext.doc.Lights[index].Id
    scriptcontext.doc.Views.Redraw()
    return rc


def AddRectangularLight(origin, width_point, height_point):
    """Adds a new rectangular light object to the document
    Parameters:
      origin (point): 3d origin point of the light
      width_point (point): 3d width and direction point of the light
      height_point (point): 3d height and direction point of the light
    Returns:
      guid: identifier of the new object if successful
    Example:
      import rhinoscriptsyntax as rs
      rect = rs.GetRectangle(2)
      if rect: rs.AddRectangularLight( rect[0], rect[1], rect[3] )
    See Also:
      IsRectangularLight
    """
    origin = rhutil.coerce3dpoint(origin, True)
    ptx = rhutil.coerce3dpoint(width_point, True)
    pty = rhutil.coerce3dpoint(height_point, True)
    length = pty-origin
    width = ptx-origin
    normal = Rhino.Geometry.Vector3d.CrossProduct(width, length)
    normal.Unitize()
    light = Rhino.Geometry.Light()
    light.LightStyle = Rhino.Geometry.LightStyle.WorldRectangular
    light.Location = origin
    light.Width = width
    light.Length = length
    light.Direction = normal
    index = scriptcontext.doc.Lights.Add(light)
    if index<0: raise Exception("unable to add light to LightTable")
    rc = scriptcontext.doc.Lights[index].Id
    scriptcontext.doc.Views.Redraw()
    return rc


def AddSpotLight(origin, radius, apex_point):
    """Adds a new spot light object to the document
    Parameters:
      origin (point): 3d origin point of the light
      radius (number):  radius of the cone
      apex_point (point): 3d apex point of the light
    Returns:
      guid: identifier of the new object
    Example:
      import rhinoscriptsyntax as rs
      radius = 5.0
      origin = rs.GetPoint("Base of cone")
      if origin:
          apex = rs.GetPoint("End of cone", origin)
          if apex: rs.AddSpotLight(origin, radius, apex)
    See Also:
      IsSpotLight
      SpotLightHardness
      SpotLightShadowIntensity
    """
    origin = rhutil.coerce3dpoint(origin, True)
    apex_point = rhutil.coerce3dpoint(apex_point, True)
    if radius<0: radius=1.0
    light = Rhino.Geometry.Light()
    light.LightStyle = Rhino.Geometry.LightStyle.WorldSpot
    light.Location = apex_point
    light.Direction = origin-apex_point
    light.SpotAngleRadians = math.atan(radius / (light.Direction.Length))
    light.HotSpot = 0.50
    index = scriptcontext.doc.Lights.Add(light)
    if index<0: raise Exception("unable to add light to LightTable")
    rc = scriptcontext.doc.Lights[index].Id
    scriptcontext.doc.Views.Redraw()
    return rc


def EnableLight(object_id, enable=None):
    """Enables or disables a light object
    Parameters:
      object_id (guid): the light object's identifier
      enable (bool, optional): the light's enabled status
    Returns:
      bool: if enable is not specified, the current enabled status
      bool: if enable is specified, the previous enabled status
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select light", rs.filter.light)
      if id: rs.EnableLight( id, False )
    See Also:
      IsLight
      IsLightEnabled
      LightColor
      LightCount
      LightName
      LightObjects
    """
    light = __coercelight(object_id, True)
    rc = light.IsEnabled
    if enable is not None and enable!=rc:
        light.IsEnabled = enable
        id = rhutil.coerceguid(object_id)
        if not scriptcontext.doc.Lights.Modify(id, light):
            return scriptcontext.errorhandler()
        scriptcontext.doc.Views.Redraw()
    return rc


def IsDirectionalLight(object_id):
    """Verifies a light object is a directional light
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsDirectionalLight(id):
          print("The object is a directional light.")
      else:
          print("The object is not a directional light.")
    See Also:
      AddDirectionalLight
    """
    light = __coercelight(object_id, True)
    return light.IsDirectionalLight


def IsLight(object_id):
    """Verifies an object is a light object
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light")
      if rs.IsLight(id):
          print("The object is a light.")
      else:
          print("The object is not a light.")
    See Also:
      EnableLight
      IsLightEnabled
      LightColor
      LightCount
      LightName
      LightObjects
    """
    light = __coercelight(object_id, False)
    return light is not None


def IsLightEnabled(object_id):
    """Verifies a light object is enabled
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsLightEnabled(id):
          print("The light is enabled (on).")
      else:
          print("The light is disabled (off).")
    See Also:
      EnableLight
      IsLight
      LightColor
      LightCount
      LightName
      LightObjects
    """
    light = __coercelight(object_id, True)
    return light.IsEnabled


def IsLightReference(object_id):
    """Verifies a light object is referenced from another file
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsLightReference(id):
          print("The light is a reference object.")
      else:
          print("The light is not a reference object.")
    See Also:
      IsObjectReference
    """
    light = __coercelight(object_id, True)
    return light.IsReference


def IsLinearLight(object_id):
    """Verifies a light object is a linear light
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsLinearLight(id):
          print("The object is a linear light.")
      else:
          print("The object is not a linear light.")
    See Also:
      AddLinearLight
    """
    light = __coercelight(object_id, True)
    return light.IsLinearLight


def IsPointLight(object_id):
    """Verifies a light object is a point light
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsPointLight(id):
          print("The object is a point light.")
      else:
          print("The object is not a point light.")
    See Also:
      AddPointLight
    """
    light = __coercelight(object_id, True)
    return light.IsPointLight


def IsRectangularLight(object_id):
    """Verifies a light object is a rectangular light
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsRectangularLight(id):
          print("The object is a rectangular light.")
      else:
          print("The object is not a rectangular light.")
    See Also:
      AddRectangularLight
    """
    light = __coercelight(object_id, True)
    return light.IsRectangularLight


def IsSpotLight(object_id):
    """Verifies a light object is a spot light
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if rs.IsSpotLight(id):
          print("The object is a spot light.")
      else:
          print("The object is not a spot light.")
    See Also:
      AddSpotLight
      SpotLightHardness
      SpotLightShadowIntensity
    """
    light = __coercelight(object_id, True)
    return light.IsSpotLight


def LightColor(object_id, color=None):
    """Returns or changes the color of a light
    Parameters:
      object_id (guid): the light object's identifier
      color (color, optional): the light's new color
    Returns:
      color: if color is not specified, the current color
      color: if color is specified, the previous color
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: rs.LightColor( id, (0,255,255) )
    See Also:
      EnableLight
      IsLight
      IsLightEnabled
      LightCount
      LightName
      LightObjects
    """
    light = __coercelight(object_id, True)
    rc = light.Diffuse
    if color:
        color = rhutil.coercecolor(color, True)
        if color!=rc:
            light.Diffuse = color
            id = rhutil.coerceguid(object_id, True)
            if not scriptcontext.doc.Lights.Modify(id, light):
                return scriptcontext.errorhandler()
            scriptcontext.doc.Views.Redraw()
    return rc


def LightCount():
    """Returns the number of light objects in the document
    Returns:
      number: the number of light objects in the document
    Example:
      import rhinoscriptsyntax as rs
      print("There are {} lights".format(rs.LightCount()))
    See Also:
      EnableLight
      IsLight
      IsLightEnabled
      LightColor
      LightName
      LightObjects
    """
    return scriptcontext.doc.Lights.Count


def LightDirection(object_id, direction=None):
    """Returns or changes the direction of a light object
    Parameters:
      object_id (guid): the light object's identifier
      direction (vector, optional): the light's new direction
    Returns:
      vector: if direction is not specified, the current direction
      vector: if direction is specified, the previous direction
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: print( rs.LightDirection(id) )
    See Also:
      IsLight
      LightLocation
    """
    light = __coercelight(object_id, True)
    rc = light.Direction
    if direction:
        direction = rhutil.coerce3dvector(direction, True)
        if direction!=rc:
            light.Direction = direction
            id = rhutil.coerceguid(object_id, True)
            if not scriptcontext.doc.Lights.Modify(id, light):
                return scriptcontext.errorhandler()
            scriptcontext.doc.Views.Redraw()
    return rc


def LightLocation(object_id, location=None):
    """Returns or changes the location of a light object
    Parameters:
      object_id (guid): the light object's identifier
      location (point, optional): the light's new location
    Returns:
      point: if location is not specified, the current location
      point: if location is specified, the previous location
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: rs.AddPoint( rs.LightLocation(id) )
    See Also:
      IsLight
      LightDirection
    """
    light = __coercelight(object_id, True)
    rc = light.Location
    if location:
        location = rhutil.coerce3dpoint(location, True)
        if location!=rc:
            light.Location = location
            id = rhutil.coerceguid(object_id, True)
            if not scriptcontext.doc.Lights.Modify(id, light):
                return scriptcontext.errorhandler()
            scriptcontext.doc.Views.Redraw()
    return rc


def LightName(object_id, name=None):
    """Returns or changes the name of a light object
    Parameters:
      object_id (guid): the light object's identifier
      name (str, optional): the light's new name
    Returns:
      str: if name is not specified, the current name
      str: if name is specified, the previous name
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id:
          name = rs.GetString("New light name")
          if name: rs.LightName(id, name)
    See Also:
      EnableLight
      IsLight
      IsLightEnabled
      LightColor
      LightCount
      LightObjects
    """
    light = __coercelight(object_id, True)
    rc = light.Name
    if name and name!=rc:
        light.Name = name
        id = rhutil.coerceguid(object_id, True)
        if not scriptcontext.doc.Lights.Modify(id, light):
            return scriptcontext.errorhandler()
        scriptcontext.doc.Views.Redraw()
    return rc


def LightObjects():
    """Returns list of identifiers of light objects in the document
    Returns:
      list(guid, ...): the list of identifiers of light objects in the document
    Example:
      import rhinoscriptsyntax as rs
      lights = rs.LightObjects()
      if lights:
          rs.AddLayer( "Lights" )
          for light in lights: rs.ObjectLayer( light, "Lights" )
    See Also:
      EnableLight
      IsLight
      IsLightEnabled
      LightColor
      LightCount
      LightName
    """
    count = scriptcontext.doc.Lights.Count
    rc = []
    for i in range(count):
        rhlight = scriptcontext.doc.Lights[i]
        if not rhlight.IsDeleted: rc.append(rhlight.Id)
    return rc


def RectangularLightPlane(object_id):
    """Returns the plane of a rectangular light object
    Parameters:
      object_id (guid): the light object's identifier
    Returns:
      plane: the plane if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a rectangular light", rs.filter.light)
      if id:
          rc = rs.RectangularLightPlane(id)
          if rc:
              plane, extents = rc
              rs.AddPlaneSurface( plane, extents[0], extents[1] )
    See Also:
      IsRectangularLight
    """
    light = __coercelight(object_id, True)
    if light.LightStyle!=Rhino.Geometry.LightStyle.WorldRectangular:
        return scriptcontext.errorhandler()
    location = light.Location
    length = light.Length
    width = light.Width
    direction = light.Direction
    plane = Rhino.Geometry.Plane(location, length, width)
    return plane, (length.Length, width.Length)


def SpotLightHardness(object_id, hardness=None):
    """Returns or changes the hardness of a spot light. Spotlight hardness
    controls the fully illuminated region.
    Parameters:
      object_id (guid): the light object's identifier
      hardness (number, optional): the light's new hardness
    Returns:
      number: if hardness is not specified, the current hardness
      number: if hardness is specified, the previous hardness
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: rs.SpotLightHardness(id, 0.75)
    See Also:
      AddSpotLight
      IsSpotLight
      SpotLightRadius
      SpotLightShadowIntensity
    """
    light = __coercelight(object_id, True)
    if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
        return scriptcontext.errorhandler()
    rc = light.HotSpot
    if hardness and hardness!=rc:
        light.HotSpot = hardness
        id = rhutil.coerceguid(object_id, True)
        if not scriptcontext.doc.Lights.Modify(id, light):
            return scriptcontext.errorhandler()
        scriptcontext.doc.Views.Redraw()
    return rc


def SpotLightRadius(object_id, radius=None):
    """Returns or changes the radius of a spot light.
    Parameters:
      object_id (guid): the light object's identifier
      radius (number, optional): the light's new radius
    Returns:
      number: if radius is not specified, the current radius
      number: if radius is specified, the previous radius
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: rs.SpotLightRadius(id, 5.0)
    See Also:
      AddSpotLight
      IsSpotLight
      SpotLightHardness
      SpotLightShadowIntensity
    """
    light = __coercelight(object_id, True)
    if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
        return scriptcontext.errorhandler()
    radians = light.SpotAngleRadians
    rc = light.Direction.Length * math.tan(radians)
    if radius and radius!=rc:
        radians = math.atan(radius/light.Direction.Length)
        light.SpotAngleRadians = radians
        id = rhutil.coerceguid(object_id, True)
        if not scriptcontext.doc.Lights.Modify(id, light):
            return scriptcontext.errorhandler()
        scriptcontext.doc.Views.Redraw()
    return rc


def SpotLightShadowIntensity(object_id, intensity=None):
    """Returns or changes the shadow intensity of a spot light.
    Parameters:
      object_id (guid): the light object's identifier
      intensity (number, optional): the light's new intensity
    Returns:
      number: if intensity is not specified, the current intensity
      number: if intensity is specified, the previous intensity
    Example:
      import rhinoscriptsyntax as rs
      id = rs.GetObject("Select a light", rs.filter.light)
      if id: rs.SpotLightShadowIntensity(id, 0.75)
    See Also:
      AddSpotLight
      IsSpotLight
      SpotLightHardness
      SpotLightRadius
    """
    light = __coercelight(object_id, True)
    if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
        return scriptcontext.errorhandler()
    rc = light.SpotLightShadowIntensity
    if intensity and intensity!=rc:
        light.SpotLightShadowIntensity = intensity
        id = rhutil.coerceguid(object_id, True)
        if not scriptcontext.doc.Lights.Modify(id, light):
            return scriptcontext.errorhandler()
        scriptcontext.doc.Views.Redraw()
    return rc

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/block.py:
--------------------------------------------------------------------------------

```python
import math

import System

import Rhino

import scriptcontext

from rhinoscript import utility as rhutil


def __InstanceObjectFromId(id, raise_if_missing):
    rhobj = rhutil.coercerhinoobject(id, True, raise_if_missing)
    if isinstance(rhobj, Rhino.DocObjects.InstanceObject): return rhobj
    if raise_if_missing: raise ValueError("unable to find InstanceObject")


def AddBlock(object_ids, base_point, name=None, delete_input=False):
    """Adds a new block definition to the document
    Parameters:
      object_ids ([guid, ....]) objects that will be included in the block
      base_point (point): 3D base point for the block definition
      name (str, optional): name of the block definition. If omitted a name will be
        automatically generated
      delete_input (bool): if True, the object_ids will be deleted
    Returns:
      str: name of new block definition on success
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select objects to define block")
      if objs:
          point = rs.GetPoint("Block base point")
          if point:
              block = rs.AddBlock(objs, point, None, True)
              rs.InsertBlock(block, point)
    See Also:
      InsertBlock
    """
    base_point = rhutil.coerce3dpoint(base_point, True)
    if not name:
        name = scriptcontext.doc.InstanceDefinitions.GetUnusedInstanceDefinitionName()
    found = scriptcontext.doc.InstanceDefinitions.Find(name)
    objects = []
    for id in object_ids:
        obj = rhutil.coercerhinoobject(id, True)
        if obj.IsReference: return
        ot = obj.ObjectType
        if ot==Rhino.DocObjects.ObjectType.Light: return
        if ot==Rhino.DocObjects.ObjectType.Grip: return
        if ot==Rhino.DocObjects.ObjectType.Phantom: return
        if ot==Rhino.DocObjects.ObjectType.InstanceReference and found:
            uses, nesting = obj.UsesDefinition(found.Index)
            if uses: return
        objects.append(obj)
    if objects:
        geometry = [obj.Geometry for obj in objects]
        attrs = [obj.Attributes for obj in objects]
        rc = 0
        if found:
          rc = scriptcontext.doc.InstanceDefinitions.ModifyGeometry(found.Index, geometry, attrs)
        else:
          rc = scriptcontext.doc.InstanceDefinitions.Add(name, "", base_point, geometry, attrs)
        if rc>=0:
            if delete_input:
                for obj in objects: scriptcontext.doc.Objects.Delete(obj, True)
            scriptcontext.doc.Views.Redraw()
    return name


def BlockContainerCount(block_name):
    """Returns number of block definitions that contain a specified
    block definition
    Parameters:
      block_name (str): the name of an existing block definition
    Returns:
      number: the number of block definitions that contain a specified block definition
    Example:
      import rhinoscriptscriptsyntax as rs
      block = rs.GetString("Block name to query")
      if rs.IsBlock(block):
          count = rs.BlockContainerCount(block)
          print("This block is nested in {} block(s).".format(count))
    See Also:
      BlockContainers
      IsBlock
    """
    return len(BlockContainers(block_name))


def BlockContainers(block_name):
    """Returns names of the block definitions that contain a specified block
    definition.
    Parameters:
      block_name (str): the name of an existing block definition
    Returns:
      list(str, ...): A list of block definition names
    Example:
      import rhinoscriptsyntax as rs
      blockname = rs.GetString("Block name to query")
      if rs.IsBlock(blockname):
          blocks = rs.BlockContainers(blockname)
          for block in blocks: print(block)
    See Also:
      BlockContainerCount
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    containers = idef.GetContainers()
    rc = []
    for item in containers:
        if not item.IsDeleted: rc.append(item.Name)
    return rc


def BlockCount():
    """Returns the number of block definitions in the document
    Returns:
      number: the number of block definitions in the document
    Example:
      import rhinoscriptsyntax as rs
      count = rs.BlockCount()
      print("There are {} blocks".format(count)
    See Also:
      BlockNames
      IsBlock
    """
    return scriptcontext.doc.InstanceDefinitions.ActiveCount


def BlockDescription(block_name, description=None):
    """Returns or sets the description of a block definition
    Parameters:
      block_name (str): the name of an existing block definition
      description (str, optional): The new description.
    Returns:
      str: if description is not specified, the current description
      str: if description is specified, the previous description
    Example:
      import rhinoscriptsyntax as rs
      blockname = rs.GetString("Block name to list description")
      if rs.IsBlock(blockname):
          desc = rs.BlockDescription(blockname)
          if desc is None: print("No description")
          else: print(desc)
    See Also:
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    rc = idef.Description
    if description: scriptcontext.doc.InstanceDefinitions.Modify( idef, idef.Name, description, True )
    return rc


def BlockInstanceCount(block_name,where_to_look=0):
    """Counts number of instances of the block in the document.
    Nested instances are not included in the count.
    Parameters:
      block_name (str): the name of an existing block definition
      where_to_look (number, optional):
        0 = get top level references in active document.
        1 = get top level and nested references in active document.
        2 = check for references from other instance definitions
    Returns:
      number: the number of instances of the block in the document
    Example:
      import rhinoscriptsyntax as rs
      blockname = rs.GetString("Block to count")
      if rs.IsBlock(blockname):
          count = rs.BlockInstanceCount(blockname)
          print("{} block(s) found.".format(count))
    See Also:
      BlockInstanceInsertPoint
      BlockInstances
      BlockInstanceXform
      IsBlockInstance
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    refs = idef.GetReferences(where_to_look)
    return len(refs)


def BlockInstanceInsertPoint(object_id):
    """Returns the insertion point of a block instance.
    Parameters:
      object_id (guid): The identifier of an existing block insertion object
    Returns:
      point: The insertion 3D point if successful
    Example:
      import rhinoscriptsyntax as rs
      strObject = rs.GetObject("Select block")
      if rs.IsBlockInstance(strObject):
          rs.AddPoint( rs.BlockInstanceInsertPoint(strObject) )
    See Also:
      BlockInstanceCount
      BlockInstances
      BlockInstanceXform
      IsBlockInstance
    """
    instance = __InstanceObjectFromId(object_id, True)
    xf = instance.InstanceXform
    pt = Rhino.Geometry.Point3d.Origin
    pt.Transform(xf)
    return pt


def BlockInstanceName(object_id):
    """Returns the block name of a block instance
    Parameters:
      object_id (guid): The identifier of an existing block insertion object
    Returns:
      str: the block name of a block instance
    Example:
      import rhinoscriptsyntax as rs
      strObject = rs.GetObject("Select block")
      if rs.IsBlockInstance(strObject):
          print(rs.BlockInstanceName(strObject))
    See Also:
      BlockInstanceCount
      BlockInstances
      BlockInstanceXform
      IsBlockInstance
    """
    instance = __InstanceObjectFromId(object_id, True)
    idef = instance.InstanceDefinition
    return idef.Name


def BlockInstances(block_name,where_to_look=0):
    """Returns the identifiers of the inserted instances of a block.
    Parameters:
      block_name (str): the name of an existing block definition
      where_to_look (number, optional):
        0 = get top level references in active document.
        1 = get top level and nested references in active document.
        2 = check for references from other instance definitions
    Returns:
      list(guid, ...): Ids identifying the instances of a block in the model.
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block to select")
      if rs.IsBlock(strBlock):
          arrObjects = rs.BlockInstances(strBlock)
          if arrobjects:
              rs.SelectObjects(arrObjects)
    See Also:
      BlockInstanceCount
      BlockInstanceInsertPoint
      BlockInstanceXform
      IsBlockInstance
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    instances = idef.GetReferences(where_to_look)
    return [item.Id for item in instances]


def BlockInstanceXform(object_id):
    """Returns the location of a block instance relative to the world coordinate
    system origin (0,0,0). The position is returned as a 4x4 transformation
    matrix
    Parameters:
      object_id (guid): The identifier of an existing block insertion object
    Returns:
      transform: the location, as a transform matrix, of a block instance relative to the world coordinate
    system origin
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select block to query")
      if rs.IsBlockInstance(obj):
          arrMatrix = rs.BlockInstanceXform(obj)
          if arrMatrix is not None:
              pointId = rs.AddPoint([0,0,0])
              rs.TransformObject( pointId, arrMatrix)
    See Also:
      BlockInstanceCount
      BlockInstanceInsertPoint
      BlockInstances
      IsBlockInstance
    """
    instance = __InstanceObjectFromId(object_id, True)
    return instance.InstanceXform


def BlockNames( sort=False ):
    """Returns the names of all block definitions in the document
    Parameters:
      sort (bool): True to return a sorted list
    Returns:
      list(str, ...): the names of all block definitions in the document
    Example:
      import rhinoscriptsyntax as rs
      names = rs.BlockNames(True)
      if names:
          for name in names: print(name)
    See Also:
      BlockCount
      IsBlock
    """
    ideflist = scriptcontext.doc.InstanceDefinitions.GetList(True)
    rc = [item.Name for item in ideflist]
    if(sort): rc.sort()
    return rc


def BlockObjectCount(block_name):
    """Returns number of objects that make up a block definition
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      number: the number of objects that make up a block definition
    Example:
      import rhinoscriptsyntax as rs
      count = rs.BlockObjectCount()
      print("There are {} blocks".format(count))
    See Also:
      BlockNames
      BlockObjects
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    return idef.ObjectCount


def BlockObjects(block_name):
    """Returns identifiers of the objects that make up a block definition
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      list(guid, ...): list of identifiers on success
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name to list identifiers")
      if rs.IsBlock(strBlock):
          objects = rs.BlockObjects(strBlock)
          if objects:
              for item in objects: print(item)
    See Also:
      BlockNames
      BlockObjectCount
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    rhobjs = idef.GetObjects()
    return [obj.Id for obj in rhobjs]


def BlockPath(block_name):
    """Returns path to the source of a linked or embedded block definition.
    A linked or embedded block definition is a block definition that was
    inserted from an external file.
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      str: path to the linked block on success
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name to list path")
      if rs.IsBlockEmbedded(strBlock):
          print(rs.BlockPath(strBlock))
    See Also:
      IsBlock
      IsBlockEmbedded
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    return idef.SourceArchive


def BlockStatus(block_name):
    """Returns the status of a linked block
    Parameters:
        block_name (str): Name of an existing block
    Returns:
      number: the status of a linked block
        Value Description
        -3    Not a linked block definition.
        -2    The linked block definition's file could not be opened or could not be read.
        -1    The linked block definition's file could not be found.
         0    The linked block definition is up-to-date.
         1    The linked block definition's file is newer than definition.
         2    The linked block definition's file is older than definition.
         3    The linked block definition's file is different than definition.
    Example:
      import rhinoscriptsyntax as rs
      block = rs.GetString("Block name to list description")
      if rs.IsBlock(block):
          status = rs.BlockStatus(block)
          print("block status for {} is {}".format(block, status))
    See Also:
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: return -3
    return int(idef.ArchiveFileStatus)


def DeleteBlock(block_name):
    """Deletes a block definition and all of it's inserted instances.
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name to delete")
      if rs.IsBlock(strBlock):
          rs.DeleteBlock(strBlock)
    See Also:
      BlockNames
      ExplodeBlockInstance
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    rc = scriptcontext.doc.InstanceDefinitions.Delete(idef.Index, True, False)
    scriptcontext.doc.Views.Redraw()
    return rc


def ExplodeBlockInstance(object_id, explode_nested_instances=False):
    """Explodes a block instance into it's geometric components. The
    exploded objects are added to the document
    Parameters:
      object_id (guid): The identifier of an existing block insertion object
      explode_nested_instances (bool, optional): By default nested blocks are not exploded.
    Returns:
      list(guid, ...): identifiers for the newly exploded objects on success
    Example:
      import rhinoscriptsyntax as rs
      strObject = rs.GetObject("Select block instance to explode")
      if rs.IsBlockInstance(strObject):
          rs.ExplodeBlockInstance(strObject)
    See Also:
      DeleteBlock
      IsBlockInstance
    """
    instance = __InstanceObjectFromId(object_id, True)
    guids = scriptcontext.doc.Objects.AddExplodedInstancePieces(instance, explodeNestedInstances=explode_nested_instances, deleteInstance=True)
    if guids:
      scriptcontext.doc.Views.Redraw()
    return guids


def InsertBlock( block_name, insertion_point, scale=(1,1,1), angle_degrees=0, rotation_normal=(0,0,1) ):
    """Inserts a block whose definition already exists in the document
    Parameters:
      block_name (str): name of an existing block definition
      insertion_point (point): insertion point for the block
      scale ({number, number, number]): x,y,z scale factors
      angle_degrees (number, optional): rotation angle in degrees
      rotation_normal (vector, optional): the axis of rotation.
    Returns:
      guid: id for the block that was added to the doc
    Example:
    See Also:
    """
    insertion_point = rhutil.coerce3dpoint(insertion_point, True)
    rotation_normal = rhutil.coerce3dvector(rotation_normal, True)
    angle_radians = math.radians(angle_degrees)
    trans = Rhino.Geometry.Transform
    move = trans.Translation(insertion_point[0],insertion_point[1],insertion_point[2])
    scale = trans.Scale(Rhino.Geometry.Plane.WorldXY, scale[0], scale[1], scale[2])
    rotate = trans.Rotation(angle_radians, rotation_normal, Rhino.Geometry.Point3d.Origin)
    xform = move * scale * rotate
    return InsertBlock2( block_name, xform )


def InsertBlock2(block_name, xform):
    """Inserts a block whose definition already exists in the document
    Parameters:
      block_name (str): name of an existing block definition
      xform (transform): 4x4 transformation matrix to apply
    Returns:
      guid: id for the block that was added to the doc on success
    Example:
    See Also:
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    xform = rhutil.coercexform(xform, True)
    id = scriptcontext.doc.Objects.AddInstanceObject(idef.Index, xform )
    if id!=System.Guid.Empty:
        scriptcontext.doc.Views.Redraw()
        return id


def IsBlock(block_name):
    """Verifies the existence of a block definition in the document.
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name")
      if rs.IsBlock(strBlock):
          print("The block definition exists.")
      else:
          print("The block definition does not exist.")
    See Also:
      IsBlockEmbedded
      IsBlockInstance
      IsBlockInUse
      IsBlockReference
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    return (idef is not None)


def IsBlockEmbedded(block_name):
    """Verifies a block definition is embedded, or linked, from an external file.
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name")
      if rs.IsBlock(strBlock):
          if rs.IsBlockEmbedded(strBlock):
              print("The block definition is embedded.")
          else:
              print("The block definition is not embedded.")
      else:
          print("The block definition does not exist.")
    See Also:
      IsBlock
      IsBlockInstance
      IsBlockInUse
      IsBlockReference
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    ut = Rhino.DocObjects.InstanceDefinitionUpdateType
    return (idef.UpdateType==ut.Embedded or idef.UpdateType==ut.Static or idef.UpdateType==ut.LinkedAndEmbedded)


def IsBlockInstance(object_id):
    """Verifies an object is a block instance
    Parameters:
      object_id (guid): The identifier of an existing block insertion object
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select block instance")
      if rs.IsBlockInstance(obj):
          print("The object is a block instance.")
      else:
          print("The object is not a block instance.")
    See Also:
      IsBlock
      IsBlockEmbedded
      IsBlockInUse
      IsBlockReference
    """
    return  __InstanceObjectFromId(object_id, False) is not None


def IsBlockInUse(block_name, where_to_look=0):
    """Verifies that a block definition is being used by an inserted instance
    Parameters:
      block_name (str): name of an existing block definition
      where_to_look (number, optional): One of the following values
           0 = Check for top level references in active document
           1 = Check for top level and nested references in active document
           2 = Check for references in other instance definitions
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name")
      if rs.IsBlock(strBlock):
          if rs.IsBlockInUse(strBlock):
              print("The block definition is in use.")
          else:
              print("The block definition is not in use.")
      else:
          print("The block definition does not exist.")
    See Also:
      IsBlock
      IsBlockInstance
      IsBlockEmbedded
      IsBlockReference
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    return idef.InUse(where_to_look)


def IsBlockReference(block_name):
    """Verifies that a block definition is from a reference file.
    Parameters:
      block_name (str): name of an existing block definition
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      strBlock = rs.GetString("Block name")
      if rs.IsBlock(strBlock):
          if rs.IsBlockReference(strBlock):
              print("The block definition is a reference definition.")
          else:
              print("The block definition is not a reference definition.")
      else:
          print("The block definition does not exist.")
    See Also:
      IsBlock
      IsBlockEmbedded
      IsBlockInUse
      IsBlockInstance
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    return idef.IsReference


def RenameBlock( block_name, new_name ):
    """Renames an existing block definition
    Parameters:
      block_name (str): name of an existing block definition
      new_name (str): name to change to
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      strOldBlock = rs.GetString("Old block name")
      if strOldBlock:
          strNewBlock = rs.GetString("New block name")
          if strNewBlock:
              rs.RenameBlock (strOldBlock, strNewBlock)
    See Also:
      BlockNames
      IsBlock
    """
    idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
    if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
    description = idef.Description
    rc = scriptcontext.doc.InstanceDefinitions.Modify(idef, new_name, description, False)
    return rc

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/pointvector.py:
--------------------------------------------------------------------------------

```python
import math

import Rhino

import scriptcontext

from rhinoscript import utility as rhutil


def IsVectorParallelTo(vector1, vector2):
    """Compares two vectors to see if they are parallel
    Parameters:
      vector1, vector2 (vector): the vectors to compare
    Returns:
    number: the value represents
            -1 = the vectors are anti-parallel
             0 = the vectors are not parallel
             1 = the vectors are parallel
    Example:
      import rhinoscriptsyntax as rs
      vector1 = (1,0,0)
      vector2 = (0,1,0)
      print(rs.IsVectorParallelTo( vector1, vector2 ))
    See Also:
      IsVectorPerpendicularTo
      IsVectorTiny
      IsVectorZero
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1.IsParallelTo(vector2)


def IsVectorPerpendicularTo(vector1, vector2):
    """Compares two vectors to see if they are perpendicular
    Parameters:
      vector1, vector2 (vector): the vectors to compare
    Returns:
      bool: True if vectors are perpendicular, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      vector1 = (1,0,0)
      vector2 = (0,1,0)
      print(rs.IsVectorPerpendicularTo( vector1, vector2 ))
    See Also:
      IsVectorParallelTo
      IsVectorTiny
      IsVectorZero
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1.IsPerpendicularTo(vector2)


def IsVectorTiny(vector):
    """Verifies that a vector is very short. The X,Y,Z elements are <= 1.0e-12
    Parameters:
      vector (vector): the vector to check
    Returns:
      bool: True if the vector is tiny, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      pt1 = rs.GetPoint("First point")
      pt2 = rs.GetPoint("Next point")
      vector = pt2 - pt1
      if rs.IsVectorTiny(vector):
          print("The vector is tiny.")
      else:
          print("The vector is not tiny.")
    See Also:
      IsVectorZero
      VectorCreate
    """
    vector = rhutil.coerce3dvector(vector, True)
    return vector.IsTiny( 1.0e-12 )


def IsVectorZero(vector):
    """Verifies that a vector is zero, or tiny. The X,Y,Z elements are equal to 0.0
    Parameters:
      vector (vector): the vector to check
    Returns:
      bool: True if the vector is zero, otherwise False
    Example:
      import rhinoscriptsyntax as rs
      pt1 = rs.GetPoint("First point")
      pt2 = rs.GetPoint("Next point")
      vector = pt2 - pt1
      if rs.IsVectorZero(vector):
          print("The vector is zero.")
      else:
          print("The vector is not zero.")
    See Also:
      IsVectorTiny
      VectorCreate
    """
    vector = rhutil.coerce3dvector(vector, True)
    return vector.IsZero


def PointAdd(point1, point2):
    """Adds a 3D point or a 3D vector to a 3D point
    Parameters:
      point1, point2 (point): the points to add
    Returns:
      point: the resulting 3D point if successful
    Example:
      import rhinoscriptsyntax as rs
      point1 = (1,1,1)
      point2 = (2,2,2)
      point = rs.PointAdd(point1, point2)
      print(point)
    See Also:
      PointCompare
      PointDivide
      PointScale
      PointSubtract
      PointTransform
    """
    point1 = rhutil.coerce3dpoint(point1, True)
    point2 = rhutil.coerce3dpoint(point2, True)
    return point1+point2


def PointArrayClosestPoint(points, test_point):
    """Finds the point in a list of 3D points that is closest to a test point
    Parameters:
      points ([point, ...]): list of points
      test_point (point): the point to compare against
    Returns:
      number: index of the element in the point list that is closest to the test point
    Example:
      import rhinoscriptsyntax as rs
      cloud = rs.GetObject("Select point cloud")
      if cloud:
          point = rs.GetPoint("Point to test")
          if point:
              cloud = rs.PointCloudPoints(cloud)
              index = rs.PointArrayClosestPoint(cloud, point)
              if index is not None:
                  point_id = rs.AddPoint(cloud[index])
                  rs.SelectObject( point_id )
    See Also:
      CurveClosestPoint
      SurfaceClosestPoint
    """
    points = rhutil.coerce3dpointlist(points, True)
    test_point = rhutil.coerce3dpoint(test_point, True)
    index = Rhino.Collections.Point3dList.ClosestIndexInList(points, test_point)
    if index>=0: return index


def PointArrayTransform(points, xform):
    """Transforms a list of 3D points
    Parameters:
      points ([point, ...]): list of 3D points
      xform (transform): transformation to apply
    Returns:
      list(point, ...): transformed points on success
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Select object")
      points = rs.BoundingBox(obj)
      xform = rs.XformRotation2(45.0, (0,0,1), (0,0,0))
      points = rs.PointArrayTransform(points, xform)
      rs.AddPoints(points)
    See Also:
      PointArrayClosestPoint
    """
    points = rhutil.coerce3dpointlist(points, True)
    xform = rhutil.coercexform(xform, True)
    return [xform*point for point in points]


def PointClosestObject(point, object_ids):
    """Finds the object that is closest to a test point
    Parameters:
      point (point): point to test
      object_id ([guid, ...]): identifiers of one or more objects
    Returns:
      list(guid, point): closest [0] object_id and [1] point on object on success
      None: on failure
    Example:
      import rhinoscriptsyntax as rs
      objs = rs.GetObjects("Select target objects for closest point", 63)
      if objs:
          point = rs.GetPoint("Test point")
          if point:
              results = rs.PointClosestObject(point, objs)
              if results:
                  print("Object id:{}".format(results[0]))
                  rs.AddPoint( results[1] )
    See Also:
      CurveClosestObject
    """
    object_ids = rhutil.coerceguidlist(object_ids)
    point = rhutil.coerce3dpoint(point, True)
    closest = None
    for id in object_ids:
        geom = rhutil.coercegeometry(id, True)
        point_geometry = geom
        if isinstance(point_geometry, Rhino.Geometry.Point):
            distance = point.DistanceTo( point_geometry.Location )
            if closest is None or distance<closest[0]:
                closest = distance, id, point_geometry.Location
            continue
        point_cloud = geom
        if isinstance(point_cloud, Rhino.Geometry.PointCloud):
            index = point_cloud.ClosestPoint(point)
            if index>=0:
                distance = point.DistanceTo( point_cloud[index].Location )
                if closest is None or distance<closest[0]:
                    closest = distance, id, point_cloud[index].Location
            continue
        curve = geom
        if isinstance(curve, Rhino.Geometry.Curve):
            rc, t = curve.ClosestPoint(point)
            if rc:
                distance = point.DistanceTo( curve.PointAt(t) )
                if closest is None or distance<closest[0]:
                    closest = distance, id, curve.PointAt(t)
            continue
        brep = geom
        if isinstance(brep, Rhino.Geometry.Brep):
            brep_closest = brep.ClosestPoint(point)
            distance = point.DistanceTo( brep_closest )
            if closest is None or distance<closest[0]:
                closest = distance, id, brep_closest
            continue
        mesh = geom
        if isinstance(mesh, Rhino.Geometry.Mesh):
            mesh_closest = mesh.ClosestPoint(point)
            distance = point.DistanceTo( mesh_closest )
            if closest is None or distance<closest[0]:
                closest = distance, id, mesh_closest
            continue
    if closest: return closest[1], closest[2]


def PointCompare(point1, point2, tolerance=None):
    """Compares two 3D points
    Parameters:
      point1, point2 (point): the points to compare
      tolerance (number, optional): tolerance to use for comparison. If omitted,
                                    Rhino's internal zero tolerance is used
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      point1 = (1,1,1)
      point2 = (2,2,2)
      print(rs.PointCompare(point1, point2))
    See Also:
      PointAdd
      PointDivide
      PointScale
      PointSubtract
      PointTransform
    """
    point1 = rhutil.coerce3dpoint(point1, True)
    point2 = rhutil.coerce3dpoint(point2, True)
    if tolerance is None: tolerance = Rhino.RhinoMath.ZeroTolerance
    vector = point2-point1
    return vector.IsTiny(tolerance)


def PointDivide(point, divide):
    """Divides a 3D point by a value
    Parameters:
      point (point): the point to divide
      divide (number): a non-zero value to divide
    Returns:
      point: resulting point
    Example:
      import rhinoscriptsyntax as rs
      point = rs.PointDivide([5,5,0], 5)
      print(point)
    See Also:
      PointAdd
      PointCompare
      PointScale
      PointSubtract
      PointTransform
    """
    point = rhutil.coerce3dpoint(point, True)
    return point/divide


def PointsAreCoplanar(points, tolerance=1.0e-12):
    """Verifies that a list of 3D points are coplanar
    Parameters:
      points ([point, ...]): 3D points to test
      tolerance (number, optional): tolerance to use when verifying
    Returns:
      bool: True or False
    Example:
      import rhinoscriptsyntax as rs
      def SurfacesAreCoplanar(srf1, srf2):
          if( not rs.IsSurface(srf1) or not rs.IsSurface(srf2) ): return False
          if( not rs.IsSurfacePlanar(srf1) or not rs.IsSurfacePlanar(srf2) ): return False
          pts1 = rs.SurfacePoints(srf1)
          pts2 = rs.SurfacePoints(srf2)
          if( pts1==None or pts2==None ): return False
          pts1.extend(pts2)
          return rs.PointsAreCoplanar(pts1)
       
      x = rs.GetObject( "First surface to test", rs.filter.surface)
      y = rs.GetObject( "Second surface to test", rs.filter.surface)
      print(SurfacesAreCoplanar(x, y))
    See Also:
      IsPoint
      IsPointCloud
      PointCoordinates
    """
    points = rhutil.coerce3dpointlist(points, True)
    return Rhino.Geometry.Point3d.ArePointsCoplanar(points, tolerance)


def PointScale(point, scale):
    """Scales a 3D point by a value
    Parameters:
      point (point): the point to divide
      scale (number): scale factor to apply
    Returns:
      point: resulting point on success
    Example:
      import rhinoscriptsyntax as rs
      point = rs.PointScale([1,0,0], 5)
      print(point)
    See Also:
      PointAdd
      PointCompare
      PointDivide
      PointSubtract
      PointTransform
    """
    point = rhutil.coerce3dpoint(point, True)
    return point*scale


def PointSubtract(point1, point2):
    """Subtracts a 3D point or a 3D vector from a 3D point
    Parameters:
      point1, point2 (point): the points to subtract
    Returns:
      point: the resulting 3D point if successful
    Example:
      import rhinoscriptsyntax as rs
      point1 = (1,1,1)
      point2 = (2,2,2)
      point = rs.PointSubtract(point1, point2)
      print(point)
    See Also:
      PointAdd
      PointCompare
      PointDivide
      PointScale
      PointTransform
    """
    point1 = rhutil.coerce3dpoint(point1, True)
    point2 = rhutil.coerce3dpoint(point2, True)
    v = point1-point2
    return Rhino.Geometry.Point3d(v)

  
def PointTransform(point, xform):
    """Transforms a 3D point
    Parameters:
      point (point): the point to transform
      xform (transform): a valid 4x4 transformation matrix
    Returns:
      point: transformed point on success
    Example:
      # Translate (move) objects by (10,10,0)
      import rhinoscriptsyntax as rs
      point = 5,5,0
      matrix = rs.XformTranslation((10,10,0))
      result = rs.PointTransform(point, matrix)
      print(result)
    See Also:
      PointAdd
      PointCompare
      PointDivide
      PointScale
      PointSubtract
    """
    point = rhutil.coerce3dpoint(point, True)
    xform = rhutil.coercexform(xform, True)
    return xform*point


def ProjectPointToMesh(points, mesh_ids, direction):
    """Projects one or more points onto one or more meshes
    Parameters:
      points ([point, ...]): one or more 3D points
      mesh_ids ([guid, ...]): identifiers of one or more meshes
      direction (vector): direction vector to project the points
    Returns:
     list(point, ...): projected points on success
    Example:
      import rhinoscriptsyntax as rs
      mesh = rs.GetObject("Select mesh to project onto", rs.filter.mesh)
      objects = rs.GetObjects("Select points to project", rs.filter.point)
      points = [rs.PointCoordinates(obj) for obj in objects]
      # project down...
      results = rs.ProjectPointToMesh(points, mesh, (0,0,-1))
      rs.AddPoints( results )
    See Also:
      ProjectCurveToMesh
      ProjectCurveToSurface
      ProjectPointToSurface
    """
    pts = rhutil.coerce3dpointlist(points, False)
    if pts is None:
        pts = [rhutil.coerce3dpoint(points, True)]
    direction = rhutil.coerce3dvector(direction, True)
    id = rhutil.coerceguid(mesh_ids, False)
    if id: mesh_ids = [id]
    meshes = [rhutil.coercemesh(id, True) for id in mesh_ids]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    rc = Rhino.Geometry.Intersect.Intersection.ProjectPointsToMeshes(meshes, pts, direction, tolerance)
    return rc


def ProjectPointToSurface(points, surface_ids, direction):
    """Projects one or more points onto one or more surfaces or polysurfaces
    Parameters:
      points ([point, ...]): one or more 3D points
      surface_ids ([guid, ...]): identifiers of one or more surfaces/polysurfaces
      direction (vector): direction vector to project the points
    Returns:
     list(point, ...): projected points on success
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface to project onto", rs.filter.surface)
      objects = rs.GetObjects("Select points to project", rs.filter.point)
      points = [rs.PointCoordinates(obj) for obj in objects]
      # Project down...
      results = rs.ProjectPointToSurface(points, surface, (0,0,-1))
      rs.AddPoints(results)
    See Also:
      ProjectCurveToMesh
      ProjectCurveToSurface
      ProjectPointToMesh
    """
    pts = rhutil.coerce3dpointlist(points)
    if pts is None:
        pts = [rhutil.coerce3dpoint(points, True)]
    direction = rhutil.coerce3dvector(direction, True)
    id = rhutil.coerceguid(surface_ids, False)
    if id: surface_ids = [id]
    breps = [rhutil.coercebrep(id, True) for id in surface_ids]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    return Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(breps, pts, direction, tolerance)


def PullPoints(object_id, points):
    """Pulls an array of points to a surface or mesh object. For more
    information, see the Rhino help file Pull command
    Parameters:
      object_id (guid): the identifier of the surface or mesh object that pulls
      points ([point, ...]): list of 3D points
    Returns:
      list(point, ...): 3D points pulled onto surface or mesh
    Example:
      import rhinoscriptsyntax as rs
      surface = rs.GetObject("Select surface that pulls", rs.filter.surface)
      objects = rs.GetObjects("Select points to pull", rs.filter.point)
      points = [rs.PointCoordinates(obj) for obj in objects]
      results = rs.PullPoints( surface, points )
      rs.AddPoints( results )
    See Also:
      PullCurve
    """
    id = rhutil.coerceguid(object_id, True)
    points = rhutil.coerce3dpointlist(points, True)
    mesh = rhutil.coercemesh(id, False)
    if mesh:
        points = mesh.PullPointsToMesh(points)
        return list(points)
    brep = rhutil.coercebrep(id, False)
    if brep and brep.Faces.Count==1:
        tolerance = scriptcontext.doc.ModelAbsoluteTolerance
        points = brep.Faces[0].PullPointsToFace(points, tolerance)
        return list(points)
    return []


def VectorAdd(vector1, vector2):
    """Adds two 3D vectors
    Parameters:
      vector1, vector2 (vector): the vectors to add
    Returns:
      vector: the resulting 3D vector if successful
    Example:
      import rhinoscriptsyntax as rs
      vector1 = (1,0,0)
      vector2 = (0,1,0)
      vector = rs.VectorAdd(vector1, vector2)
      print(vector)
    See Also:
      VectorCreate
      VectorScale
      VectorSubtract
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1+vector2


def VectorAngle(vector1, vector2):
    """Returns the angle, in degrees, between two 3-D vectors
    Parameters:
      vector1 (vector): The first 3-D vector.
      vector2 (vector): The second 3-D vector.
    Returns:
      number: The angle in degrees if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      s0 = rs.GetObject("Surface 0", rs.filter.surface)
      s1 = rs.GetObject("Surface 1", rs.filter.surface)
      du0 = rs.SurfaceDomain(s0, 0)
      dv0 = rs.SurfaceDomain(s0, 1)
      du1 = rs.SurfaceDomain(s1, 0)
      dv1 = rs.SurfaceDomain(s1, 1)
      n0 = rs.SurfaceNormal(s0, (du0[0], dv0[0]))
      n1 = rs.SurfaceNormal(s1, (du1[0], dv1[0]))
      print(rs.VectorAngle(n0, n1))
      print(rs.VectorAngle(n0, rs.VectorReverse(n1)))
    See Also:
      Angle
      Angle2
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    vector1 = Rhino.Geometry.Vector3d(vector1.X, vector1.Y, vector1.Z)
    vector2 = Rhino.Geometry.Vector3d(vector2.X, vector2.Y, vector2.Z)
    if not vector1.Unitize() or not vector2.Unitize():
        raise ValueError("unable to unitize vector")
    dot = vector1 * vector2
    dot = rhutil.clamp(-1,1,dot)
    radians = math.acos(dot)
    return math.degrees(radians)


def VectorCompare(vector1, vector2):
    """Compares two 3D vectors
    Parameters:
      vector1, vector2 (vector): the two vectors to compare
    Returns:
      number: result of comparing the vectors.
              -1 if vector1 is less than vector2
              0 if vector1 is equal to vector2
              1 if vector1 is greater than vector2
    Example:
      import rhinoscriptsyntax as rs
      vector1 = (1,0,0)
      vector2 = (0,1,0)
      rc = rs.VectorCompare(vector1 , vector2)
      print(rc)
    See Also:
      IsVectorTiny
      IsVectorZero
      VectorCreate
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1.CompareTo(vector2)


def VectorCreate(to_point, from_point):
    """Creates a vector from two 3D points
    Parameters:
      to_point, from_point (point): the points defining the vector
    Returns:
      vector: the resulting vector if successful
    Example:
      import rhinoscriptsyntax as rs
      point1 = rs.GetPoint("First point")
      point2 = rs.GetPoint("Next point")
      vector = rs.VectorCreate(point2, point1)
      print(vector)
    See Also:
      IsVectorTiny
      IsVectorZero
      VectorCompare
      VectorUnitize
    """
    to_point = rhutil.coerce3dpoint(to_point, True)
    from_point = rhutil.coerce3dpoint(from_point, True)
    return to_point-from_point


def VectorCrossProduct(vector1, vector2):
    """Calculates the cross product of two 3D vectors
    Parameters:
      vector1, vector2 (vector): the vectors to perform cross product on
    Returns:
      vector: the resulting cross product direction if successful
    Example:
      import rhinoscriptsyntax as rs
      vector1 = (1,0,0)
      vector2 = (0,1,0)
      vector = rs.VectorCrossProduct(vector1, vector2)
      print(vector)
    See Also:
      VectorDotProduct
      VectorUnitize
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return Rhino.Geometry.Vector3d.CrossProduct( vector1, vector2 )


def VectorDivide(vector, divide):
    """Divides a 3D vector by a value
    Parameters:
      vector (vector): the vector to divide
      divide (number): a non-zero value to divide
    Returns:
      vector: resulting vector on success
    Example:
      import rhinoscriptsyntax as rs
      vector = rs.VectorDivide((5,5,0), 5)
      print(vector)
    See Also:
      VectorAdd
      VectorCreate
      VectorSubtract
    """
    vector = rhutil.coerce3dvector(vector, True)
    return vector/divide


def VectorDotProduct(vector1, vector2):
    """Calculates the dot product of two 3D vectors
    Parameters:
      vector1, vector2 (vector): the vectors to perform the dot product on
    Returns:
      vector: the resulting dot product if successful
    Example:
      import rhinoscriptsyntax as rs
      vector1 = [1,0,0]
      vector2 = [0,1,0]
      dblDotProduct = rs.VectorDotProduct(vector1, vector2)
      print(dblDotProduct)
    See Also:
      VectorCrossProduct
      VectorUnitize
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1*vector2


def VectorLength(vector):
    """Returns the length of a 3D vector
    Parameters:
      vector (vector):  The 3-D vector.
    Returns:
      number: The length of the vector if successful, otherwise None
    Example:
      import rhinoscriptsyntax as rs
      point1 = rs.GetPoint("First point")
      point2 = rs.GetPoint("Next point")
      vector = rs.VectorCreate(point1, point2)
      print(rs.VectorLength(vector))
    See Also:
      VectorAdd
      VectorCreate
      VectorSubtract
      VectorUnitize
    """
    vector = rhutil.coerce3dvector(vector, True)
    return vector.Length


def VectorMultiply(vector1, vector2):
    """Multiplies two 3D vectors
    Parameters:
      vector1, vector2 (vector): the vectors to multiply
    Returns:
      vector: the resulting inner (dot) product if successful
    Example:
      import rhinoscriptsyntax as rs
      product = rs.VectorMultiply( [2,2,2], [3,3,3] )
      print(product)
    See Also:
      VectorAdd
      VectorCreate
      VectorSubtract
    """
    return VectorDotProduct(vector1, vector2)


def VectorReverse(vector):
    """Reverses the direction of a 3D vector
    Parameters:
      vector (vector): the vector to reverse
    Returns:
      vector: reversed vector on success
    Example:
      import rhinoscriptsyntax as rs
      vector = rs.VectorReverse([1,0,0])
      print(vector)
    See Also:
      VectorCreate
      VectorUnitize
    """
    vector = rhutil.coerce3dvector(vector, True)
    rc = Rhino.Geometry.Vector3d(vector.X, vector.Y, vector.Z)
    rc.Reverse()
    return rc


def VectorRotate(vector, angle_degrees, axis):
    """Rotates a 3D vector
    Parameters:
      vector (vector): the vector to rotate
      angle_degrees (number): rotation angle
      axis (vector): axis of rotation
    Returns:
      vector: rotated vector on success
    Example:
      import rhinoscriptsyntax as rs
      vector = rs.VectorRotate([1,0,0], 90.0, [0,0,1])
      print(vector)
    See Also:
      VectorCreate
      VectorScale
    """
    vector = rhutil.coerce3dvector(vector, True)
    axis = rhutil.coerce3dvector(axis, True)
    angle_radians = Rhino.RhinoMath.ToRadians(angle_degrees)
    rc = Rhino.Geometry.Vector3d(vector.X, vector.Y, vector.Z)
    if rc.Rotate(angle_radians, axis): return rc


def VectorScale(vector, scale):
    """Scales a 3-D vector
    Parameters:
      vector (vector): the vector to scale
      scale (number): scale factor to apply
    Returns:
      vector: resulting vector on success
    Example:
      import rhinoscriptsyntax as rs
      vector = rs.VectorScale([1,0,0], 5)
      print(vector)
    See Also:
      VectorAdd
      VectorCreate
      VectorSubtract
    """
    vector = rhutil.coerce3dvector(vector, True)
    return vector*scale


def VectorSubtract(vector1, vector2):
    """Subtracts two 3D vectors
    Parameters:
      vector1 (vector): the vector to subtract from
      vector2 (vector): the vector to subtract
    Returns:
      vector: the resulting 3D vector
    Example:
      import rhinoscriptsyntax as rs
      vector1 = [1,0,0]
      vector2 = [0,1,0]
      vector = rs.VectorSubtract(vector1, vector2)
      print(vector)
    See Also:
      VectorAdd
      VectorCreate
      VectorScale
    """
    vector1 = rhutil.coerce3dvector(vector1, True)
    vector2 = rhutil.coerce3dvector(vector2, True)
    return vector1-vector2


def VectorTransform(vector, xform):
    """Transforms a 3D vector
    Parameters:
      vector (vector): the vector to transform
      xform (transform): a valid 4x4 transformation matrix
    Returns:
      vector: transformed vector on success
    Example:
      import rhinoscriptsyntax as rs
      vector = (1,0,0) #world x-axis
      xform = rs.XformRotation2(90.0, (0,0,1), (0,0,0))
      vector = rs.VectorTransform(vector, xform)
      print(vector)
    See Also:
      IsVectorZero
      VectorCreate
      VectorUnitize
    """
    vector = rhutil.coerce3dvector(vector, True)
    xform = rhutil.coercexform(xform, True)
    return xform*vector


def VectorUnitize(vector):
    """Unitizes, or normalizes a 3D vector. Note, zero vectors cannot be unitized
    Parameters:
      vector (vector): the vector to unitize
    Returns:
      vector: unitized vector on success
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      vector = rs.VectorUnitize( [1.5,-4.1,3.6] )
      print(vector)
    See Also:
      IsVectorZero
      VectorCreate
    """
    vector = rhutil.coerce3dvector(vector, True)
    rc = Rhino.Geometry.Vector3d(vector.X, vector.Y, vector.Z)
    if rc.Unitize(): return rc


def PointArrayBoundingBox(points, view_or_plane=None, in_world_coords=True):
    """Returns either a world axis-aligned or a construction plane axis-aligned 
    bounding box of an array of 3-D point locations.
    Parameters:
      points ([point, ...]): A list of 3-D points
      view_or_plane (str|plane, optional): Title or id of the view that contains the
          construction plane to which the bounding box should be aligned -or-
          user defined plane. If omitted, a world axis-aligned bounding box
          will be calculated
      in_world_coords (bool, optional): return the bounding box as world coordinates or
          construction plane coordinates. Note, this option does not apply to
          world axis-aligned bounding boxes.
    Returns:
      list(point, ....): Eight points that define the bounding box. Points returned in counter-
      clockwise order starting with the bottom rectangle of the box.
      None: on error
    Example:
      
    See Also:
      BoundingBox
    """
    points = rhutil.coerce3dpointlist(points)
    if not points:
      return None
    bbox = Rhino.Geometry.BoundingBox(points)

    xform = None
    plane = rhutil.coerceplane(view_or_plane)
    if plane is None and view_or_plane:
        view = view_or_plane
        modelviews = scriptcontext.doc.Views.GetStandardRhinoViews()
        for item in modelviews:
            viewport = item.MainViewport
            if type(view) is str and viewport.Name==view:
                plane = viewport.ConstructionPlane()
                break
            elif type(view) is System.Guid and viewport.Id==view:
                plane = viewport.ConstructionPlane()
                break
        if plane is None: return scriptcontext.errorhandler()
    if plane:
        xform = Rhino.Geometry.Transform.ChangeBasis(Rhino.Geometry.Plane.WorldXY, plane)
        bbox = xform.TransformBoundingBox(bbox)
    if not bbox.IsValid: return scriptcontext.errorhandler()

    corners = list(bbox.GetCorners())
    if in_world_coords and plane is not None:
        plane_to_world = Rhino.Geometry.Transform.ChangeBasis(plane, Rhino.Geometry.Plane.WorldXY)
        for pt in corners: pt.Transform(plane_to_world)
    return corners

```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/layer.py:
--------------------------------------------------------------------------------

```python
import System

import Rhino
from Rhino.DocObjects import Layer
from Rhino import RhinoMath

import scriptcontext

from rhinoscript import utility as rhutil


def __getlayer(name_or_id, raise_if_missing):
    if not name_or_id: raise TypeError("Parameter must be a string or Guid")
    id = rhutil.coerceguid(name_or_id)
    if id:
        layer = scriptcontext.doc.Layers.FindId(id)
    else:
        name = name_or_id
        layer_index = scriptcontext.doc.Layers.FindByFullPath(name, RhinoMath.UnsetIntIndex)
        if layer_index != RhinoMath.UnsetIntIndex: return scriptcontext.doc.Layers[layer_index]
        layer = scriptcontext.doc.Layers.FindName(name)
    if layer: return layer
    if raise_if_missing: raise ValueError("%s does not exist in LayerTable" % name_or_id)


def AddLayer(name=None, color=None, visible=True, locked=False, parent=None):
    """Add a new layer to the document
    Parameters:
      name (str, optional): The name of the new layer. If omitted, Rhino automatically
          generates the layer name.
      color (color): A Red-Green-Blue color value. If omitted, the color Black is assigned.
      visible (bool optional): layer's visibility
      locked (bool, optional): layer's locked state
      parent (str, optional): name of the new layer's parent layer. If omitted, the new
          layer will not have a parent layer.
    Returns:
      str: The full name of the new layer if successful.
    Example:
      import rhinoscriptsyntax as rs
      from System.Drawing import Color
      print("New layer:{}".format(rs.AddLayer()))
      print("New layer:{}".format(rs.AddLayer("MyLayer1")))
      print("New layer:{}".format(rs.AddLayer("MyLayer2", Color.DarkSeaGreen)))
      print("New layer:{}".format(rs.AddLayer("MyLayer3", Color.Cornsilk)))
      print("New layer:{}".format(rs.AddLayer("MyLayer4",parent="MyLayer3")))
    See Also:
      CurrentLayer
      DeleteLayer
      RenameLayer
    """
    names = ['']
    if name:
      if not isinstance(name, str): name = str(name)
      names = [n for n in name.split("::") if name]
      
    last_parent_index = -1
    last_parent = None
    for idx, name in enumerate(names):
      layer = Rhino.DocObjects.Layer.GetDefaultLayerProperties()

      if idx == 0:
        if parent:
          last_parent = __getlayer(parent, True)
      else:
        if last_parent_index != -1:
          last_parent = scriptcontext.doc.Layers[last_parent_index]

      if last_parent:
        layer.ParentLayerId = last_parent.Id
      if name:
        layer.Name = name
        
      color = rhutil.coercecolor(color)
      if color: layer.Color = color
      layer.IsVisible = visible
      layer.IsLocked = locked
    
      last_parent_index = scriptcontext.doc.Layers.Add(layer)
      if last_parent_index == -1:
        full_path = layer.Name
        if last_parent:
            full_path = last_parent.FullPath + "::" + full_path
        last_parent_index = scriptcontext.doc.Layers.FindByFullPath(full_path, RhinoMath.UnsetIntIndex)
    return scriptcontext.doc.Layers[last_parent_index].FullPath


def CurrentLayer(layer=None):
    """Returns or changes the current layer
    Parameters:
      layer (guid): the name or Guid of an existing layer to make current
    Returns:
      str: If a layer name is not specified, the full name of the current layer
      str: If a layer name is specified, the full name of the previous current layer
    Example:
      import rhinoscriptsyntax as rs
      rs.AddLayer("MyLayer")
      rs.CurrentLayer("MyLayer")
    See Also:
      AddLayer
      DeleteLayer
      RenameLayer
    """
    rc = scriptcontext.doc.Layers.CurrentLayer.FullPath
    if layer:
        layer = __getlayer(layer, True)
        scriptcontext.doc.Layers.SetCurrentLayerIndex(layer.LayerIndex, True)
    return rc


def DeleteLayer(layer):
    """Removes an existing layer from the document. The layer to be removed
    cannot be the current layer. Unlike the PurgeLayer method, the layer must
    be empty, or contain no objects, before it can be removed. Any layers that
    are children of the specified layer will also be removed if they are also
    empty.
    Parameters:
      layer (str|guid): the name or id of an existing empty layer
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer to remove")
      if layer: rs.DeleteLayer(layer)
    See Also:
      AddLayer
      CurrentLayer
      PurgeLayer
      RenameLayer
    """
    layer = __getlayer(layer, True)
    return scriptcontext.doc.Layers.Delete( layer.LayerIndex, True)


def ExpandLayer( layer, expand ):
    """Expands a layer. Expanded layers can be viewed in Rhino's layer dialog
    Parameters:
      layer (str): name of the layer to expand
      expand (bool): True to expand, False to collapse
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      if rs.IsLayerExpanded("Default"):
          rs.ExpandLayer( "Default", False )
    See Also:
      IsLayerExpanded
    """
    layer = __getlayer(layer, True)
    if layer.IsExpanded==expand: return False
    layer.IsExpanded = expand
    return True


def IsLayer(layer):
    """Verifies the existance of a layer in the document
    Parameters:
      layer (str|guid): the name or id of a layer to search for
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          print("The layer exists.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayerChangeable
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, False)
    return layer is not None


def IsLayerChangeable(layer):
    """Verifies that the objects on a layer can be changed (normal)
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerChangeable(layer): print("The layer is changeable.")
          else: print("The layer is not changeable.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    rc = layer.IsVisible and not layer.IsLocked
    return rc


def IsLayerChildOf(layer, test):
    """Verifies that a layer is a child of another layer
    Parameters:
      layer (str|guid): the name or id of the layer to test against
      test (str|guid): the name or id to the layer to test
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      rs.AddLayer("MyLayer1")
      rs.AddLayer("MyLayer2", parent="MyLayer1")
      rs.AddLayer("MyLayer3", parent="MyLayer2")
      rs.MessageBox( rs.IsLayerChildOf("MyLayer1", "MyLayer3") )
    See Also:
      IsLayerParentOf
    """
    layer = __getlayer(layer, True)
    test = __getlayer(test, True)
    return test.IsChildOf(layer)


def IsLayerCurrent(layer):
    """Verifies that a layer is the current layer
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerCurrent(layer): print("The layer is current.")
          else: print("The layer is not current.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    return layer.LayerIndex == scriptcontext.doc.Layers.CurrentLayerIndex


def IsLayerEmpty(layer):
    """Verifies that an existing layer is empty, or contains no objects
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerEmpty(layer): print("The layer is empty.")
          else: print("The layer is not empty.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayerChangeable
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    rhobjs = scriptcontext.doc.Objects.FindByLayer(layer)
    if not rhobjs: return True
    return False


def IsLayerExpanded(layer):
    """Verifies that a layer is expanded. Expanded layers can be viewed in
    Rhino's layer dialog
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      if rs.IsLayerExpanded("Default"):
          rs.ExpandLayer( "Default", False )
    See Also:
      ExpandLayer
    """
    layer = __getlayer(layer, True)
    return layer.IsExpanded   


def IsLayerLocked(layer):
    """Verifies that a layer is locked.
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      cool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerLocked(layer): print("The layer is locked.")
          else: print("The layer is not locked.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerChangeable
      IsLayerEmpty
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    return layer.IsLocked


def IsLayerOn(layer):
    """Verifies that a layer is on.
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerOn(layer): print("The layer is on.")
          else: print("The layer is not on.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerChangeable
      IsLayerEmpty
      IsLayerLocked
      IsLayerReference
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    return layer.IsVisible


def IsLayerSelectable(layer):
    """Verifies that an existing layer is selectable (normal and reference)
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerSelectable(layer): print("The layer is selectable.")
          else: print("The layer is not selectable.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerChangeable
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    return layer.IsVisible and not layer.IsLocked


def IsLayerParentOf(layer, test):
    """Verifies that a layer is a parent of another layer
    Parameters:
      layer (str|guid): the name or id of the layer to test against
      test (str|guid): the name or id to the layer to test
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      rs.AddLayer("MyLayer1")
      rs.AddLayer("MyLayer2", parent="MyLayer1")
      rs.AddLayer("MyLayer3", parent="MyLayer2")
      rs.MessageBox( rs.IsLayerParentOf("MyLayer3", "MyLayer1") )
    See Also:
      IsLayerChildOf
    """
    layer = __getlayer(layer, True)
    test = __getlayer(test, True)
    return test.IsParentOf(layer)


def IsLayerReference(layer):
    """Verifies that a layer is from a reference file.
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerReference(layer): print("The layer is a reference layer.")
          else: print("The layer is not a reference layer.")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerChangeable
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerSelectable
      IsLayerVisible
    """
    layer = __getlayer(layer, True)
    return layer.IsReference


def IsLayerVisible(layer):
    """Verifies that a layer is visible (normal, locked, and reference)
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      bool: True on success otherwise False
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer name")
      if rs.IsLayer(layer):
          if rs.IsLayerVisible(layer): print("The layer is visible")
          else: print("The layer is not visible")
      else:
          print("The layer does not exist.")
    See Also:
      IsLayer
      IsLayerChangeable
      IsLayerEmpty
      IsLayerLocked
      IsLayerOn
      IsLayerReference
      IsLayerSelectable
    """
    layer = __getlayer(layer, True)
    return layer.IsVisible


def LayerChildCount(layer):
    """Returns the number of immediate child layers of a layer
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      number: the number of immediate child layers if successful
    Example:
      import rhinoscriptsyntax as rs
      children = rs.LayerChildCount("Default")
      if children: rs.ExpandLayer("Default", True)
    See Also:
      LayerChildren
    """
    layer = __getlayer(layer, True)
    children = layer.GetChildren()
    if children: return len(children)
    return 0


def LayerChildren(layer):
    """Returns the immediate child layers of a layer
    Parameters:
      layer (str|guid): the name or id of an existing layer
    Returns:
      list(str, ...): List of children layer names
    Example:
      import rhinoscriptsyntax as rs
      children = rs.LayerChildren("Default")
      if children:
          for child in children: print(child)
    See Also:
      LayerChildCount
      ParentLayer
    """
    layer = __getlayer(layer, True)
    children = layer.GetChildren()
    if children: return [child.FullPath for child in children]
    return [] #empty list


def LayerColor(layer, color=None):
    """Returns or changes the color of a layer.
    Parameters:
      layer (str|guid): name or id of an existing layer
      color (color): the new color value. If omitted, the current layer color is returned.
    Returns:
      color: If a color value is not specified, the current color value on success
      color: If a color value is specified, the previous color value on success
    Example:
      import rhinoscriptsyntax as rs
      import random
      from System.Drawing import Color
       
      def randomcolor():
          red = int(255*random.random())
          green = int(255*random.random())
          blue = int(255*random.random())
          return Color.FromArgb(red,green,blue)
       
      layerNames = rs.LayerNames()
      if layerNames:
          for name in layerNames: rs.LayerColor(name, randomcolor())
    See Also:
      
    """
    layer = __getlayer(layer, True)
    rc = layer.Color
    if color:
        color = rhutil.coercecolor(color)
        if color is not None:
          layer.Color = color
          scriptcontext.doc.Views.Redraw()
    return rc


def LayerCount():
    """Returns the number of layers in the document
    Returns:
      number: the number of layers in the document
    Example:
      import rhinoscriptsyntax as rs
      count = rs.LayerCount()
      print("There are {} layers".format(count))
    See Also:
      LayerNames
    """
    return scriptcontext.doc.Layers.ActiveCount


def LayerIds():
    """Return identifiers of all layers in the document
    Returns:
      list(guid, ...): the identifiers of all layers in the document
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerIds()
      for layer in layers: print(layer)
    See Also:
      LayerCount
      LayerNames
    """
    return [layer.Id for layer in scriptcontext.doc.Layers if not layer.IsDeleted]


def LayerLinetype(layer, linetype=None):
    """Returns or changes the linetype of a layer
    Parameters:
      layer (str): name of an existing layer
      linetype (str, optional): name of a linetype
    Returns:
      str: If linetype is not specified, name of the current linetype
      str: If linetype is specified, name of the previous linetype
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers:
              if rs.LayerLinetype(layer)!="Continuous":
                  rs.LayerLinetype(layer,"Continuous")
    See Also:
      LayerPrintColor
      LayerPrintWidth
    """
    layer = __getlayer(layer, True)
    index = layer.LinetypeIndex
    rc = scriptcontext.doc.Linetypes[index].Name
    if linetype:
        if not isinstance(linetype, str): linetype = str(linetype)
        if linetype == scriptcontext.doc.Linetypes.ContinuousLinetypeName:
          index = -1
        else:
          lt = scriptcontext.doc.Linetypes.FindName(linetype)
          if lt == None: return scriptcontext.errorhandler()
          index = lt.LinetypeIndex
        layer.LinetypeIndex = index
        scriptcontext.doc.Views.Redraw()
    return rc


def LayerLocked(layer, locked=None):
    """Returns or changes the locked mode of a layer
    Parameters:
      layer (str): name of an existing layer
      locked (bool, optional): new layer locked mode
    Returns:
      bool: If locked is not specified, the current layer locked mode
      bool: If locked is specified, the previous layer locked mode
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers:
              if rs.LayerLocked(layer): rs.LayerLocked(layer, False)
    See Also:
      LayerVisible
    """
    layer = __getlayer(layer, True)
    rc = layer.IsLocked 
    if locked!=None and locked!=layer.GetPersistentLocking():
        layer.IsLocked = locked
        layer.SetPersistentLocking(locked)
        scriptcontext.doc.Views.Redraw()
    return rc


def LayerMaterialIndex(layer,index=None):
    """Returns or changes the material index of a layer. A material index of -1
    indicates that no material has been assigned to the layer. Thus, the layer
    will use Rhino's default layer material
    Parameters:
      layer (str):  name of existing layer
      index (number, optional): the new material index
    Returns:
      number: a zero-based material index if successful
    Example:
      import rhinoscriptsyntax as rs
      index = rs.LayerMaterialIndex("Default")
      if index is not None:
          if index==-1:
              print("The default layer does not have a material assigned.")
          else:
              print("The default layer has a material assigned.")
    See Also:
      
    """
    layer = __getlayer(layer, True)
    rc = layer.RenderMaterialIndex
    if index is not None and index>=-1:
        layer.RenderMaterialIndex = index
        scriptcontext.doc.Views.Redraw()
    return rc


def LayerId(layer):
    """Returns the identifier of a layer given the layer's name.
    Parameters:
      layer (str): name of existing layer
    Returns:
      guid (str): The layer's identifier if successful.
      None: If not successful, or on error.
    Example:
      import rhinoscriptsyntax as  rs
      id = rs.LayerId('Layer 01')
    See Also:
      LayerName
    """
    idx = scriptcontext.doc.Layers.FindByFullPath(layer, RhinoMath.UnsetIntIndex)
    return str(scriptcontext.doc.Layers[idx].Id) if idx != RhinoMath.UnsetIntIndex else None


def LayerName(layer_id, fullpath=True):
    """Return the name of a layer given it's identifier
    Parameters:
      layer_id (guid): layer identifier
      fullpath (bool, optional): return the full path name `True` or short name `False`
    Returns:
      str: the layer's name if successful
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerIds()
      if layers:
          for layer in layers: print(rs.LayerName(layer))
    See Also:
      LayerId
    """
    layer = __getlayer(layer_id, True)
    if fullpath: return layer.FullPath
    return layer.Name


def LayerNames(sort=False):
    """Returns the names of all layers in the document.
    Parameters:
      sort (bool, optional): return a sorted list of the layer names
    Returns:
      list(str, ...): list of layer names
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers: print(layer)
    See Also:
      LayerCount
    """
    rc = []
    for layer in scriptcontext.doc.Layers:
        if not layer.IsDeleted: rc.append(layer.FullPath)
    if sort: rc.sort()
    return rc


def LayerOrder(layer):
    """Returns the current display order index of a layer as displayed in Rhino's
    layer dialog box. A display order index of -1 indicates that the current
    layer dialog filter does not allow the layer to appear in the layer list
    Parameters:
      layer (str): name of existing layer
    Returns:
      number: 0 based index of layer
    Example:
      import rhinoscriptsyntax as rs
      index = rs.LayerOrder("Default")
      if index is not None:
          if index==-1: print("The layer does not display in the Layer dialog.")
          else: print("The layer does display in the Layer dialog.")
    See Also:
      
    """
    layer = __getlayer(layer, True)
    return layer.SortIndex


def LayerPrintColor(layer, color=None):
    """Returns or changes the print color of a layer. Layer print colors are
    represented as RGB colors.
    Parameters:
      layer (str): name of existing layer
      color (color): new print color
    Returns:
      color: if color is not specified, the current layer print color
      color: if color is specified, the previous layer print color
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers:
              black = rs.CreateColor((0,0,0))
              if rs.LayerPrintColor(layer)!=black:
                  rs.LayerPrintColor(layer, black)
    See Also:
      LayerLinetype
      LayerPrintWidth
    """
    layer = __getlayer(layer, True)
    rc = layer.PlotColor
    if color:
        color = rhutil.coercecolor(color)
        layer.PlotColor = color
        scriptcontext.doc.Views.Redraw()
    return rc


def LayerPrintWidth(layer, width=None):
    """Returns or changes the print width of a layer. Print width is specified
    in millimeters. A print width of 0.0 denotes the "default" print width.
    Parameters:
      layer (str): name of existing layer
      width (number, optional): new print width
    Returns:
      number: if width is not specified, the current layer print width
      number: if width is specified, the previous layer print width
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers:
              if rs.LayerPrintWidth(layer)!=0:
                  rs.LayerPrintWidth(layer, 0)
    See Also:
      LayerLinetype
      LayerPrintColor
    """
    layer = __getlayer(layer, True)
    rc = layer.PlotWeight
    if width is not None and width!=rc:
        layer.PlotWeight = width
        scriptcontext.doc.Views.Redraw()
    return rc


def LayerVisible(layer, visible=None, forcevisible_or_donotpersist=False):
    """Returns or changes the visible property of a layer.
    Parameters:
      layer (str): name of existing layer
      visible (bool, optional): new visible state
      forcevisible_or_donotpersist (bool, optional): if visible is True then turn parent layers on if True.  If visible is False then do not persist if True
    Returns:
      bool: if visible is not specified, the current layer visibility
      bool: if visible is specified, the previous layer visibility
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
          for layer in layers:
              if rs.LayerVisible(layer)==False:
                  rs.LayerVisible(layer,True)
    See Also:
      LayerLocked
    """
    layer = __getlayer(layer, True)
    rc = layer.IsVisible
    if visible is not None:
        layer.IsVisible = visible
        if visible and forcevisible_or_donotpersist:
            scriptcontext.doc.Layers.ForceLayerVisible(layer.Id)
        if not visible and not forcevisible_or_donotpersist:
          if layer.ParentLayerId != System.Guid.Empty:
            layer.SetPersistentVisibility(visible)
        scriptcontext.doc.Views.Redraw()
    return rc


def ParentLayer(layer, parent=None):
    """Return or modify the parent layer of a layer
    Parameters:
      layer (str): name of an existing layer
      parent (str, optional):  name of new parent layer. To remove the parent layer,
        thus making a root-level layer, specify an empty string
    Returns:
      str: If parent is not specified, the name of the current parent layer
      str: If parent is specified, the name of the previous parent layer
      None: if the layer does not have a parent
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      for layer in layers:
          parent = rs.ParentLayer(layer)
          print("Layer: {}, Parent: {}".format(layer, parent))
    See Also:
      LayerChildren
    """
    layer = __getlayer(layer, True)
    parent_id = layer.ParentLayerId
    oldparent = None
    if parent_id!=System.Guid.Empty:
        oldparentlayer = scriptcontext.doc.Layers.Find(parent_id, True, -1)
        if oldparentlayer is not None:
            oldparentlayer = scriptcontext.doc.Layers[oldparentlayer]
            oldparent = oldparentlayer.FullPath
    if parent is None: return oldparent
    if parent=="":
        layer.ParentLayerId = System.Guid.Empty
    else:
        parent = __getlayer(parent, True)
        layer.ParentLayerId = parent.Id
    return oldparent


def PurgeLayer(layer):
    """Removes an existing layer from the document. The layer will be removed
    even if it contains geometry objects. The layer to be removed cannot be the
    current layer
    empty.
    Parameters:
      layer (str|guid): the name or id of an existing empty layer
    Returns:
      bool: True or False indicating success or failure
    Example:
      import rhinoscriptsyntax as rs
      layer = rs.GetString("Layer to purge")
      if layer: rs.PurgeLayer(layer)
    See Also:
      AddLayer
      CurrentLayer
      DeleteLayer
      RenameLayer
    """
    layer = __getlayer(layer, True)
    rc = scriptcontext.doc.Layers.Purge( layer.LayerIndex, True)
    scriptcontext.doc.Views.Redraw()
    return rc


def RenameLayer(oldname, newname):
    """Renames an existing layer
    Parameters:
      oldname (str): original layer name
      newname (str): new layer name
    Returns: 
      str: The new layer name if successful otherwise None
    Example:
      import rhinoscriptsyntax as rs
      oldname = rs.GetString("Old layer name")
      if oldname:
          newname = rs.GetString("New layer name")
          if newname: rs.RenameLayer(oldname, newname)
    See Also:
      AddLayer
      CurrentLayer
      DeleteLayer
    """
    if oldname and newname:
        layer = __getlayer(oldname, True)
        layer.Name = newname
        return newname

```
Page 2/7FirstPrevNextLast