This is page 2 of 8. Use http://codebase.md/jingcheng-chen/rhinomcp?format=md&lines=true&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_plugin/RhinoMCPServer.cs:
--------------------------------------------------------------------------------

```csharp
  1 | ﻿using System;
  2 | using System.Collections.Generic;
  3 | using System.Linq;
  4 | using System.Net;
  5 | using System.Net.Sockets;
  6 | using System.Text;
  7 | using System.Threading;
  8 | using System.Threading.Tasks;
  9 | using Rhino;
 10 | using Rhino.Commands;
 11 | using Rhino.Geometry;
 12 | using Rhino.Input;
 13 | using Rhino.Input.Custom;
 14 | using Rhino.UI;
 15 | using Newtonsoft.Json;
 16 | using Newtonsoft.Json.Linq;
 17 | using static System.Runtime.InteropServices.JavaScript.JSType;
 18 | using System.Text.Json;
 19 | using Rhino.DocObjects;
 20 | using rhinomcp.Serializers;
 21 | using JsonException = Newtonsoft.Json.JsonException;
 22 | using Eto.Forms;
 23 | using RhinoMCPPlugin.Functions;
 24 | 
 25 | namespace RhinoMCPPlugin
 26 | {
 27 |     public class RhinoMCPServer
 28 |     {
 29 |         private string host;
 30 |         private int port;
 31 |         private bool running;
 32 |         private TcpListener listener;
 33 |         private Thread serverThread;
 34 |         private readonly object lockObject = new object();
 35 |         private RhinoMCPFunctions handler;
 36 | 
 37 |         public RhinoMCPServer(string host = "127.0.0.1", int port = 1999)
 38 |         {
 39 |             this.host = host;
 40 |             this.port = port;
 41 |             this.running = false;
 42 |             this.listener = null;
 43 |             this.serverThread = null;
 44 |             this.handler = new RhinoMCPFunctions();
 45 |         }
 46 | 
 47 | 
 48 |         public void Start()
 49 |         {
 50 |             lock (lockObject)
 51 |             {
 52 |                 if (running)
 53 |                 {
 54 |                     RhinoApp.WriteLine("Server is already running");
 55 |                     return;
 56 |                 }
 57 | 
 58 |                 running = true;
 59 |             }
 60 | 
 61 |             try
 62 |             {
 63 |                 // Create TCP listener
 64 |                 IPAddress ipAddress = IPAddress.Parse(host);
 65 |                 listener = new TcpListener(ipAddress, port);
 66 |                 listener.Start();
 67 | 
 68 |                 // Start server thread
 69 |                 serverThread = new Thread(ServerLoop);
 70 |                 serverThread.IsBackground = true;
 71 |                 serverThread.Start();
 72 | 
 73 |                 RhinoApp.WriteLine($"RhinoMCP server started on {host}:{port}");
 74 |             }
 75 |             catch (Exception e)
 76 |             {
 77 |                 RhinoApp.WriteLine($"Failed to start server: {e.Message}");
 78 |                 Stop();
 79 |             }
 80 |         }
 81 | 
 82 |         public void Stop()
 83 |         {
 84 |             lock (lockObject)
 85 |             {
 86 |                 running = false;
 87 |             }
 88 | 
 89 |             // Close listener
 90 |             if (listener != null)
 91 |             {
 92 |                 try
 93 |                 {
 94 |                     listener.Stop();
 95 |                 }
 96 |                 catch
 97 |                 {
 98 |                     // Ignore errors on closing
 99 |                 }
100 |                 listener = null;
101 |             }
102 | 
103 |             // Wait for thread to finish
104 |             if (serverThread != null && serverThread.IsAlive)
105 |             {
106 |                 try
107 |                 {
108 |                     serverThread.Join(1000); // Wait up to 1 second
109 |                 }
110 |                 catch
111 |                 {
112 |                     // Ignore errors on join
113 |                 }
114 |                 serverThread = null;
115 |             }
116 | 
117 |             RhinoApp.WriteLine("RhinoMCP server stopped");
118 |         }
119 | 
120 |         private void ServerLoop()
121 |         {
122 |             RhinoApp.WriteLine("Server thread started");
123 | 
124 |             while (IsRunning())
125 |             {
126 |                 try
127 |                 {
128 |                     // Set a timeout to check running condition periodically
129 |                     listener.Server.ReceiveTimeout = 1000;
130 |                     listener.Server.SendTimeout = 1000;
131 | 
132 |                     // Wait for client connection
133 |                     if (listener.Pending())
134 |                     {
135 |                         TcpClient client = listener.AcceptTcpClient();
136 |                         RhinoApp.WriteLine($"Connected to client: {client.Client.RemoteEndPoint}");
137 | 
138 |                         // Handle client in a separate thread
139 |                         Thread clientThread = new Thread(() => HandleClient(client));
140 |                         clientThread.IsBackground = true;
141 |                         clientThread.Start();
142 |                     }
143 |                     else
144 |                     {
145 |                         // No pending connections, sleep a bit to prevent CPU overuse
146 |                         Thread.Sleep(100);
147 |                     }
148 |                 }
149 |                 catch (Exception e)
150 |                 {
151 |                     RhinoApp.WriteLine($"Error in server loop: {e.Message}");
152 | 
153 |                     if (!IsRunning())
154 |                         break;
155 | 
156 |                     Thread.Sleep(500);
157 |                 }
158 |             }
159 | 
160 |             RhinoApp.WriteLine("Server thread stopped");
161 |         }
162 | 
163 |         private bool IsRunning()
164 |         {
165 |             lock (lockObject)
166 |             {
167 |                 return running;
168 |             }
169 |         }
170 | 
171 |         private void HandleClient(TcpClient client)
172 |         {
173 |             RhinoApp.WriteLine("Client handler started");
174 | 
175 |             byte[] buffer = new byte[8192];
176 |             string incompleteData = string.Empty;
177 | 
178 |             try
179 |             {
180 |                 NetworkStream stream = client.GetStream();
181 | 
182 |                 while (IsRunning())
183 |                 {
184 |                     try
185 |                     {
186 |                         // Check if there's data available to read
187 |                         if (client.Available > 0 || stream.DataAvailable)
188 |                         {
189 |                             int bytesRead = stream.Read(buffer, 0, buffer.Length);
190 |                             if (bytesRead == 0)
191 |                             {
192 |                                 RhinoApp.WriteLine("Client disconnected");
193 |                                 break;
194 |                             }
195 | 
196 |                             string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
197 |                             incompleteData += data;
198 | 
199 |                             try
200 |                             {
201 |                                 // Try to parse as JSON
202 |                                 JObject command = JObject.Parse(incompleteData);
203 |                                 incompleteData = string.Empty;
204 | 
205 |                                 // Execute command on Rhino's main thread
206 |                                 RhinoApp.InvokeOnUiThread(new Action(() =>
207 |                                 {
208 |                                     try
209 |                                     {
210 |                                         JObject response = ExecuteCommand(command);
211 |                                         string responseJson = JsonConvert.SerializeObject(response);
212 | 
213 |                                         try
214 |                                         {
215 |                                             byte[] responseBytes = Encoding.UTF8.GetBytes(responseJson);
216 |                                             stream.Write(responseBytes, 0, responseBytes.Length);
217 |                                         }
218 |                                         catch
219 |                                         {
220 |                                             RhinoApp.WriteLine("Failed to send response - client disconnected");
221 |                                         }
222 |                                     }
223 |                                     catch (Exception e)
224 |                                     {
225 |                                         RhinoApp.WriteLine($"Error executing command: {e.Message}");
226 |                                         try
227 |                                         {
228 |                                             JObject errorResponse = new JObject
229 |                                             {
230 |                                                 ["status"] = "error",
231 |                                                 ["message"] = e.Message
232 |                                             };
233 | 
234 |                                             byte[] errorBytes = Encoding.UTF8.GetBytes(errorResponse.ToString());
235 |                                             stream.Write(errorBytes, 0, errorBytes.Length);
236 |                                         }
237 |                                         catch
238 |                                         {
239 |                                             // Ignore send errors
240 |                                         }
241 |                                     }
242 |                                 }));
243 |                             }
244 |                             catch (JsonException)
245 |                             {
246 |                                 // Incomplete JSON data, wait for more
247 |                             }
248 |                         }
249 |                         else
250 |                         {
251 |                             // No data available, sleep a bit to prevent CPU overuse
252 |                             Thread.Sleep(50);
253 |                         }
254 |                     }
255 |                     catch (Exception e)
256 |                     {
257 |                         RhinoApp.WriteLine($"Error receiving data: {e.Message}");
258 |                         break;
259 |                     }
260 |                 }
261 |             }
262 |             catch (Exception e)
263 |             {
264 |                 RhinoApp.WriteLine($"Error in client handler: {e.Message}");
265 |             }
266 |             finally
267 |             {
268 |                 try
269 |                 {
270 |                     client.Close();
271 |                 }
272 |                 catch
273 |                 {
274 |                     // Ignore errors on close
275 |                 }
276 |                 RhinoApp.WriteLine("Client handler stopped");
277 |             }
278 |         }
279 | 
280 |         private JObject ExecuteCommand(JObject command)
281 |         {
282 |             try
283 |             {
284 |                 string cmdType = command["type"]?.ToString();
285 |                 JObject parameters = command["params"] as JObject ?? new JObject();
286 | 
287 |                 RhinoApp.WriteLine($"Executing command: {cmdType}");
288 | 
289 |                 JObject result = ExecuteCommandInternal(cmdType, parameters);
290 | 
291 |                 RhinoApp.WriteLine("Command execution complete");
292 |                 return result;
293 |             }
294 |             catch (Exception e)
295 |             {
296 |                 RhinoApp.WriteLine($"Error executing command: {e.Message}");
297 |                 return new JObject
298 |                 {
299 |                     ["status"] = "error",
300 |                     ["message"] = e.Message
301 |                 };
302 |             }
303 |         }
304 | 
305 |         private JObject ExecuteCommandInternal(string cmdType, JObject parameters)
306 |         {
307 | 
308 |             // Dictionary to map command types to handler methods
309 |             Dictionary<string, Func<JObject, JObject>> handlers = new Dictionary<string, Func<JObject, JObject>>
310 |             {
311 |                 ["get_document_info"] = this.handler.GetDocumentInfo,
312 |                 ["create_object"] = this.handler.CreateObject,
313 |                 ["create_objects"] = this.handler.CreateObjects,
314 |                 ["get_object_info"] = this.handler.GetObjectInfo,
315 |                 ["get_selected_objects_info"] = this.handler.GetSelectedObjectsInfo,
316 |                 ["delete_object"] = this.handler.DeleteObject,
317 |                 ["modify_object"] = this.handler.ModifyObject,
318 |                 ["modify_objects"] = this.handler.ModifyObjects,
319 |                 ["execute_rhinoscript_python_code"] = this.handler.ExecuteRhinoscript,
320 |                 ["select_objects"] = this.handler.SelectObjects,
321 |                 ["create_layer"] = this.handler.CreateLayer,
322 |                 ["get_or_set_current_layer"] = this.handler.GetOrSetCurrentLayer,
323 |                 ["delete_layer"] = this.handler.DeleteLayer
324 |                 // Add more handlers as needed
325 |             };
326 | 
327 |             if (handlers.TryGetValue(cmdType, out var handler))
328 |             {
329 |                 var doc = RhinoDoc.ActiveDoc;
330 |                 var record = doc.BeginUndoRecord("Run MCP command");
331 |                 try
332 |                 {
333 |                     JObject result = handler(parameters);
334 |                     return new JObject
335 |                     {
336 |                         ["status"] = "success",
337 |                         ["result"] = result
338 |                     };
339 |                 }
340 |                 catch (Exception e)
341 |                 {
342 |                     RhinoApp.WriteLine($"Error in handler: {e.Message}");
343 |                     return new JObject
344 |                     {
345 |                         ["status"] = "error",
346 |                         ["message"] = e.Message
347 |                     };
348 |                 }
349 |                 finally
350 |                 {
351 |                     doc.EndUndoRecord(record);
352 |                 }
353 |             }
354 |             else
355 |             {
356 |                 return new JObject
357 |                 {
358 |                     ["status"] = "error",
359 |                     ["message"] = $"Unknown command type: {cmdType}"
360 |                 };
361 |             }
362 |         }
363 |     }
364 | }
```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/group.py:
--------------------------------------------------------------------------------

```python
  1 | import scriptcontext
  2 | 
  3 | from rhinoscript import utility as rhutil
  4 | 
  5 | 
  6 | def AddGroup(group_name=None):
  7 |     """Adds a new empty group to the document
  8 |     Parameters:
  9 |       group_name (str, optional): name of the new group. If omitted, rhino automatically
 10 |           generates the group name
 11 |     Returns:
 12 |       str: name of the new group if successful
 13 |       None: is not successful or on error
 14 |     Example:
 15 |       import rhinoscriptsyntax as rs
 16 |       name = rs.AddGroup("NewGroup")
 17 |     See Also:
 18 |       DeleteGroup
 19 |       GroupCount
 20 |       GroupNames
 21 |       IsGroup
 22 |       RenameGroup
 23 |     """
 24 |     index = -1
 25 |     if group_name is None:
 26 |         index = scriptcontext.doc.Groups.Add()
 27 |     else:
 28 |         if not isinstance(group_name, str): group_name = str(group_name)
 29 |         index = scriptcontext.doc.Groups.Add( group_name )
 30 |     rc = scriptcontext.doc.Groups.GroupName(index)
 31 |     if rc is None: return scriptcontext.errorhandler()
 32 |     return rc
 33 | 
 34 | 
 35 | def AddObjectsToGroup(object_ids, group_name):
 36 |     """Adds one or more objects to an existing group.
 37 |     Parameters:
 38 |       object_ids ([guid, ...]) list of Strings or Guids representing the object identifiers
 39 |       group_name (str): the name of an existing group
 40 |     Returns:
 41 |       number: number of objects added to the group
 42 |     Example:
 43 |       import rhinoscriptsyntax as rs
 44 |       name = "NewGroup"
 45 |       object_ids = rs.GetObjects("Select objects to add to group")
 46 |       if object_ids: rs.AddObjectsToGroup(object_ids, name)
 47 |     See Also:
 48 |       AddObjectToGroup
 49 |       IsGroupEmpty
 50 |       ObjectGroups
 51 |       ObjectsByGroup
 52 |     """
 53 |     if not isinstance(group_name, str): group_name = str(group_name)
 54 |     index = scriptcontext.doc.Groups.Find(group_name)
 55 |     object_ids = rhutil.coerceguidlist(object_ids)
 56 |     if index<0 or not object_ids: return 0
 57 |     if not scriptcontext.doc.Groups.AddToGroup(index, object_ids): return 0
 58 |     return len(object_ids)
 59 | 
 60 | 
 61 | def AddObjectToGroup(object_id, group_name):
 62 |     """Adds a single object to an existing group.
 63 |     Parameters:
 64 |       object_id (guid): String or Guid representing the object identifier
 65 |       group_name (str): the name of an existing group
 66 |     Returns:
 67 |       True or False representing success or failure
 68 |     Example:
 69 |       import rhinoscriptsyntax as rs
 70 |       name = "NewGroup"
 71 |       id = rs.GetObject("Select object to add to group")
 72 |       if id: rs.AddObjectToGroup(id,name)
 73 |     See Also:
 74 |       AddObjectsToGroup
 75 |       IsGroupEmpty
 76 |       ObjectGroups
 77 |       ObjectsByGroup
 78 |     """
 79 |     object_id = rhutil.coerceguid(object_id)
 80 |     if not isinstance(group_name, str): group_name = str(group_name)
 81 |     index = scriptcontext.doc.Groups.Find(group_name)
 82 |     if object_id is None or index<0: return False
 83 |     return scriptcontext.doc.Groups.AddToGroup(index, object_id)
 84 | 
 85 | 
 86 | def DeleteGroup(group_name):
 87 |     """Removes an existing group from the document. Reference groups cannot be
 88 |     removed. Deleting a group does not delete the member objects
 89 |     Parameters:
 90 |       group_name (str): the name of an existing group
 91 |     Returns:
 92 |       bool: True or False representing success or failure
 93 |     Example:
 94 |       import rhinoscriptsyntax as rs
 95 |       groups = rs.GroupNames()
 96 |       if groups:
 97 |           for group in groups: rs.DeleteGroup(group)
 98 |     See Also:
 99 |       AddGroup
100 |       GroupCount
101 |       GroupNames
102 |       IsGroup
103 |       RenameGroup
104 |     """
105 |     if not isinstance(group_name, str): group_name = str(group_name)
106 |     index = scriptcontext.doc.Groups.Find(group_name)
107 |     return scriptcontext.doc.Groups.Delete(index)
108 | 
109 | 
110 | def GroupCount():
111 |     """Returns the number of groups in the document
112 |     Returns:
113 |       number: the number of groups in the document
114 |     Example:
115 |       import rhinoscriptsyntax as rs
116 |       numgroups = rs.GroupCount()
117 |       print("Group count:{}".format(numgroups))
118 |     See Also:
119 |       AddGroup
120 |       DeleteGroup
121 |       GroupNames
122 |       IsGroup
123 |       RenameGroup
124 |     """
125 |     return scriptcontext.doc.Groups.Count
126 | 
127 | 
128 | def GroupNames():
129 |     """Returns the names of all the groups in the document
130 |     None if no names exist in the document
131 |     Returns:
132 |       list(str, ...): the names of all the groups in the document.  None if no names exist in the document
133 |     Example:
134 |       import rhinoscriptsyntax as rs
135 |       groups = rs.GroupNames()
136 |       if groups:
137 |           for group in groups: print(group)
138 |     See Also:
139 |       AddGroup
140 |       DeleteGroup
141 |       GroupCount
142 |       IsGroup
143 |       RenameGroup
144 |     """
145 |     names = scriptcontext.doc.Groups.GroupNames(True)
146 |     if names is None: return None
147 |     return list(names)
148 | 
149 | 
150 | def HideGroup(group_name):
151 |     """Hides a group of objects. Hidden objects are not visible, cannot be
152 |     snapped to, and cannot be selected
153 |     Parameters:
154 |       group_name (str): the name of an existing group
155 |     Returns:
156 |       number: The number of objects that were hidden
157 |     Example:
158 |       import rhinoscriptsyntax as rs
159 |       groups = rs.GroupNames()
160 |       if groups:
161 |           for group in groups: rs.HideGroup(group)
162 |     See Also:
163 |       LockGroup
164 |       ShowGroup
165 |       UnlockGroup
166 |     """
167 |     index = scriptcontext.doc.Groups.Find(group_name)
168 |     if index<0: return 0
169 |     return scriptcontext.doc.Groups.Hide(index);
170 | 
171 | 
172 | def IsGroup(group_name):
173 |     """Verifies the existance of a group
174 |     Parameters:
175 |       group_name (str): the name of the group to check for
176 |     Returns:
177 |       bool: True or False
178 |     Example:
179 |       import rhinoscriptsyntax as rs
180 |       group = rs.GetString("Group name to verify")
181 |       if rs.IsGroup(group):
182 |           print("The group exists.")
183 |       else:
184 |           print("The group does not exist.")
185 |     See Also:
186 |       AddGroup
187 |       DeleteGroup
188 |       GroupCount
189 |       GroupNames
190 |       RenameGroup
191 |     """
192 |     if not isinstance(group_name, str): group_name = str(group_name)
193 |     return scriptcontext.doc.Groups.Find(group_name)>=0
194 | 
195 | 
196 | def IsGroupEmpty(group_name):
197 |     """Verifies that an existing group is empty, or contains no object members
198 |     Parameters:
199 |       group_name (str): the name of an existing group
200 |     Returns:
201 |       bool: True or False if group_name exists
202 |       None: if group_name does not exist
203 |     Example:
204 |       import rhinoscriptsyntax as rs
205 |       names = rs.GroupNames()
206 |       if names:
207 |           for name in names:
208 |               if rs.IsGroupEmpty(name): rs.DeleteGroup(name)
209 |     See Also:
210 |       AddObjectsToGroup
211 |       AddObjectToGroup
212 |       RemoveObjectFromAllGroups
213 |       RemoveObjectFromGroup
214 |       RemoveObjectsFromGroup
215 |     """
216 |     if not isinstance(group_name, str): group_name = str(group_name)
217 |     index = scriptcontext.doc.Groups.Find(group_name)
218 |     if index<0: return scriptcontext.errorhandler()
219 |     return scriptcontext.doc.Groups.GroupObjectCount(index)>0
220 | 
221 | 
222 | def LockGroup(group_name):
223 |     """Locks a group of objects. Locked objects are visible and they can be
224 |     snapped to. But, they cannot be selected
225 |     Parameters:
226 |       group_name (str): the name of an existing group
227 |     Returns:
228 |       number: Number of objects that were locked if successful
229 |       None: on error
230 |     Example:
231 |       import rhinoscriptsyntax as rs
232 |       names = rs.GroupNames()
233 |       if names:
234 |           for name in names: rs.LockGroup(name)
235 |     See Also:
236 |       HideGroup
237 |       ShowGroup
238 |       UnlockGroup
239 |     """
240 |     if not isinstance(group_name, str): group_name = str(group_name)
241 |     index = scriptcontext.doc.Groups.Find(group_name)
242 |     if index<0: return scriptcontext.errorhandler()
243 |     return scriptcontext.doc.Groups.Lock(index);
244 | 
245 | 
246 | def RemoveObjectFromAllGroups(object_id):
247 |     """Removes a single object from any and all groups that it is a member.
248 |     Neither the object nor the group can be reference objects
249 |     Parameters:
250 |       object_id (guid): the object identifier
251 |     Returns:
252 |       bool: True or False indicating success or failure
253 |     Example:
254 |       import rhinoscriptsyntax as rs
255 |       object = rs.GetObject("Select object")
256 |       if object: rs.RemoveObjectFromAllGroups(object)
257 |     See Also:
258 |       IsGroupEmpty
259 |       ObjectGroups
260 |       ObjectsByGroup
261 |       RemoveObjectFromGroup
262 |       RemoveObjectsFromGroup
263 |     """
264 |     rhinoobject = rhutil.coercerhinoobject(object_id, True, True)
265 |     if rhinoobject.GroupCount<1: return False
266 |     attrs = rhinoobject.Attributes
267 |     attrs.RemoveFromAllGroups()
268 |     return scriptcontext.doc.Objects.ModifyAttributes(rhinoobject, attrs, True)
269 | 
270 | 
271 | def RemoveObjectFromGroup(object_id, group_name):
272 |     """Remove a single object from an existing group
273 |     Parameters:
274 |       object_id (guid): the object identifier
275 |       group_name (str): the name of an existing group
276 |     Returns:
277 |       bool: True or False indicating success or failure
278 |     Example:
279 |       import rhinoscriptsyntax as rs
280 |       name = "NewGroup"
281 |       id = rs.GetObject("Select object")
282 |       if name: rs.RemoveObjectFromGroup(id,name)
283 |     See Also:
284 |       IsGroupEmpty
285 |       ObjectGroups
286 |       ObjectsByGroup
287 |       RemoveObjectFromAllGroups
288 |       RemoveObjectsFromGroup
289 |     """
290 |     count = RemoveObjectsFromGroup(object_id, group_name)
291 |     return not (count is None or count<1)
292 | 
293 | 
294 | def RemoveObjectsFromGroup(object_ids, group_name):
295 |     """Removes one or more objects from an existing group
296 |     Parameters:
297 |       object_ids ([guid, ...]): a list of object identifiers
298 |       group_name (str): the name of an existing group
299 |     Returns:
300 |       number: The number of objects removed from the group is successful
301 |       None: on error
302 |     Example:
303 |       import rhinoscriptsyntax as rs
304 |       group = "NewGroup"
305 |       ids = rs.GetObjects("Select objects")
306 |       if ids: rs.RemoveObjectsFromGroup(ids,group)
307 |     See Also:
308 |       IsGroupEmpty
309 |       ObjectGroups
310 |       ObjectsByGroup
311 |       RemoveObjectFromAllGroups
312 |       RemoveObjectFromGroup
313 |     """
314 |     if not isinstance(group_name, str): group_name = str(group_name)
315 |     index = scriptcontext.doc.Groups.Find(group_name)
316 |     if index<0: return scriptcontext.errorhandler()
317 |     id = rhutil.coerceguid(object_ids, False)
318 |     if id: object_ids = [id]
319 |     objects_removed = 0
320 |     for id in object_ids:
321 |         rhinoobject = rhutil.coercerhinoobject(id, True, True)
322 |         attrs = rhinoobject.Attributes
323 |         attrs.RemoveFromGroup(index)
324 |         if scriptcontext.doc.Objects.ModifyAttributes(rhinoobject, attrs, True):
325 |             objects_removed+=1
326 |     return objects_removed
327 | 
328 | 
329 | def RenameGroup(old_name, new_name):
330 |     """Renames an existing group
331 |     Parameters:
332 |       old_name (str): the name of an existing group
333 |       new_name (str): the new group name
334 |     Returns:
335 |       str: the new group name if successful
336 |       None: on error
337 |     Example:
338 |       import rhinoscriptsyntax as rs
339 |       strOldGroup = rs.GetString("Old group name")
340 |       if strOldGroup:
341 |           strNewGroup = rs.GetString("New group name")
342 |           if strNewName: rs.RenameGroup(strOldGroup, strNewGroup)
343 |     See Also:
344 |       AddGroup
345 |       DeleteGroup
346 |       GroupCount
347 |       GroupNames
348 |       IsGroup
349 |     """
350 |     if not isinstance(old_name, str): old_name = str(old_name)
351 |     index = scriptcontext.doc.Groups.Find(old_name)
352 |     if index<0: return scriptcontext.errorhandler()
353 |     if not isinstance(new_name, str): new_name = str(new_name)
354 |     if scriptcontext.doc.Groups.ChangeGroupName(index, new_name):
355 |         return new_name
356 |     return scriptcontext.errorhandler()
357 | 
358 | 
359 | def ShowGroup(group_name):
360 |     """Shows a group of previously hidden objects. Hidden objects are not
361 |     visible, cannot be snapped to, and cannot be selected
362 |     Parameters:
363 |       group_name (str): the name of an existing group
364 |     Returns:
365 |       number: The number of objects that were shown if successful
366 |       None: on error
367 |     Example:
368 |       import rhinoscriptsyntax as rs
369 |       groups = rs.GroupNames()
370 |       if groups:
371 |           for group in groups: rs.ShowGroup(group)
372 |     See Also:
373 |       HideGroup
374 |       LockGroup
375 |       UnlockGroup
376 |     """
377 |     if not isinstance(group_name, str): group_name = str(group_name)
378 |     index = scriptcontext.doc.Groups.Find(group_name)
379 |     if index<0: return scriptcontext.errorhandler()
380 |     return scriptcontext.doc.Groups.Show(index);
381 | 
382 | 
383 | def UnlockGroup(group_name):
384 |     """Unlocks a group of previously locked objects. Lockes objects are visible,
385 |     can be snapped to, but cannot be selected
386 |     Parameters:
387 |       group_name (str): the name of an existing group
388 |     Returns:
389 |       number: The number of objects that were unlocked if successful
390 |       None: on error
391 |     Example:
392 |       import rhinoscriptsyntax as rs
393 |       groups = rs.GroupNames()
394 |       if groups:
395 |           for group in groups: rs.UnlockGroup(group)
396 |     See Also:
397 |       HideGroup
398 |       LockGroup
399 |       ShowGroup
400 |     """
401 |     if not isinstance(group_name, str): group_name = str(group_name)
402 |     index = scriptcontext.doc.Groups.Find(group_name)
403 |     if index<0: return scriptcontext.errorhandler()
404 |     return scriptcontext.doc.Groups.Unlock(index);
405 | 
406 | 
407 | def ObjectTopGroup(object_id):
408 |     """Returns the top most group name that an object is assigned.  This function primarily applies to objects that are members of nested groups
409 |     Parameters:
410 |       object_id (guid): String or Guid representing the object identifier
411 |     Returns:
412 |       str: the top group's name if successful
413 |       None: if not successful
414 |     Example:
415 |       import rhinoscriptsyntax as rs
416 |       id = rs.GetObject("Select object to add to group")
417 |       groupName = rs.ObjectTopGroup(id)
418 |     See Also:
419 |       ObjectGroups
420 |     """
421 |     object_id = rhutil.coerceguid(object_id)
422 |     if object_id is None: return None
423 |     obj = scriptcontext.doc.Objects.FindId(object_id)
424 |     topGroupName = None
425 |     groupIndexes = obj.GetGroupList()
426 |     if groupIndexes is not None:
427 |         topGroupIndex = max(groupIndexes) # this is a bad assumption. See RH-49189
428 |         topGroupName = scriptcontext.doc.Groups.FindIndex(topGroupIndex).Name
429 |     return topGroupName
430 | 
431 | 
```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/grips.py:
--------------------------------------------------------------------------------

```python
  1 | import Rhino
  2 | 
  3 | import scriptcontext
  4 | 
  5 | import rhinocompat as compat
  6 | from rhinoscript import utility as rhutil
  7 | 
  8 | 
  9 | def __neighborgrip(i, object_id, index, direction, enable):
 10 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
 11 |     grips = rhobj.GetGrips()
 12 |     if not grips or len(grips)<=index: return scriptcontext.errorhandler()
 13 |     grip = grips[index]
 14 |     next_grip=None
 15 |     if direction==0:
 16 |         next_grip = grip.NeighborGrip(i,0,0,False)
 17 |     else:
 18 |         next_grip = grip.NeighborGrip(0,i,0,False)
 19 |     if next_grip and enable:
 20 |         next_grip.Select(True)
 21 |         scriptcontext.doc.Views.Redraw()
 22 |     return next_grip
 23 | 
 24 | 
 25 | def EnableObjectGrips(object_id, enable=True):
 26 |     """Enables or disables an object's grips. For curves and surfaces, these are
 27 |     also called control points.
 28 |     Parameters:
 29 |       object_id (guid): identifier of the object
 30 |       enable (bool, optional): if True, the specified object's grips will be turned on.
 31 |         Otherwise, they will be turned off
 32 |     Returns:
 33 |       bool: True on success, False on failure
 34 |     Example:
 35 |       import rhinoscriptsyntax as  rs
 36 |       objects = rs.GetObjects("Select  objects")
 37 |       if objects: [rs.EnableObjectGrips(obj)  for obj in objs]
 38 |     See Also:
 39 |       ObjectGripCount
 40 |       ObjectGripsOn
 41 |       ObjectGripsSelected
 42 |       SelectObjectGrips
 43 |       UnselectObjectGrips
 44 |     """
 45 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
 46 |     if enable!=rhobj.GripsOn:
 47 |         rhobj.GripsOn = enable
 48 |         scriptcontext.doc.Views.Redraw()
 49 | 
 50 | 
 51 | def GetObjectGrip(message=None, preselect=False, select=False):
 52 |     """Prompts the user to pick a single object grip
 53 |     Parameters:
 54 |       message (str, optional): prompt for picking
 55 |       preselect (bool, optional): allow for selection of pre-selected object grip.
 56 |       select (bool, optional): select the picked object grip.
 57 |     Returns:
 58 |       tuple(guid, number, point): defining a grip record.
 59 |          [0] = identifier of the object that owns the grip
 60 |          [1] = index value of the grip
 61 |          [2] = location of the grip
 62 |       None: on error
 63 |     Example:
 64 |       import rhinoscriptsyntax as rs
 65 |       curve = rs.GetObject("Select a curve", rs.filter.curve)
 66 |       if curve:
 67 |           rs.EnableObjectGrips( curve )
 68 |           grip = rs.GetObjectGrip("Select a curve grip")
 69 |           if grip: print(grip[2])
 70 |     See Also:
 71 |       GetObjectGrips
 72 |     """
 73 |     if not preselect:
 74 |         scriptcontext.doc.Objects.UnselectAll()
 75 |         scriptcontext.doc.Views.Redraw()
 76 |     rc, grip = Rhino.Input.RhinoGet.GetGrip(message)
 77 |     if rc!=Rhino.Commands.Result.Success: return scriptcontext.errorhandler()
 78 |     if select:
 79 |         grip.Select(True, True)
 80 |         scriptcontext.doc.Views.Redraw()
 81 |     return grip.OwnerId, grip.Index, grip.CurrentLocation
 82 | 
 83 | 
 84 | def GetObjectGrips(message=None, preselect=False, select=False):
 85 |     """Prompts user to pick one or more object grips from one or more objects.
 86 |     Parameters:
 87 |       message (str, optional): prompt for picking
 88 |       preselect (bool, optional): allow for selection of pre-selected object grips
 89 |       select (bool, optional) select the picked object grips
 90 |     Returns:
 91 |       list((guid, number, point), ...): containing one or more grip records. Each grip record is a tuple
 92 |         [n][0] = identifier of the object that owns the grip
 93 |         [n][1] = index value of the grip
 94 |         [n][2] = location of the grip
 95 |       None: on error
 96 |     Example:
 97 |       import rhinoscriptsyntax as rs
 98 |       curves = rs.GetObjects("Select curves", rs.filter.curves)
 99 |       if curves:
100 |           for curve in curves: rs.EnableObjectGrips(curve)
101 |           grips = rs.GetObjectGrips("Select curve grips")
102 |           if grips: for grip in grips: print(grip[0])
103 |     See Also:
104 |       GetObjectGrip
105 |     """
106 |     if not preselect:
107 |         scriptcontext.doc.Objects.UnselectAll()
108 |         scriptcontext.doc.Views.Redraw()
109 |     getrc, grips = Rhino.Input.RhinoGet.GetGrips(message)
110 |     if getrc!=Rhino.Commands.Result.Success or not grips:
111 |         return scriptcontext.errorhandler()
112 |     rc = []
113 |     for grip in grips:
114 |         id = grip.OwnerId
115 |         index = grip.Index
116 |         location = grip.CurrentLocation
117 |         rc.append((id, index, location))
118 |         if select: grip.Select(True, True)
119 |     if select: scriptcontext.doc.Views.Redraw()
120 |     return rc
121 | 
122 | 
123 | def NextObjectGrip(object_id, index, direction=0, enable=True):
124 |     """Returns the next grip index from a specified grip index of an object
125 |     Parameters:
126 |       object_id (guid): identifier of the object
127 |       index (number): zero based grip index from which to get the next grip index
128 |       direction ([number, number], optional): direction to get the next grip index (0=U, 1=V)
129 |       enable (bool, optional): if True, the next grip index found will be selected
130 |     Returns:
131 |       number: index of the next grip on success
132 |       None: on failure
133 |     Example:
134 |       import rhinoscriptsyntax as rs
135 |       object_id = rs.GetObject("Select curve", rs.filter.curve)
136 |       if object_id:
137 |           rs.EnableObjectGrips( object_id )
138 |           count = rs.ObjectGripCount( object_id )
139 |           for i in range(0,count,2):
140 |               rs.NextObjectGrip(object_id, i, 0, True)
141 |     See Also:
142 |       EnableObjectGrips
143 |       PrevObjectGrip
144 |     """
145 |     return __neighborgrip(1, object_id, index, direction, enable)
146 | 
147 | 
148 | def ObjectGripCount(object_id):
149 |     """Returns number of grips owned by an object
150 |     Parameters:
151 |       object_id (guid): identifier of the object
152 |     Returns:
153 |       number: number of grips if successful
154 |       None: on error
155 |     Example:
156 |       import rhinoscriptsyntax as rs
157 |       obj = rs.GetObject("Select object")
158 |       if rs.ObjectGripsOn(obj):
159 |           print("Grip count ={}".format(rs.ObjectGripCount(obj)))
160 |     See Also:
161 |       EnableObjectGrips
162 |       ObjectGripsOn
163 |       ObjectGripsSelected
164 |       SelectObjectGrips
165 |       UnselectObjectGrips
166 |     """
167 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
168 |     grips = rhobj.GetGrips()
169 |     if not grips: return scriptcontext.errorhandler()
170 |     return grips.Length
171 | 
172 | 
173 | def ObjectGripLocation(object_id, index, point=None):
174 |     """Returns or modifies the location of an object's grip
175 |     Parameters:
176 |       object_id (guid) identifier of the object
177 |       index (number): index of the grip to either query or modify
178 |       point (point, optional): 3D point defining new location of the grip
179 |     Returns:
180 |       point: if point is not specified, the current location of the grip referenced by index
181 |       point: if point is specified, the previous location of the grip referenced by index
182 |       None: on error
183 |     Example:
184 |       import rhinoscriptsyntax as rs
185 |       obj = rs.GetObject("Select curve", rs.filter.curve)
186 |       if obj:
187 |           rs.EnableObjectGrips(obj)
188 |           point = rs.ObjectGripLocation(obj, 0)
189 |           point[0] = point[0] + 1.0
190 |           point[1] = point[1] + 1.0
191 |           point[2] = point[2] + 1.0
192 |           rs.ObjectGripLocation(obj, 0, point)
193 |           rs.EnableObjectGrips(obj, False)
194 |     See Also:
195 |       EnableObjectGrips
196 |       ObjectGripLocations
197 |     """
198 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
199 |     if not rhobj.GripsOn: return scriptcontext.errorhandler()
200 |     grips = rhobj.GetGrips()
201 |     if not grips or index<0 or index>=grips.Length:
202 |         return scriptcontext.errorhandler()
203 |     grip = grips[index]
204 |     rc = grip.CurrentLocation
205 |     if point:
206 |         grip.CurrentLocation = rhutil.coerce3dpoint(point, True)
207 |         scriptcontext.doc.Objects.GripUpdate(rhobj, True)
208 |         scriptcontext.doc.Views.Redraw()
209 |     return rc
210 | 
211 | 
212 | def ObjectGripLocations(object_id, points=None):
213 |     """Returns or modifies the location of all grips owned by an object. The
214 |     locations of the grips are returned in a list of Point3d with each position
215 |     in the list corresponding to that grip's index. To modify the locations of
216 |     the grips, you must provide a list of points that contain the same number
217 |     of points at grips
218 |     Parameters:
219 |       object_id (guid): identifier of the object
220 |       points ([point, ...], optional) list of 3D points identifying the new grip locations
221 |     Returns:
222 |       list(point, ...): if points is not specified, the current location of all grips
223 |       list(point, ...): if points is specified, the previous location of all grips
224 |       None: if not successful
225 |     Example:
226 |       import rhinoscriptsyntax as rs
227 |       obj = rs.GetObject("Select curve", rs.filter.curve)
228 |       if obj:
229 |           rs.EnableObjectGrips( obj )
230 |           points = rs.ObjectGripLocations(obj)
231 |           for point in points:  print(point)
232 |     See Also:
233 |       EnableObjectGrips
234 |       ObjectGripCount
235 |       ObjectGripLocation
236 |     """
237 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
238 |     if not rhobj.GripsOn: return scriptcontext.errorhandler()
239 |     grips = rhobj.GetGrips()
240 |     if grips is None: return scriptcontext.errorhandler()
241 |     rc = [grip.CurrentLocation for grip in grips]
242 |     if points and len(points)==len(grips):
243 |         points = rhutil.coerce3dpointlist(points, True)
244 |         for i, grip in enumerate(grips):
245 |             point = points[i]
246 |             grip.CurrentLocation = point
247 |         scriptcontext.doc.Objects.GripUpdate(rhobj, True)
248 |         scriptcontext.doc.Views.Redraw()
249 |     return rc
250 | 
251 | 
252 | def ObjectGripsOn(object_id):
253 |     """Verifies that an object's grips are turned on
254 |     Parameters:
255 |       object_id (guid): identifier of the object
256 |     Returns:
257 |       bool: True or False indicating Grips state
258 |       None: on error
259 |     Example:
260 |       import rhinoscriptsyntax as rs
261 |       obj = rs.GetObject("Select object")
262 |       if rs.ObjectGripsOn(obj):
263 |           print("Grip count = {}".format(rs.ObjectGripCount(obj)))
264 |     See Also:
265 |       EnableObjectGrips
266 |       ObjectGripCount
267 |       ObjectGripsSelected
268 |       SelectObjectGrips
269 |       UnselectObjectGrips
270 |     """
271 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
272 |     return rhobj.GripsOn
273 | 
274 | 
275 | def ObjectGripsSelected(object_id):
276 |     """Verifies that an object's grips are turned on and at least one grip
277 |     is selected
278 |     Parameters:
279 |       object_id (guid): identifier of the object
280 |     Returns:
281 |       bool: True or False indicating success or failure
282 |     Example:
283 |       import rhinoscriptsyntax as rs
284 |       obj = rs.GetObject("Select object")
285 |       if rs.ObjectGripsSelected(obj):
286 |           rs.UnselectObjectGrips( obj )
287 |     See Also:
288 |       EnableObjectGrips
289 |       ObjectGripCount
290 |       ObjectGripsOn
291 |       SelectObjectGrips
292 |       UnselectObjectGrips
293 |     """
294 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
295 |     if not rhobj.GripsOn: return False
296 |     grips = rhobj.GetGrips()
297 |     if grips is None: return False
298 |     for grip in grips:
299 |         if grip.IsSelected(False): return True
300 |     return False
301 | 
302 | 
303 | def PrevObjectGrip(object_id, index, direction=0, enable=True):
304 |     """Returns the previous grip index from a specified grip index of an object
305 |     Parameters:
306 |       object_id (guid): identifier of the object
307 |       index (number): zero based grip index from which to get the previous grip index
308 |       direction ([number, number], optional): direction to get the next grip index (0=U, 1=V)
309 |       enable (bool, optional): if True, the next grip index found will be selected
310 |     Returns:
311 |       number: index of the next grip on success
312 |       None: on failure
313 |     Example:
314 |       import rhinoscriptsyntax as rs
315 |       object_id = rs.GetObject("Select curve", rs.filter.curve)
316 |       if object_id:
317 |           rs.EnableObjectGrips(object_id)
318 |           count = rs.ObjectGripCount(object_id)
319 |           for i in range(count-1, 0, -2):
320 |               rs.PrevObjectGrip(object_id, i, 0, True)
321 |     See Also:
322 |       EnableObjectGrips
323 |       NextObjectGrip
324 |     """
325 |     return __neighborgrip(-1, object_id, index, direction, enable)
326 | 
327 | 
328 | def SelectedObjectGrips(object_id):
329 |     """Returns a list of grip indices indentifying an object's selected grips
330 |     Parameters:
331 |       object_id (guid): identifier of the object
332 |     Returns:
333 |       list(number): list of indices on success
334 |       None: on failure or if no grips are selected
335 |     Example:
336 |       import rhinoscriptsyntax as rs
337 |       obj = rs.GetObject("Select curve", rs.filter.curve)
338 |       if obj:
339 |           rs.EnableObjectGrips( obj )
340 |           count = rs.ObjectGripCount( obj )
341 |           for i in range(0,count,2):
342 |               rs.SelectObjectGrip( obj, i )
343 |           grips = rs.SelectedObjectGrips(obj)
344 |           if grips: print(len(grips{}).format("grips selected"))
345 |     See Also:
346 |       EnableObjectGrips
347 |       SelectObjectGrip
348 |       SelectObjectGrips
349 |     """
350 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
351 |     if not rhobj.GripsOn: return None
352 |     grips = rhobj.GetGrips()
353 |     rc = []
354 |     if grips:
355 |         for i in compat.RANGE(grips.Length):
356 |             if grips[i].IsSelected(False): rc.append(i)
357 |     return rc
358 | 
359 | 
360 | def SelectObjectGrip(object_id, index):
361 |     """Selects a single grip owned by an object. If the object's grips are
362 |     not turned on, the grips will not be selected
363 |     Parameters:
364 |       object_id (guid) identifier of the object
365 |       index (number): index of the grip to select
366 |     Returns:
367 |       bool: True or False indicating success or failure
368 |     Example:
369 |       import rhinoscriptsyntax as rs
370 |       obj = rs.GetObject("Select curve", rs.filter.curve)
371 |       if obj:
372 |           rs.EnableObjectGrips( obj )
373 |           count = rs.ObjectGripCount( obj )
374 |           for i in range(0,count,2): rs.SelectObjectGrip(obj,i)
375 |     See Also:
376 |       EnableObjectGrips
377 |       ObjectGripCount
378 |       SelectObjectGrips
379 |     """
380 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
381 |     if not rhobj.GripsOn: return False
382 |     grips = rhobj.GetGrips()
383 |     if grips is None: return False
384 |     if index<0 or index>=grips.Length: return False
385 |     grip = grips[index]
386 |     if grip.Select(True,True)>0:
387 |         scriptcontext.doc.Views.Redraw()
388 |         return True
389 |     return False
390 | 
391 | 
392 | def SelectObjectGrips(object_id):
393 |     """Selects an object's grips. If the object's grips are not turned on,
394 |     they will not be selected
395 |     Parameters:
396 |       object_id (guid): identifier of the object
397 |     Returns:
398 |       number: Number of grips selected on success
399 |       None: on failure
400 |     Example:
401 |       import rhinoscriptsyntax as rs
402 |       obj = rs.GetObject("Select object")
403 |       if rs.ObjectGripsSelected(obj)==False:
404 |           rs.SelectObjectGrips( obj )
405 |     See Also:
406 |       EnableObjectGrips
407 |       ObjectGripCount
408 |       SelectObjectGrip
409 |     """
410 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
411 |     if not rhobj.GripsOn: return scriptcontext.errorhandler()
412 |     grips = rhobj.GetGrips()
413 |     if grips is None: return scriptcontext.errorhandler()
414 |     count = 0
415 |     for grip in grips:
416 |         if grip.Select(True,True)>0: count+=1
417 |     if count>0:
418 |         scriptcontext.doc.Views.Redraw()
419 |         return count
420 |     return scriptcontext.errorhandler()
421 | 
422 | 
423 | def UnselectObjectGrip(object_id, index):
424 |     """Unselects a single grip owned by an object. If the object's grips are
425 |     not turned on, the grips will not be unselected
426 |     Parameters:
427 |       object_id (guid): identifier of the object
428 |       index (number): index of the grip to unselect
429 |     Returns:
430 |       bool: True or False indicating success or failure
431 |     Example:
432 |       import rhinoscriptsyntax as rs
433 |       obj = rs.GetObject("Select curve", rs.filter.curve)
434 |       if obj:
435 |           rs.EnableObjectGrips( obj )
436 |           count = rs.ObjectGripCount(obj)
437 |           for i in range(0,count,2):
438 |               rs.UnselectObjectGrip( obj, i )
439 |     See Also:
440 |       EnableObjectGrips
441 |       ObjectGripCount
442 |       UnselectObjectGrips
443 |     """
444 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
445 |     if not rhobj.GripsOn: return False
446 |     grips = rhobj.GetGrips()
447 |     if grips is None: return False
448 |     if index<0 or index>=grips.Length: return False
449 |     grip = grips[index]
450 |     if grip.Select(False)==0:
451 |         scriptcontext.doc.Views.Redraw()
452 |         return True
453 |     return False
454 | 
455 | 
456 | def UnselectObjectGrips(object_id):
457 |     """Unselects an object's grips. Note, the grips will not be turned off.
458 |     Parameters:
459 |       object_id (guid): identifier of the object
460 |     Returns:
461 |       number: Number of grips unselected on success
462 |       None: on failure
463 |     Example:
464 |       import rhinoscriptsyntax as rs
465 |       obj = rs.GetObject("Select object")
466 |       if rs.ObjectGripsSelected(obj): rs.UnselectObjectGrips(obj)
467 |     See Also:
468 |       EnableObjectGrips
469 |       ObjectGripCount
470 |       UnselectObjectGrip
471 |     """
472 |     rhobj = rhutil.coercerhinoobject(object_id, True, True)
473 |     if not rhobj.GripsOn: return scriptcontext.errorhandler()
474 |     grips = rhobj.GetGrips()
475 |     if grips is None: return scriptcontext.errorhandler()
476 |     count = 0
477 |     for grip in grips:
478 |         if grip.Select(False)==0: count += 1
479 |     if count>0:
480 |         scriptcontext.doc.Views.Redraw()
481 |         return count
482 |     return scriptcontext.errorhandler()
483 | 
```

--------------------------------------------------------------------------------
/rhino_mcp_server/static/material.py:
--------------------------------------------------------------------------------

```python
  1 | import Rhino
  2 | import Rhino.DocObjects
  3 | 
  4 | import scriptcontext
  5 | 
  6 | from rhinoscript import utility as rhutil
  7 | from rhinoscript.layer import __getlayer
  8 | 
  9 | 
 10 | def AddMaterialToLayer(layer):
 11 |     """Add material to a layer and returns the new material's index. If the
 12 |     layer already has a material, then the layer's current material index is
 13 |     returned
 14 |     Parameters:
 15 |       layer (str): name of an existing layer.
 16 |     Returns:
 17 |       number: Material index of the layer if successful
 18 |       None: if not successful or on error
 19 |     Example:
 20 |       import rhinoscriptsyntax as rs
 21 |       layer = rs.CurrentLayer()
 22 |       index = rs.LayerMaterialIndex(layer)
 23 |       if index==-1: index = rs.AddMaterialToLayer(layer)
 24 |     See Also:
 25 |       LayerMaterialIndex
 26 |       IsMaterialDefault
 27 |     """
 28 |     layer = __getlayer(layer, True)
 29 |     if layer.RenderMaterialIndex>-1: return layer.RenderMaterialIndex
 30 |     material_index = scriptcontext.doc.Materials.Add()
 31 |     layer.RenderMaterialIndex = material_index
 32 |     scriptcontext.doc.Views.Redraw()
 33 |     return material_index
 34 |     #return scriptcontext.errorhandler()
 35 | 
 36 | 
 37 | def AddMaterialToObject(object_id):
 38 |     """Adds material to an object and returns the new material's index. If the
 39 |     object already has a material, the the object's current material index is
 40 |     returned.
 41 |     Parameters:
 42 |       object_id (guid): identifier of an object
 43 |     Returns:
 44 |       number: material index of the object
 45 |     Example:
 46 |       import rhinoscriptsyntax as rs
 47 |       obj = rs.GetObject()
 48 |       if obj:
 49 |           index = rs.ObjectMaterialIndex(obj)
 50 |           if index==-1: index = rs.AddMaterialToObject(obj)
 51 |     See Also:
 52 |       IsMaterialDefault
 53 |       ObjectMaterialIndex
 54 |       ObjectMaterialSource
 55 |     """
 56 |     rhino_object = rhutil.coercerhinoobject(object_id, True, True)
 57 |     attr = rhino_object.Attributes
 58 |     if attr.MaterialSource!=Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject:
 59 |         attr.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject
 60 |         scriptcontext.doc.Objects.ModifyAttributes(rhino_object, attr, True)
 61 |         attr = rhino_object.Attributes
 62 |     material_index = attr.MaterialIndex
 63 |     if material_index>-1: return material_index
 64 |     material_index = scriptcontext.doc.Materials.Add()
 65 |     attr.MaterialIndex = material_index
 66 |     scriptcontext.doc.Objects.ModifyAttributes(rhino_object, attr, True)
 67 |     return material_index
 68 | 
 69 |     
 70 | def CopyMaterial(source_index, destination_index):
 71 |     """Copies definition of a source material to a destination material
 72 |     Parameters:
 73 |       source_index, destination_index (number): indices of materials to copy
 74 |     Returns:
 75 |       bool: True or False indicating success or failure
 76 |     Example:
 77 |       import rhinoscriptsyntax as rs
 78 |       src = rs.LayerMaterialIndex("Default")
 79 |       dest = rs.LayerMaterialIndex(rs.CurrentLayer())
 80 |       if src>=0 and dest>=0 and src!=dest:
 81 |           rs.CopyMaterial( src, dest )
 82 |     See Also:
 83 |       LayerMaterialIndex
 84 |       ObjectMaterialIndex
 85 |     """
 86 |     if source_index==destination_index: return False
 87 |     source = scriptcontext.doc.Materials[source_index]
 88 |     if source is None: return False
 89 |     rc = scriptcontext.doc.Materials.Modify(source, destination_index, True)
 90 |     if rc: scriptcontext.doc.Views.Redraw()
 91 |     return rc
 92 | 
 93 | 
 94 | def IsMaterialDefault(material_index):
 95 |     """Verifies a material is a copy of Rhino's built-in "default" material.
 96 |     The default material is used by objects and layers that have not been
 97 |     assigned a material.
 98 |     Parameters:
 99 |       material_index (number): the zero-based material index
100 |     Returns:
101 |       bool: True or False indicating success or failure
102 |     Example:
103 |       import rhinoscriptsyntax as rs
104 |       obj = rs.GetObject()
105 |       if obj:
106 |           index = rs.ObjectMaterialIndex(obj)
107 |           if rs.IsMaterialDefault(index):
108 |               print("Object is assigned default material.")
109 |           else:
110 |               print("Object is not assigned default material.")
111 |     See Also:
112 |       LayerMaterialIndex
113 |       ObjectMaterialIndex
114 |     """
115 |     mat = scriptcontext.doc.Materials[material_index]
116 |     return mat and mat.IsDefaultMaterial
117 | 
118 | 
119 | def IsMaterialReference(material_index):
120 |     """Verifies a material is referenced from another file
121 |     Parameters:
122 |       material_index (number): the zero-based material index
123 |     Returns:
124 |       bool: True or False indicating success or failure
125 |     Example:
126 |       import rhinoscriptsyntax as rs
127 |       obj = rs.GetObject()
128 |       if obj:
129 |           index = rs.ObjectMaterialIndex(obj)
130 |           if rs.IsMaterialReference(index):
131 |               print("The material is referenced from another file.")
132 |           else:
133 |               print("The material is not referenced from another file.")
134 |     See Also:
135 |       IsLayerReference
136 |       IsLightReference
137 |       IsObjectReference
138 |     """
139 |     mat = scriptcontext.doc.Materials[material_index]
140 |     return mat and mat.IsReference
141 | 
142 | 
143 | def MatchMaterial(source, destination):
144 |     """Copies the material definition from one material to one or more objects
145 |     Parameters:
146 |       source (number|guid): source material index -or- identifier of the source object.
147 |         The object must have a material assigned
148 |       destination ([guid, ...]) identifiers(s) of the destination object(s)
149 |     Returns:
150 |       number: number of objects that were modified if successful
151 |       None: if not successful or on error
152 |     Example:
153 |       import rhinoscriptsyntax as rs
154 |       obj = rs.GetObject("Select source object")
155 |       if obj and rs.ObjectMaterialIndex(obj)>-1:
156 |           objects = rs.GetObjects("Select destination objects")
157 |           if objects: rs.MatchMaterial( obj, objects )
158 |     See Also:
159 |       CopyMaterial
160 |       LayerMaterialIndex
161 |       ObjectMaterialIndex
162 |     """
163 |     source_id = rhutil.coerceguid(source)
164 |     source_mat = None
165 |     if source_id:
166 |         rhobj = rhutil.coercerhinoobject(source_id, True, True)
167 |         source = rhobj.Attributes.MaterialIndex
168 |     mat = scriptcontext.doc.Materials[source]
169 |     if not mat: return scriptcontext.errorhandler()
170 |     destination_id = rhutil.coerceguid(destination)
171 |     if destination_id: destination = [destination]
172 |     ids = [rhutil.coerceguid(d) for d in destination]
173 |     rc = 0
174 |     for id in ids:
175 |         rhobj = scriptcontext.doc.Objects.Find(id)
176 |         if rhobj:
177 |             rhobj.Attributes.MaterialIndex = source
178 |             rhobj.Attributes.MaterialSource = Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject
179 |             rhobj.CommitChanges()
180 |             rc += 1
181 |     if rc>0: scriptcontext.doc.Views.Redraw()
182 |     return rc
183 | 
184 | 
185 | def MaterialBump(material_index, filename=None):
186 |     """Returns or modifies a material's bump bitmap filename
187 |     Parameters:
188 |       material_index (number): zero based material index
189 |       filename (str, optional): the bump bitmap filename
190 |     Returns:
191 |       str: if filename is not specified, the current bump bitmap filename
192 |       str: if filename is specified, the previous bump bitmap filename
193 |       None: if not successful or on error
194 |     Example:
195 |       import rhinoscriptsyntax as rs
196 |       obj = rs.GetObject("Select object")
197 |       if obj:
198 |           index = rs.ObjectMaterialIndex(obj)
199 |           if index>-1:
200 |               rs.MaterialBump( index, "C:\\Users\\Steve\\Desktop\\bumpimage.png" )
201 |     See Also:
202 |       MaterialColor
203 |       MaterialName
204 |       MaterialReflectiveColor
205 |       MaterialShine
206 |       MaterialTexture
207 |       MaterialTransparency
208 |     """
209 |     mat = scriptcontext.doc.Materials[material_index]
210 |     if mat is None: return scriptcontext.errorhandler()
211 |     texture = mat.GetBumpTexture()
212 |     rc = texture.FileName if texture else ""
213 |     if filename:
214 |         mat.SetBumpTexture(filename)
215 |         mat.CommitChanges()
216 |         scriptcontext.doc.Views.Redraw()
217 |     return rc
218 | 
219 | 
220 | def MaterialColor(material_index, color=None):
221 |     """Returns or modifies a material's diffuse color.
222 |     Parameters:
223 |       material_index (number): zero based material index
224 |       color (color, optional): the new color value
225 |     Returns:
226 |       color: if color is not specified, the current material color
227 |       color: if color is specified, the previous material color
228 |       None: on error
229 |     Example:
230 |       import rhinoscriptsyntax as rs
231 |       obj = rs.GetObject("Select object")
232 |       if obj:
233 |           index = rs.ObjectMaterialIndex(obj)
234 |           if index>-1:
235 |               rs.MaterialColor( index, (127, 255, 191) )
236 |     See Also:
237 |       MaterialBump
238 |       MaterialName
239 |       MaterialReflectiveColor
240 |       MaterialShine
241 |       MaterialTexture
242 |       MaterialTransparency
243 |     """
244 |     mat = scriptcontext.doc.Materials[material_index]
245 |     if mat is None: return scriptcontext.errorhandler()
246 |     rc = mat.DiffuseColor
247 |     color = rhutil.coercecolor(color)
248 |     if color:
249 |         mat.DiffuseColor = color
250 |         mat.CommitChanges()
251 |         scriptcontext.doc.Views.Redraw()
252 |     return rc
253 | 
254 | 
255 | def MaterialEnvironmentMap(material_index, filename=None):
256 |     """Returns or modifies a material's environment bitmap filename.
257 |     Parameters:
258 |       material_index (number): zero based material index
259 |       filename (str, optional): the environment bitmap filename
260 |     Returns:
261 |       str: if filename is not specified, the current environment bitmap filename
262 |       str: if filename is specified, the previous environment bitmap filename
263 |       None: if not successful or on error
264 |     Example:
265 |       import rhinoscriptsyntax as rs
266 |       obj = rs.GetObject("Select object")
267 |       if obj:
268 |           index = rs.ObjectMaterialIndex(obj)
269 |           if index>-1:
270 |               rs.MaterialEnvironmentMap( index, "C:\\Users\\Steve\\Desktop\\emapimage.png" )
271 |     See Also:
272 |       MaterialBump
273 |       MaterialTexture
274 |       MaterialTransparencyMap
275 |     """
276 |     mat = scriptcontext.doc.Materials[material_index]
277 |     if mat is None: return scriptcontext.errorhandler()
278 |     texture = mat.GetEnvironmentTexture()
279 |     rc = texture.FileName if texture else ""
280 |     if filename:
281 |         mat.SetEnvironmentTexture(filename)
282 |         mat.CommitChanges()
283 |         scriptcontext.doc.Views.Redraw()
284 |     return rc
285 | 
286 | 
287 | def MaterialName(material_index, name=None):
288 |     """Returns or modifies a material's user defined name
289 |     Parameters:
290 |       material_index (number): zero based material index
291 |       name (str, optional): the new name
292 |     Returns:
293 |       str: if name is not specified, the current material name
294 |       str: if name is specified, the previous material name
295 |       None: on error
296 |     Example:
297 |       import rhinoscriptsyntax as rs
298 |       obj = rs.GetObject("Select object")
299 |       if obj:
300 |           index = rs.ObjectMaterialIndex(obj)
301 |           if index>-1:
302 |               rs.MaterialName( index, "Fancy_Material" )
303 |     See Also:
304 |       MaterialBump
305 |       MaterialColor
306 |       MaterialReflectiveColor
307 |       MaterialShine
308 |       MaterialTexture
309 |       MaterialTransparency
310 |     """
311 |     mat = scriptcontext.doc.Materials[material_index]
312 |     if mat is None: return scriptcontext.errorhandler()
313 |     rc = mat.Name
314 |     if name:
315 |         mat.Name = name
316 |         mat.CommitChanges()
317 |     return rc
318 | 
319 | 
320 | def MaterialReflectiveColor(material_index, color=None):
321 |     """Returns or modifies a material's reflective color.
322 |     Parameters:
323 |       material_index (number): zero based material index
324 |       color (color, optional): the new color value
325 |     Returns:
326 |       color: if color is not specified, the current material reflective color
327 |       color: if color is specified, the previous material reflective color
328 |       None: on error
329 |     Example:
330 |       import rhinoscriptsyntax as rs
331 |       obj = rs.GetObject("Select object")
332 |       if obj:
333 |           index = rs.ObjectMaterialIndex(obj)
334 |           if index>-1:
335 |               rs.MaterialReflectiveColor( index, (191, 191, 255) )
336 |     See Also:
337 |       MaterialBump
338 |       MaterialColor
339 |       MaterialName
340 |       MaterialShine
341 |       MaterialTexture
342 |       MaterialTransparency
343 |     """
344 |     mat = scriptcontext.doc.Materials[material_index]
345 |     if mat is None: return scriptcontext.errorhandler()
346 |     rc = mat.ReflectionColor
347 |     color = rhutil.coercecolor(color)
348 |     if color:
349 |         mat.ReflectionColor = color
350 |         mat.CommitChanges()
351 |         scriptcontext.doc.Views.Redraw()
352 |     return rc
353 | 
354 | 
355 | def MaterialShine(material_index, shine=None):
356 |     """Returns or modifies a material's shine value
357 |     Parameters:
358 |       material_index (number): zero based material index
359 |       shine (number, optional): the new shine value. A material's shine value ranges from 0.0 to 255.0, with
360 |         0.0 being matte and 255.0 being glossy
361 |     Returns:
362 |       number: if shine is not specified, the current material shine value
363 |       number: if shine is specified, the previous material shine value
364 |       None: on error
365 |     Example:
366 |       import rhinoscriptsyntax as rs
367 |       MAX_SHINE = 255.0
368 |       obj = rs.GetObject("Select object")
369 |       if obj:
370 |           index = rs.ObjectMaterialIndex(obj)
371 |           if index>-1:
372 |               rs.MaterialShine( index, MAX_SHINE/2 )
373 |     See Also:
374 |       MaterialBump
375 |       MaterialColor
376 |       MaterialName
377 |       MaterialReflectiveColor
378 |       MaterialTexture
379 |       MaterialTransparency
380 |     """
381 |     mat = scriptcontext.doc.Materials[material_index]
382 |     if mat is None: return scriptcontext.errorhandler()
383 |     rc = mat.Shine
384 |     if shine:
385 |         mat.Shine = shine
386 |         mat.CommitChanges()
387 |         scriptcontext.doc.Views.Redraw()
388 |     return rc
389 | 
390 | 
391 | def MaterialTexture(material_index, filename=None):
392 |     """Returns or modifies a material's texture bitmap filename
393 |     Parameters:
394 |       material_index (number): zero based material index
395 |       filename (str, optional): the texture bitmap filename
396 |     Returns:
397 |       str: if filename is not specified, the current texture bitmap filename
398 |       str: if filename is specified, the previous texture bitmap filename
399 |       None: if not successful or on error
400 |     Example:
401 |       import rhinoscriptsyntax as rs
402 |       obj = rs.GetObject("Select object")
403 |       if obj:
404 |           index = rs.ObjectMaterialIndex(obj)
405 |           if index>-1:
406 |               rs.MaterialTexture( index, "C:\\Users\\Steve\\Desktop\\textureimage.png" )
407 |     See Also:
408 |       MaterialBump
409 |       MaterialColor
410 |       MaterialName
411 |       MaterialReflectiveColor
412 |       MaterialShine
413 |       MaterialTransparency
414 |     """
415 |     mat = scriptcontext.doc.Materials[material_index]
416 |     if mat is None: return scriptcontext.errorhandler()
417 |     texture = mat.GetBitmapTexture()
418 |     rc = texture.FileName if texture else ""
419 |     if filename:
420 |         mat.SetBitmapTexture(filename)
421 |         mat.CommitChanges()
422 |         scriptcontext.doc.Views.Redraw()
423 |     return rc
424 | 
425 | 
426 | def MaterialTransparency(material_index, transparency=None):
427 |     """Returns or modifies a material's transparency value
428 |     Parameters:
429 |       material_index (number): zero based material index
430 |       transparency (number, optional): the new transparency value. A material's transparency value ranges from 0.0 to 1.0, with
431 |         0.0 being opaque and 1.0 being transparent
432 |     Returns:
433 |       number: if transparency is not specified, the current material transparency value
434 |       number: if transparency is specified, the previous material transparency value
435 |       None: on error
436 |     Example:
437 |       import rhinoscriptsyntax as rs
438 |       obj = rs.GetObject("Select object")
439 |       if obj:
440 |           index = rs.ObjectMaterialIndex(obj)
441 |           if index>-1:
442 |               rs.MaterialTransparency( index, 0.50 )
443 |     See Also:
444 |       MaterialBump
445 |       MaterialColor
446 |       MaterialName
447 |       MaterialReflectiveColor
448 |       MaterialShine
449 |       MaterialTexture
450 |     """
451 |     mat = scriptcontext.doc.Materials[material_index]
452 |     if mat is None: return scriptcontext.errorhandler()
453 |     rc = mat.Transparency
454 |     if transparency:
455 |         mat.Transparency = transparency
456 |         mat.CommitChanges()
457 |         scriptcontext.doc.Views.Redraw()
458 |     return rc
459 | 
460 | 
461 | def MaterialTransparencyMap(material_index, filename=None):
462 |     """Returns or modifies a material's transparency bitmap filename
463 |     Parameters:
464 |       material_index (number): zero based material index
465 |       filename (str, optional): the transparency bitmap filename
466 |     Returns:
467 |       str: if filename is not specified, the current transparency bitmap filename
468 |       str: if filename is specified, the previous transparency bitmap filename
469 |       None: if not successful or on error
470 |     Example:
471 |       import rhinoscriptsyntax as rs
472 |       obj = rs.GetObject("Select object")
473 |       if obj:
474 |           index = rs.ObjectMaterialIndex(obj)
475 |           if index>-1:
476 |               rs.MaterialTransparencyMap( index, "C:\\Users\\Steve\\Desktop\\texture.png" )
477 |     See Also:
478 |       MaterialBump
479 |       MaterialEnvironmentMap
480 |       MaterialTexture
481 |     """
482 |     mat = scriptcontext.doc.Materials[material_index]
483 |     if mat is None: return scriptcontext.errorhandler()
484 |     texture = mat.GetTransparencyTexture()
485 |     rc = texture.FileName if texture else ""
486 |     if filename:
487 |         mat.SetTransparencyTexture(filename)
488 |         mat.CommitChanges()
489 |         scriptcontext.doc.Views.Redraw()
490 |     return rc
491 | 
492 | 
493 | def ResetMaterial(material_index):
494 |     """Resets a material to Rhino's default material
495 |     Parameters:
496 |       material_index (number) zero based material index
497 |     Returns:
498 |       bool: True or False indicating success or failure
499 |     Example:
500 |       import rhinoscriptsyntax as rs
501 |       obj = rs.GetObject("Select object")
502 |       if obj:
503 |           index = rs.ObjectMaterialIndex(obj)
504 |           if index>-1: rs.ResetMaterial(index)
505 |     See Also:
506 |       LayerMaterialIndex
507 |       ObjectMaterialIndex
508 |     """
509 |     mat = scriptcontext.doc.Materials[material_index]
510 |     if mat is None: return False
511 |     rc = scriptcontext.doc.Materials.ResetMaterial(material_index)
512 |     scriptcontext.doc.Views.Redraw()
513 |     return rc
514 | 
```

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

```python
  1 | import math
  2 | 
  3 | import Rhino.Geometry
  4 | 
  5 | import scriptcontext
  6 | 
  7 | from rhinoscript import utility as rhutil
  8 | 
  9 | 
 10 | def DistanceToPlane(plane, point):
 11 |     """Returns the distance from a 3D point to a plane
 12 |     Parameters:
 13 |       plane (plane): the plane
 14 |       point (point): List of 3 numbers or Point3d
 15 |     Returns:
 16 |       number: The distance if successful, otherwise None
 17 |     Example:
 18 |       import rhinoscriptsyntax as rs
 19 |       point = rs.GetPoint("Point to test")
 20 |       if point:
 21 |           plane = rs.ViewCPlane()
 22 |           if plane:
 23 |               distance = rs.DistanceToPlane(plane, point)
 24 |               if distance is not None:
 25 |                   print("Distance to plane: {}".format(distance))
 26 |     See Also:
 27 |       Distance
 28 |       PlaneClosestPoint
 29 |     """
 30 |     plane = rhutil.coerceplane(plane, True)
 31 |     point = rhutil.coerce3dpoint(point, True)
 32 |     return plane.DistanceTo(point)
 33 | 
 34 | 
 35 | def EvaluatePlane(plane, parameter):
 36 |     """Evaluates a plane at a U,V parameter
 37 |     Parameters:
 38 |       plane (plane): the plane to evaluate
 39 |       parameter ([number, number]): list of two numbers defining the U,V parameter to evaluate
 40 |     Returns:
 41 |       point: Point3d on success
 42 |     Example:
 43 |       import rhinoscriptsyntax as rs
 44 |       view = rs.CurrentView()
 45 |       plane = rs.ViewCPlane(view)
 46 |       point = rs.EvaluatePlane(plane, (5,5))
 47 |       rs.AddPoint( point )
 48 |     See Also:
 49 |       PlaneClosestPoint
 50 |     """
 51 |     plane = rhutil.coerceplane(plane, True)
 52 |     return plane.PointAt(parameter[0], parameter[1])
 53 | 
 54 | 
 55 | def IntersectPlanes(plane1, plane2, plane3):
 56 |     """Calculates the intersection of three planes
 57 |     Parameters:
 58 |       plane1 (plane): the 1st plane to intersect
 59 |       plane2 (plane): the 2nd plane to intersect
 60 |       plane3 (plane): the 3rd plane to intersect
 61 |     Returns:
 62 |       point: the intersection point between the 3 planes on success
 63 |       None: on error
 64 |     Example:
 65 |       import rhinoscriptsyntax as rs
 66 |       plane1 = rs.WorldXYPlane()
 67 |       plane2 = rs.WorldYZPlane()
 68 |       plane3 = rs.WorldZXPlane()
 69 |       point = rs.IntersectPlanes(plane1, plane2, plane3)
 70 |       if point: rs.AddPoint(point)
 71 |     See Also:
 72 |       LineLineIntersection
 73 |       LinePlaneIntersection
 74 |       PlanePlaneIntersection
 75 |     """
 76 |     plane1 = rhutil.coerceplane(plane1, True)
 77 |     plane2 = rhutil.coerceplane(plane2, True)
 78 |     plane3 = rhutil.coerceplane(plane3, True)
 79 |     rc, point = Rhino.Geometry.Intersect.Intersection.PlanePlanePlane(plane1, plane2, plane3)
 80 |     if rc: return point
 81 | 
 82 | 
 83 | def MovePlane(plane, origin):
 84 |     """Moves the origin of a plane
 85 |     Parameters:
 86 |       plane (plane): Plane or ConstructionPlane
 87 |       origin (point): Point3d or list of three numbers
 88 |     Returns:
 89 |       plane: moved plane
 90 |     Example:
 91 |       import rhinoscriptsyntax as rs
 92 |       origin = rs.GetPoint("CPlane origin")
 93 |       if origin:
 94 |           plane = rs.ViewCPlane()
 95 |           plane = rs.MovePlane(plane,origin)
 96 |           rs.ViewCplane(plane)
 97 |     See Also:
 98 |       PlaneFromFrame
 99 |       PlaneFromNormal
100 |       RotatePlane
101 |     """
102 |     plane = rhutil.coerceplane(plane, True)
103 |     origin = rhutil.coerce3dpoint(origin, True)
104 |     rc = Rhino.Geometry.Plane(plane)
105 |     rc.Origin = origin
106 |     return rc
107 | 
108 | 
109 | def PlaneClosestPoint(plane, point, return_point=True):
110 |     """Returns the point on a plane that is closest to a test point.
111 |     Parameters:
112 |       plane (plane): The plane
113 |       point (point): The 3-D point to test.
114 |       return_point (bool, optional): If omitted or True, then the point on the plane
115 |          that is closest to the test point is returned. If False, then the
116 |          parameter of the point on the plane that is closest to the test
117 |          point is returned.
118 |     Returns:
119 |       point: If return_point is omitted or True, then the 3-D point
120 |       point: If return_point is False, then an array containing the U,V parameters
121 |       of the point
122 |       None: if not successful, or on error.
123 |     Example:
124 |       import rhinoscriptsyntax as rs
125 |       point = rs.GetPoint("Point to test")
126 |       if point:
127 |           plane = rs.ViewCPlane()
128 |           if plane:
129 |               print(rs.PlaneClosestPoint(plane, point))
130 |     See Also:
131 |       DistanceToPlane
132 |       EvaluatePlane
133 |     """
134 |     plane = rhutil.coerceplane(plane, True)
135 |     point = rhutil.coerce3dpoint(point, True)
136 |     if return_point:
137 |         return plane.ClosestPoint(point)
138 |     else:
139 |         rc, s, t = plane.ClosestParameter(point)
140 |         if rc: return s, t
141 | 
142 | 
143 | def PlaneCurveIntersection(plane, curve, tolerance=None):
144 |     """Intersect an infinite plane and a curve object
145 |     Parameters:
146 |       plane (plane): The plane to intersect.
147 |       curve (guid): The identifier of the curve object
148 |       torerance (number, optional): The intersection tolerance. If omitted, the document's absolute tolerance is used.
149 |     Returns:
150 |       A list of intersection information tuple if successful.  The list will contain one or more of the following tuple:
151 | 
152 |         Element Type        Description
153 | 
154 |         [0]       Number      The intersection event type, either Point (1) or Overlap (2).
155 | 
156 |         [1]       Point3d     If the event type is Point (1), then the intersection point on the curve.
157 |                             If the event type is Overlap (2), then intersection start point on the curve.
158 | 
159 |         [2]       Point3d     If the event type is Point (1), then the intersection point on the curve.
160 |                             If the event type is Overlap (2), then intersection end point on the curve.
161 | 
162 |         [3]       Point3d     If the event type is Point (1), then the intersection point on the plane.
163 |                             If the event type is Overlap (2), then intersection start point on the plane.
164 | 
165 |         [4]       Point3d     If the event type is Point (1), then the intersection point on the plane.
166 | 
167 |                             If the event type is Overlap (2), then intersection end point on the plane.
168 | 
169 |         [5]       Number      If the event type is Point (1), then the curve parameter.
170 |                             If the event type is Overlap (2), then the start value of the curve parameter range.
171 |                             
172 |         [6]       Number      If the event type is Point (1), then the curve parameter.
173 |                             If the event type is Overlap (2),  then the end value of the curve parameter range.
174 | 
175 |         [7]       Number      If the event type is Point (1), then the U plane parameter.
176 |                             If the event type is Overlap (2), then the U plane parameter for curve at (n, 5).
177 | 
178 |         [8]       Number      If the event type is Point (1), then the V plane parameter.
179 |                             If the event type is Overlap (2), then the V plane parameter for curve at (n, 5).
180 | 
181 |         [9]       Number      If the event type is Point (1), then the U plane parameter.
182 |                             If the event type is Overlap (2), then the U plane parameter for curve at (n, 6).
183 |                             
184 |         [10]      Number      If the event type is Point (1), then the V plane parameter.
185 |                             If the event type is Overlap (2), then the V plane parameter for curve at (n, 6).
186 | 
187 |       None: on error
188 |     Example:
189 |       import rhinoscriptsyntax as rs
190 |       curve = rs.GetObject("Select curve", rs.filter.curve)
191 |       if curve:
192 |           plane = rs.WorldXYPlane()
193 |           intersections = rs.PlaneCurveIntersection(plane, curve)
194 |           if intersections:
195 |               for intersection in intersections:
196 |                   rs.AddPoint(intersection[1])
197 |     See Also:
198 |       IntersectPlanes
199 |       PlanePlaneIntersection
200 |       PlaneSphereIntersection
201 |     """
202 |     plane = rhutil.coerceplane(plane, True)
203 |     curve = rhutil.coercecurve(curve, -1, True)
204 |     if tolerance is None: tolerance = scriptcontext.doc.ModelAbsoluteTolerance
205 |     intersections = Rhino.Geometry.Intersect.Intersection.CurvePlane(curve, plane, tolerance)
206 |     if intersections:
207 |         rc = []
208 |         for intersection in intersections:
209 |             a = 1
210 |             if intersection.IsOverlap: a = 2
211 |             b = intersection.PointA
212 |             c = intersection.PointA2
213 |             d = intersection.PointB
214 |             e = intersection.PointB2
215 |             f = intersection.ParameterA
216 |             g = intersection.ParameterB
217 |             h = intersection.OverlapA[0]
218 |             i = intersection.OverlapA[1]
219 |             j = intersection.OverlapB[0]
220 |             k = intersection.OverlapB[1]
221 |             rc.append( (a,b,c,d,e,f,g,h,i,j,k) )
222 |         return rc
223 | 
224 | 
225 | def PlaneEquation(plane):
226 |     """Returns the equation of a plane as a tuple of four numbers. The standard
227 |     equation of a plane with a non-zero vector is Ax+By+Cz+D=0
228 |     Parameters:
229 |       plane (plane): the plane to deconstruct
230 |     Returns:
231 |       tuple(number, number, number, number): containing four numbers that represent the coefficients of the equation  (A, B, C, D) if successful
232 |       None: if not successful
233 |     Example:
234 |       import rhinoscriptsyntax as rs
235 |       plane = rs.ViewCPlane()
236 |       equation = rs.PlaneEquation(plane)
237 |       print("A = {}".format(equation[0]))
238 |       print("B = {}".format(equation[1]))
239 |       print("C = {}".format(equation[2]))
240 |       print("D = {}".format(equation[3]))
241 |     See Also:
242 |       PlaneFromFrame
243 |       PlaneFromNormal
244 |       PlaneFromPoints
245 |     """
246 |     plane = rhutil.coerceplane(plane, True)
247 |     rc = plane.GetPlaneEquation()
248 |     return rc[0], rc[1], rc[2], rc[3]
249 | 
250 | 
251 | def PlaneFitFromPoints(points):
252 |     """Returns a plane that was fit through an array of 3D points.
253 |     Parameters:
254 |     points (point): An array of 3D points.
255 |     Returns: 
256 |       plane: The plane if successful
257 |       None: if not successful
258 |     Example:
259 |       import rhinoscriptsyntax as rs
260 |       points = rs.GetPoints()
261 |       if points:
262 |           plane = rs.PlaneFitFromPoints(points)
263 |           if plane:
264 |               magX = plane.XAxis.Length
265 |               magY = plane.YAxis.Length
266 |               rs.AddPlaneSurface( plane, magX, magY )
267 |     See Also:
268 |       PlaneFromFrame
269 |       PlaneFromNormal
270 |       PlaneFromPoints
271 |     """
272 |     points = rhutil.coerce3dpointlist(points, True)
273 |     rc, plane = Rhino.Geometry.Plane.FitPlaneToPoints(points)
274 |     if rc==Rhino.Geometry.PlaneFitResult.Success: return plane
275 | 
276 | 
277 | def PlaneFromFrame(origin, x_axis, y_axis):
278 |     """Construct a plane from a point, and two vectors in the plane.
279 |     Parameters:
280 |       origin (point): A 3D point identifying the origin of the plane.
281 |       x_axis (vector): A non-zero 3D vector in the plane that determines the X axis
282 |                direction.
283 |       y_axis (vector): A non-zero 3D vector not parallel to x_axis that is used
284 |                to determine the Y axis direction. Note, y_axis does not
285 |                have to be perpendicular to x_axis.
286 |     Returns:
287 |       plane: The plane if successful.
288 |     Example:
289 |       import rhinoscriptsyntax as rs
290 |       origin = rs.GetPoint("CPlane origin")
291 |       if origin:
292 |           xaxis = (1,0,0)
293 |           yaxis = (0,0,1)
294 |           plane = rs.PlaneFromFrame( origin, xaxis, yaxis )
295 |           rs.ViewCPlane(None, plane)
296 |     See Also:
297 |       MovePlane
298 |       PlaneFromNormal
299 |       PlaneFromPoints
300 |       RotatePlane
301 |     """
302 |     origin = rhutil.coerce3dpoint(origin, True)
303 |     x_axis = rhutil.coerce3dvector(x_axis, True)
304 |     y_axis = rhutil.coerce3dvector(y_axis, True)
305 |     return Rhino.Geometry.Plane(origin, x_axis, y_axis)
306 | 
307 | 
308 | def PlaneFromNormal(origin, normal, xaxis=None):
309 |     """Creates a plane from an origin point and a normal direction vector.
310 |     Parameters:
311 |       origin (point): A 3D point identifying the origin of the plane.
312 |       normal (vector): A 3D vector identifying the normal direction of the plane.
313 |       xaxis (vector, optional): optional vector defining the plane's x-axis
314 |     Returns:
315 |       plane: The plane if successful.
316 |     Example:
317 |       import rhinoscriptsyntax as rs
318 |       origin = rs.GetPoint("CPlane origin")
319 |       if origin:
320 |           direction = rs.GetPoint("CPlane direction")
321 |           if direction:
322 |               normal = direction - origin
323 |               normal = rs.VectorUnitize(normal)
324 |               rs.ViewCPlane( None, rs.PlaneFromNormal(origin, normal) )
325 |     See Also:
326 |       MovePlane
327 |       PlaneFromFrame
328 |       PlaneFromPoints
329 |       RotatePlane
330 |     """
331 |     origin = rhutil.coerce3dpoint(origin, True)
332 |     normal = rhutil.coerce3dvector(normal, True)
333 |     rc = Rhino.Geometry.Plane(origin, normal)
334 |     if xaxis:
335 |         xaxis = rhutil.coerce3dvector(xaxis, True)
336 |         xaxis = Rhino.Geometry.Vector3d(xaxis)#prevent original xaxis parameter from being unitized too
337 |         xaxis.Unitize()
338 |         yaxis = Rhino.Geometry.Vector3d.CrossProduct(rc.Normal, xaxis)
339 |         rc = Rhino.Geometry.Plane(origin, xaxis, yaxis)
340 |     return rc
341 | 
342 | 
343 | def PlaneFromPoints(origin, x, y):
344 |     """Creates a plane from three non-colinear points
345 |     Parameters:
346 |       origin (point): origin point of the plane
347 |       x, y (point): points on the plane's x and y axes
348 |     Returns:
349 |       plane: The plane if successful, otherwise None
350 |     Example:
351 |       import rhinoscriptsyntax as rs
352 |       corners = rs.GetRectangle()
353 |       if corners:
354 |           rs.ViewCPlane( rs.PlaneFromPoints(corners[0], corners[1], corners[3]))
355 |     See Also:
356 |       PlaneFromFrame
357 |       PlaneFromNormal
358 |     """
359 |     origin = rhutil.coerce3dpoint(origin, True)
360 |     x = rhutil.coerce3dpoint(x, True)
361 |     y = rhutil.coerce3dpoint(y, True)
362 |     plane = Rhino.Geometry.Plane(origin, x, y)
363 |     if plane.IsValid: return plane
364 | 
365 | 
366 | def PlanePlaneIntersection(plane1, plane2):
367 |     """Calculates the intersection of two planes
368 |     Parameters:
369 |       plane1 (plane): the 1st plane to intersect
370 |       plane2 (plane): the 2nd plane to intersect
371 |     Returns:
372 |       line:  a line with two 3d points identifying the starting/ending points of the intersection
373 |       None: on error
374 |     Example:
375 |       import rhinoscriptsyntax as rs
376 |       plane1 = rs.WorldXYPlane()
377 |       plane2 = rs.WorldYZPlane()
378 |       line = rs.PlanePlaneIntersection(plane1, plane2)
379 |       if line: rs.AddLine(line[0], line[1])
380 |     See Also:
381 |       IntersectPlanes
382 |       LineLineIntersection
383 |       LinePlaneIntersection
384 |     """
385 |     plane1 = rhutil.coerceplane(plane1, True)
386 |     plane2 = rhutil.coerceplane(plane2, True)
387 |     rc, line = Rhino.Geometry.Intersect.Intersection.PlanePlane(plane1, plane2)
388 |     if rc: return line.From, line.To
389 | 
390 | 
391 | def PlaneSphereIntersection(plane, sphere_plane, sphere_radius):
392 |     """Calculates the intersection of a plane and a sphere
393 |     Parameters:
394 |       plane (plane): the plane to intersect
395 |       sphere_plane (plane): equatorial plane of the sphere. origin of the plane is
396 |         the center of the sphere
397 |       sphere_radius (number): radius of the sphere
398 |     Returns:
399 |       list(number, point|plane, number): of intersection results
400 |           Element    Type      Description
401 |           [0]       number     The type of intersection, where 0 = point and 1 = circle.
402 |           [1]   point or plane If a point intersection, the a Point3d identifying the 3-D intersection location.
403 |                                If a circle intersection, then the circle's plane. The origin of the plane will be the center point of the circle
404 |           [2]       number     If a circle intersection, then the radius of the circle.
405 |       None: on error
406 |     Example:
407 |       import rhinoscriptsyntax as rs
408 |       plane = rs.WorldXYPlane()
409 |       radius = 10
410 |       results = rs.PlaneSphereIntersection(plane, plane, radius)
411 |       if results:
412 |           if results[0]==0:
413 |               rs.AddPoint(results[1])
414 |           else:
415 |               rs.AddCircle(results[1], results[2])
416 |     See Also:
417 |       IntersectPlanes
418 |       LinePlaneIntersection
419 |       PlanePlaneIntersection
420 |     """
421 |     plane = rhutil.coerceplane(plane, True)
422 |     sphere_plane = rhutil.coerceplane(sphere_plane, True)
423 |     sphere = Rhino.Geometry.Sphere(sphere_plane, sphere_radius)
424 |     rc, circle = Rhino.Geometry.Intersect.Intersection.PlaneSphere(plane, sphere)
425 |     if rc==Rhino.Geometry.Intersect.PlaneSphereIntersection.Point:
426 |         return 0, circle.Center
427 |     if rc==Rhino.Geometry.Intersect.PlaneSphereIntersection.Circle:
428 |         return 1, circle.Plane, circle.Radius
429 | 
430 | 
431 | def PlaneTransform(plane, xform):
432 |     """Transforms a plane
433 |     Parameters:
434 |       plane (plane): Plane to transform
435 |       xform (transform): Transformation to apply
436 |     Returns:
437 |       plane:the resulting plane if successful
438 |       None: if not successful
439 |     Example:
440 |       import rhinoscriptsyntax as rs
441 |       plane = rs.ViewCPlane()
442 |       xform = rs.XformRotation(45.0, plane.Zaxis, plane.Origin)
443 |       plane = rs.PlaneTransform(plane, xform)
444 |       rs.ViewCPlane(None, plane)
445 |     See Also:
446 |       PlaneFromFrame
447 |       PlaneFromNormal
448 |       PlaneFromPoints
449 |     """
450 |     plane = rhutil.coerceplane(plane, True)
451 |     xform = rhutil.coercexform(xform, True)
452 |     rc = Rhino.Geometry.Plane(plane)
453 |     if rc.Transform(xform): return rc
454 | 
455 | 
456 | def RotatePlane(plane, angle_degrees, axis):
457 |     """Rotates a plane
458 |     Parameters:
459 |       plane (plane): Plane to rotate
460 |       angle_degrees (number): rotation angle in degrees
461 |       axis (vector): Axis of rotation or list of three numbers
462 |     Returns:
463 |       plane: rotated plane on success
464 |     Example:
465 |       import rhinoscriptsyntax as rs
466 |       plane = rs.ViewCPlane()
467 |       rotated = rs.RotatePlane(plane, 45.0, plane.XAxis)
468 |       rs.ViewCPlane( None, rotated )
469 |     See Also:
470 |       MovePlane
471 |       PlaneFromFrame
472 |       PlaneFromNormal
473 |     """
474 |     plane = rhutil.coerceplane(plane, True)
475 |     axis = rhutil.coerce3dvector(axis, True)
476 |     angle_radians = math.radians(angle_degrees)
477 |     rc = Rhino.Geometry.Plane(plane)
478 |     if rc.Rotate(angle_radians, axis): return rc
479 | 
480 | 
481 | def WorldXYPlane():
482 |     """Returns Rhino's world XY plane
483 |     Returns:
484 |       plane: Rhino's world XY plane
485 |     Example:
486 |       import rhinoscriptsyntax as rs
487 |       view = rs.CurrentView()
488 |       rs.ViewCPlane( view, rs.WorldXYPlane() )
489 |     See Also:
490 |       WorldYZPlane
491 |       WorldZXPlane
492 |     """
493 |     return Rhino.Geometry.Plane.WorldXY
494 | 
495 | 
496 | def WorldYZPlane():
497 |     """Returns Rhino's world YZ plane
498 |     Returns:
499 |       plane: Rhino's world YZ plane
500 |     Example:
501 |       import rhinoscriptsyntax as rs
502 |       view = rs.CurrentView()
503 |       rs.ViewCPlane( view, rs.WorldYZPlane() )
504 |     See Also:
505 |       WorldXYPlane
506 |       WorldZXPlane
507 |     """
508 |     return Rhino.Geometry.Plane.WorldYZ
509 | 
510 | 
511 | def WorldZXPlane():
512 |     """Returns Rhino's world ZX plane
513 |     Returns:
514 |       plane: Rhino's world ZX plane
515 |     Example:
516 |       import rhinoscriptsyntax as rs
517 |       view = rs.CurrentView()
518 |       rs.ViewCPlane( view, rs.WorldZXPlane() )
519 |     See Also:
520 |       WorldXYPlane
521 |       WorldYZPlane
522 |     """
523 |     return Rhino.Geometry.Plane.WorldZX
```

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

```python
  1 | import System
  2 | 
  3 | import Rhino
  4 | 
  5 | import scriptcontext
  6 | 
  7 | from rhinoscript import utility as rhutil
  8 | 
  9 | 
 10 | def __initHatchPatterns():
 11 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Solid.Name) is None:
 12 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Solid)
 13 | 
 14 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch1.Name) is None:
 15 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch1)
 16 | 
 17 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch2.Name) is None:
 18 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch2)
 19 | 
 20 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Hatch3.Name) is None:
 21 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Hatch3)
 22 | 
 23 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Dash.Name) is None:
 24 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Dash)
 25 | 
 26 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Grid.Name) is None:
 27 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Grid)
 28 | 
 29 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Grid60.Name) is None:
 30 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Grid60)
 31 | 
 32 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Plus.Name) is None:
 33 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Plus)
 34 | 
 35 |     if scriptcontext.doc.HatchPatterns.FindName(Rhino.DocObjects.HatchPattern.Defaults.Squares.Name) is None:
 36 |         scriptcontext.doc.HatchPatterns.Add(Rhino.DocObjects.HatchPattern.Defaults.Squares)
 37 | 
 38 | 
 39 | def AddHatch(curve_id, hatch_pattern=None, scale=1.0, rotation=0.0):
 40 |     """Creates a new hatch object from a closed planar curve object
 41 |     Parameters:
 42 |       curve_id (guid): identifier of the closed planar curve that defines the
 43 |           boundary of the hatch object
 44 |       hatch_pattern (str, optional): name of the hatch pattern to be used by the hatch
 45 |           object. If omitted, the current hatch pattern will be used
 46 |       scale (number, optional): hatch pattern scale factor
 47 |       rotation (number, optional): hatch pattern rotation angle in degrees.
 48 |     Returns:
 49 |       guid:identifier of the newly created hatch on success
 50 |       None on error
 51 |     Example:
 52 |       import rhinoscriptsyntax as rs
 53 |       circle = rs.AddCircle(rs.WorldXYPlane(), 10.0)
 54 |       if rs.IsHatchPattern("Grid"):
 55 |           rs.AddHatch( circle, "Grid" )
 56 |       else:
 57 |           rs.AddHatch( circle, rs.CurrentHatchPattern() )
 58 |     See Also:
 59 |       AddHatches
 60 |       CurrentHatchPattern
 61 |       HatchPatternNames
 62 |     """
 63 |     rc = AddHatches(curve_id, hatch_pattern, scale, rotation)
 64 |     if rc: return rc[0]
 65 |     return scriptcontext.errorhandler()
 66 | 
 67 | 
 68 | def AddHatches(curve_ids, hatch_pattern=None, scale=1.0, rotation=0.0, tolerance=None):
 69 |     """Creates one or more new hatch objects a list of closed planar curves
 70 |     Parameters:
 71 |       curve_ids ([guid, ...]): identifiers of the closed planar curves that defines the
 72 |           boundary of the hatch objects
 73 |       hatch_pattern (str, optional):  name of the hatch pattern to be used by the hatch
 74 |           object. If omitted, the current hatch pattern will be used
 75 |       scale (number, optional): hatch pattern scale factor
 76 |       rotation (number, optional): hatch pattern rotation angle in degrees.
 77 |       tolerance (number, optional): tolerance for hatch fills.
 78 |     Returns:
 79 |       list(guid, ...): identifiers of the newly created hatch on success
 80 |       None: on error
 81 |     Example:
 82 |       import rhinoscriptsyntax as rs
 83 |       curves = rs.GetObjects("Select closed planar curves", rs.filter.curve)
 84 |       if curves:
 85 |           if rs.IsHatchPattern("Grid"):
 86 |               rs.AddHatches( curves, "Grid" )
 87 |           else:
 88 |               rs.AddHatches( curves, rs.CurrentHatchPattern() )
 89 |     See Also:
 90 |       AddHatch
 91 |       CurrentHatchPattern
 92 |       HatchPatternNames
 93 |     """
 94 |     __initHatchPatterns()
 95 |     id = rhutil.coerceguid(curve_ids, False)
 96 |     if id: curve_ids = [id]
 97 |     index = scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex
 98 |     if hatch_pattern is None:
 99 |         hatch_pattern = CurrentHatchPattern()
100 |     if isinstance(hatch_pattern, int) and hatch_pattern != index:
101 |         index = hatch_pattern
102 |     else:
103 |         pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
104 |         index = Rhino.RhinoMath.UnsetIntIndex if pattern_instance is None else pattern_instance.Index
105 |     if index<0: return scriptcontext.errorhandler()
106 |     curves = [rhutil.coercecurve(id, -1, True) for id in curve_ids]
107 |     rotation = Rhino.RhinoMath.ToRadians(rotation)
108 |     if tolerance is None or tolerance < 0:
109 |         tolerance = scriptcontext.doc.ModelAbsoluteTolerance
110 |     hatches = Rhino.Geometry.Hatch.Create(curves, index, rotation, scale, tolerance)
111 |     if not hatches: return scriptcontext.errorhandler()
112 |     ids = []
113 |     for hatch in hatches:
114 |         id = scriptcontext.doc.Objects.AddHatch(hatch)
115 |         if id==System.Guid.Empty: continue
116 |         ids.append(id)
117 |     if not ids: return scriptcontext.errorhandler()
118 |     scriptcontext.doc.Views.Redraw()
119 |     return ids
120 | 
121 | 
122 | def AddHatchPatterns(filename, replace=False):
123 |     """Adds hatch patterns to the document by importing hatch pattern definitions
124 |     from a pattern file.
125 |     Parameters:
126 |       filename (str): name of the hatch pattern file
127 |       replace (bool, optional): If hatch pattern names already in the document match hatch
128 |           pattern names in the pattern definition file, then the existing hatch
129 |           patterns will be redefined
130 |     Returns:
131 |       list(str, ...): Names of the newly added hatch patterns if successful
132 |       None: on error
133 |     Example:
134 |       import rhinoscriptsyntax as rs
135 |       filename = rs.OpenFileName("Import", "Pattern Files (*.pat)|*.pat||")
136 |       if filename:
137 |           patterns = rs.AddHatchPatterns(filename)
138 |           if patterns:
139 |               for pattern in patterns: print(pattern)
140 |     See Also:
141 |       HatchPatternCount
142 |       HatchPatternNames
143 |     """
144 |     patterns = Rhino.DocObjects.HatchPattern.ReadFromFile(filename, True)
145 |     if not patterns: return scriptcontext.errorhandler()
146 |     rc = []
147 |     for pattern in patterns:
148 |          index = scriptcontext.doc.HatchPatterns.Add(pattern)
149 |          if index>=0:
150 |              pattern = scriptcontext.doc.HatchPatterns[index]
151 |              rc.append(pattern.Name)
152 |     if not rc: return scriptcontext.errorhandler()
153 |     return rc
154 | 
155 | 
156 | def CurrentHatchPattern(hatch_pattern=None):
157 |     """Returns or sets the current hatch pattern file
158 |     Parameters:
159 |       hatch_pattern(str, optional):  name of an existing hatch pattern to make current
160 |     Returns:
161 |       str: if hatch_pattern is not specified, the current hatch pattern
162 |       str: if hatch_pattern is specified, the previous hatch pattern
163 |       None: on error
164 |     Example:
165 |       import rhinoscriptsyntax as rs
166 |       if rs.IsHatchPattern("Hatch2"): rs.CurrentHatchPattern("Hatch2")
167 |     See Also:
168 |       HatchPatternCount
169 |       HatchPatternNames
170 |     """
171 |     i = scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex
172 |     rc = scriptcontext.doc.HatchPatterns[i].Name
173 |     if hatch_pattern:
174 |         __initHatchPatterns()
175 |         pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
176 |         if pattern_instance is None: return scriptcontext.errorhandler()
177 |         scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex = pattern_instance.Index
178 |     return rc
179 | 
180 | 
181 | def ExplodeHatch(hatch_id, delete=False):
182 |     """Explodes a hatch object into its component objects. The exploded objects
183 |     will be added to the document. If the hatch object uses a solid pattern,
184 |     then planar face Brep objects will be created. Otherwise, line curve objects
185 |     will be created
186 |     Parameters:
187 |       hatch_id (guid): identifier of a hatch object
188 |       delete (bool, optional): delete the hatch object
189 |     Returns:
190 |       list(guid, ...): list of identifiers for the newly created objects
191 |       None: on error
192 |     Example:
193 |       import rhinoscriptsyntax as rs
194 |       id = rs.GetObject("Select object")
195 |       if rs.IsHatch(id): rs.ExplodeHatch(id, True)
196 |     See Also:
197 |       IsHatch
198 |       HatchPattern
199 |       HatchRotation
200 |       HatchScale
201 |     """
202 |     rhobj = rhutil.coercerhinoobject(hatch_id, True, True)
203 |     pieces = rhobj.HatchGeometry.Explode()
204 |     if not pieces: return scriptcontext.errorhandler()
205 |     attr = rhobj.Attributes
206 |     rc = []
207 |     for piece in pieces:
208 |         id = None
209 |         if isinstance(piece, Rhino.Geometry.Curve):
210 |             id = scriptcontext.doc.Objects.AddCurve(piece, attr)
211 |         elif isinstance(piece, Rhino.Geometry.Brep):
212 |             id = scriptcontext.doc.Objects.AddBrep(piece, attr)
213 |         if id: rc.append(id)
214 |     if delete: scriptcontext.doc.Objects.Delete(rhobj)
215 |     return rc
216 | 
217 | 
218 | def HatchPattern(hatch_id, hatch_pattern=None):
219 |     """Returns or changes a hatch object's hatch pattern
220 |     Parameters:
221 |       hatch_id (guid): identifier of a hatch object
222 |       hatch_pattern (str, optional): name of an existing hatch pattern to replace the
223 |           current hatch pattern
224 |     Returns:
225 |       str: if hatch_pattern is not specified, the current hatch pattern
226 |       str: if hatch_pattern is specified, the previous hatch pattern
227 |       None: on error
228 |     Example:
229 |       import rhinoscriptsyntax as rs
230 |       objects = rs.AllObjects()
231 |       if objects is not None:
232 |           for obj in objects:
233 |               if rs.IsHatch(obj) and rs.HatchPattern(obj)=="Solid":
234 |                   rs.SelectObject(obj)
235 |     See Also:
236 |       AddHatch
237 |       AddHatches
238 |       HatchRotation
239 |       HatchScale
240 |       IsHatch
241 |     """
242 |     hatchobj = rhutil.coercerhinoobject(hatch_id, True, True)
243 |     if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
244 |         return scriptcontext.errorhandler()
245 |     old_index = hatchobj.HatchGeometry.PatternIndex
246 |     if hatch_pattern:
247 |         __initHatchPatterns()
248 |         new_patt = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
249 |         if new_patt is None: return scriptcontext.errorhandler()
250 |         hatchobj.HatchGeometry.PatternIndex = new_patt.Index
251 |         hatchobj.CommitChanges()
252 |         scriptcontext.doc.Views.Redraw()
253 |     return scriptcontext.doc.HatchPatterns[old_index].Name
254 | 
255 | 
256 | def HatchPatternCount():
257 |     """Returns the number of hatch patterns in the document
258 |     Returns:
259 |       number: the number of hatch patterns in the document
260 |     Example:
261 |       import rhinoscriptsyntax as rs
262 |       print("There are {} hatch patterns.".format(rs.HatchPatternCount()))
263 |     See Also:
264 |       HatchPatternNames
265 |     """
266 |     __initHatchPatterns()
267 |     return scriptcontext.doc.HatchPatterns.Count
268 | 
269 | 
270 | def HatchPatternDescription(hatch_pattern):
271 |     """Returns the description of a hatch pattern. Note, not all hatch patterns
272 |     have descriptions
273 |     Parameters:
274 |       hatch_pattern (str): name of an existing hatch pattern
275 |     Returns:
276 |       str: description of the hatch pattern on success otherwise None
277 |     Example:
278 |       import rhinoscriptsyntax as rs
279 |       patterns = rs.HatchPatternNames()
280 |       for pattern in patterns:
281 |           description = rs.HatchPatternDescription(pattern)
282 |           if description: print("{} - {}".format(pattern, description))
283 |           else: print(pattern)
284 |     See Also:
285 |       HatchPatternCount
286 |       HatchPatternNames
287 |     """
288 |     __initHatchPatterns()
289 |     pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
290 |     if pattern_instance is None: return scriptcontext.errorhandler()
291 |     return pattern_instance.Description
292 | 
293 | 
294 | def HatchPatternFillType(hatch_pattern):
295 |     """Returns the fill type of a hatch pattern.
296 |     Parameters:
297 |       hatch_pattern (str): name of an existing hatch pattern
298 |     Returns:
299 |       number: hatch pattern's fill type if successful
300 |               0 = solid, uses object color
301 |               1 = lines, uses pattern file definition
302 |               2 = gradient, uses fill color definition
303 |       None: if unsuccessful
304 |     Example:
305 |       import rhinoscriptsyntax as rs
306 |       patterns = rs.HatchPatternNames()
307 |       for pattern in patterns:
308 |           fill = rs.HatchPatternFillType(pattern)
309 |           print("{} - {}".format(pattern, fill))
310 |     See Also:
311 |       HatchPatternCount
312 |       HatchPatternNames
313 |     """
314 |     __initHatchPatterns()
315 |     pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
316 |     if pattern_instance is None: return scriptcontext.errorhandler()
317 |     return int(pattern_instance.FillType)
318 | 
319 | 
320 | def HatchPatternNames():
321 |     """Returns the names of all of the hatch patterns in the document
322 |     Returns:
323 |       list(str, ...): the names of all of the hatch patterns in the document
324 |     Example:
325 |       import rhinoscriptsyntax as rs
326 |       patterns = rs.HatchPatternNames()
327 |       for pattern in patterns:
328 |           description = rs.HatchPatternDescription(pattern)
329 |           if description: print("{} - {}".format(pattern, description))
330 |           else: print(pattern)
331 |     See Also:
332 |       HatchPatternCount
333 |     """
334 |     __initHatchPatterns()
335 |     rc = []
336 |     for i in range(scriptcontext.doc.HatchPatterns.Count):
337 |         hatchpattern = scriptcontext.doc.HatchPatterns[i]
338 |         if hatchpattern.IsDeleted: continue
339 |         rc.append(hatchpattern.Name)
340 |     return rc
341 | 
342 | 
343 | def HatchRotation(hatch_id, rotation=None):
344 |     """Returns or modifies the rotation applied to the hatch pattern when
345 |     it is mapped to the hatch's plane
346 |     Parameters:
347 |       hatch_id (guid): identifier of a hatch object
348 |       rotation (number, optional): rotation angle in degrees
349 |     Returns:
350 |       number: if rotation is not defined, the current rotation angle
351 |       number: if rotation is specified, the previous rotation angle
352 |       None: on error
353 |     Example:
354 |       import rhinoscriptsyntax as rs
355 |       objects = rs.AllObjects()
356 |       if objects:
357 |           for obj in objects:
358 |               if rs.IsHatch(obj) and rs.HatchRotation(obj)>0:
359 |                   rs.HatchRotation(obj,0)
360 |     See Also:
361 |       AddHatch
362 |       AddHatches
363 |       HatchPattern
364 |       HatchScale
365 |       IsHatch
366 |     """
367 |     hatchobj = rhutil.coercerhinoobject(hatch_id, True, True)
368 |     if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
369 |         return scriptcontext.errorhandler()
370 |     rc = hatchobj.HatchGeometry.PatternRotation
371 |     rc = Rhino.RhinoMath.ToDegrees(rc)
372 |     if rotation is not None and rotation!=rc:
373 |         rotation = Rhino.RhinoMath.ToRadians(rotation)
374 |         hatchobj.HatchGeometry.PatternRotation = rotation
375 |         hatchobj.CommitChanges()
376 |         scriptcontext.doc.Views.Redraw()
377 |     return rc
378 | 
379 | 
380 | def HatchScale(hatch_id, scale=None):
381 |     """Returns or modifies the scale applied to the hatch pattern when it is
382 |     mapped to the hatch's plane
383 |     Parameters:
384 |       hatch_id (guid): identifier of a hatch object
385 |       scale (number, optional):  scale factor
386 |     Returns:
387 |       number: if scale is not defined, the current scale factor
388 |       number: if scale is defined, the previous scale factor
389 |       None: on error
390 |     Example:
391 |       import rhinoscriptsyntax as rs
392 |       objects = rs.NormalObjects()
393 |       if objects:
394 |           for obj in objects:
395 |               if rs.IsHatch(obj) and rs.HatchScale(obj)>1.0:
396 |                   rs.HatchScale(obj, 1.0)
397 |     See Also:
398 |       HatchPattern
399 |       HatchRotation
400 |       IsHatch
401 |     """
402 |     hatchobj = rhutil.coercerhinoobject(hatch_id)
403 |     if not isinstance(hatchobj, Rhino.DocObjects.HatchObject):
404 |         return scriptcontext.errorhandler()
405 |     rc = hatchobj.HatchGeometry.PatternScale
406 |     if scale and scale!=rc:
407 |         hatchobj.HatchGeometry.PatternScale = scale
408 |         hatchobj.CommitChanges()
409 |         scriptcontext.doc.Views.Redraw()
410 |     return rc
411 | 
412 | 
413 | def IsHatch(object_id):
414 |     """Verifies the existence of a hatch object in the document
415 |     Parameters:
416 |       object_id (guid): identifier of an object
417 |     Returns:
418 |       bool: True or False
419 |     Example:
420 |       import rhinoscriptsyntax as rs
421 |       obj = rs.GetObject("Select object")
422 |       if rs.IsHatch(obj): print("Object is a hatch")
423 |       else: print("Object is not a hatch")
424 |     See Also:
425 |       HatchPattern
426 |       HatchRotation
427 |       HatchScale
428 |     """
429 |     rhobj = rhutil.coercerhinoobject(object_id, True, False)
430 |     return isinstance(rhobj, Rhino.DocObjects.HatchObject)
431 | 
432 | 
433 | def IsHatchPattern(name):
434 |     """Verifies the existence of a hatch pattern in the document
435 |     Parameters:
436 |       name (str): the name of a hatch pattern
437 |     Returns:
438 |       bool: True or False
439 |     Example:
440 |       import rhinoscriptsyntax as rs
441 |       hatch = rs.GetString("Hatch pattern name")
442 |       if rs.IsHatchPattern(hatch): print("The hatch pattern exists.")
443 |       else: print("The hatch pattern does not exist.")
444 |     See Also:
445 |       IsHatchPatternCurrent
446 |       IsHatchPatternReference
447 |     """
448 |     __initHatchPatterns()
449 |     return scriptcontext.doc.HatchPatterns.FindName(name) is not None
450 | 
451 | 
452 | def IsHatchPatternCurrent(hatch_pattern):
453 |     """Verifies that a hatch pattern is the current hatch pattern
454 |     Parameters:
455 |       hatch_pattern (str): name of an existing hatch pattern
456 |     Returns:
457 |       bool: True or False
458 |       None: on error
459 |     Example:
460 |       import rhinoscriptsyntax as rs
461 |       hatch = rs.GetString("Hatch pattern name")
462 |       if rs.IsHatchPattern(hatch):
463 |           if rs.IsHatchPatternCurrent(hatch):
464 |               print("The hatch pattern is current.")
465 |           else:
466 |               print("The hatch pattern is not current.")
467 |       else: print("The hatch pattern does not exist.")
468 |     See Also:
469 |       IsHatchPattern
470 |       IsHatchPatternReference
471 |     """
472 |     __initHatchPatterns()
473 |     pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
474 |     if pattern_instance is None: return scriptcontext.errorhandler()
475 |     return pattern_instance.Index==scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex
476 | 
477 | 
478 | def IsHatchPatternReference(hatch_pattern):
479 |     """Verifies that a hatch pattern is from a reference file
480 |     Parameters:
481 |       hatch_pattern (str): name of an existing hatch pattern
482 |     Returns:
483 |       bool: True or False
484 |       None: on error
485 |     Example:
486 |       import rhinoscriptsyntax as rs
487 |       hatch = rs.GetString("Hatch pattern name")
488 |       if rs.IsHatchPattern(hatch):
489 |           if rs.IsHatchPatternReference(hatch):
490 |               print("The hatch pattern is reference.")
491 |           else:
492 |               print("The hatch pattern is not reference.")
493 |       else:
494 |           print("The hatch pattern does not exist.")
495 |     See Also:
496 |       IsHatchPattern
497 |       IsHatchPatternCurrent
498 |     """
499 |     __initHatchPatterns()
500 |     pattern_instance = scriptcontext.doc.HatchPatterns.FindName(hatch_pattern)
501 |     if pattern_instance is None: return scriptcontext.errorhandler()
502 |     return pattern_instance.IsReference
503 | 
```

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

```python
  1 | import math
  2 | 
  3 | import Rhino
  4 | 
  5 | import scriptcontext
  6 | 
  7 | from rhinoscript import utility as rhutil
  8 | from rhinoscript.view import __viewhelper
  9 | 
 10 | 
 11 | def IsXformIdentity(xform):
 12 |     """Verifies a matrix is the identity matrix
 13 |     Parameters:
 14 |       xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
 15 |     Returns:
 16 |       bool: True or False indicating success or failure.
 17 |     Example:
 18 |       import rhinoscriptsyntax as rs
 19 |       xform = rs.XformIdentity()
 20 |       print(rs.IsXformIdentity(xform))
 21 |     See Also:
 22 |       IsXformSimilarity
 23 |       IsXformZero
 24 |       XformIdentity
 25 |     """
 26 |     xform = rhutil.coercexform(xform, True)
 27 |     return xform==Rhino.Geometry.Transform.Identity
 28 | 
 29 | 
 30 | def IsXformSimilarity(xform):
 31 |     """Verifies a matrix is a similarity transformation. A similarity
 32 |     transformation can be broken into a sequence of dilations, translations,
 33 |     rotations, and reflections
 34 |     Parameters:
 35 |       xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
 36 |     Returns:
 37 |       bool: True if this transformation is an orientation preserving similarity, otherwise False.
 38 |     Example:
 39 |       import rhinoscriptsyntax as rs
 40 |       xform = rs.BlockInstanceXform(block)
 41 |       print(rs.IsXformSimilarity(xform))
 42 |     See Also:
 43 |       IsXformIdentity
 44 |       IsXformZero
 45 |     """
 46 |     xform = rhutil.coercexform(xform, True)
 47 |     return xform.SimilarityType!=Rhino.Geometry.TransformSimilarityType.NotSimilarity
 48 | 
 49 | 
 50 | def IsXformZero(xform):
 51 |     """verifies that a matrix is a zero transformation matrix
 52 |     Parameters:
 53 |       xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
 54 |     Returns:
 55 |       bool: True or False indicating success or failure.
 56 |     Example:
 57 |       import rhinoscriptsyntax as rs
 58 |       xform = rs.XformZero()
 59 |       print(rs.IsXformZero(xform))
 60 |     See Also:
 61 |       IsXformIdentity
 62 |       IsXformSimilarity
 63 |       XformZero
 64 |     """
 65 |     xform = rhutil.coercexform(xform, True)
 66 |     for i in range(4):
 67 |         for j in range(4):
 68 |             if xform[i,j]!=0: return False
 69 |     return True
 70 | 
 71 | 
 72 | def XformChangeBasis(initial_plane, final_plane):
 73 |     """Returns a change of basis transformation matrix or None on error
 74 |     Parameters:
 75 |       initial_plane (plane): the initial plane
 76 |       final_plane (plane): the final plane
 77 |     Returns:
 78 |       transform: The 4x4 transformation matrix if successful
 79 |       None: if not successful
 80 |     Example:
 81 |       import rhinoscriptsyntax as rs
 82 |       import math
 83 |       objs = rs.GetObjects("Select objects to shear")
 84 |       if objs:
 85 |           cplane = rs.ViewCPlane()
 86 |           cob = rs.XformChangeBasis(rs.WorldXYPlane(), cplane)
 87 |           shear2d = rs.XformIdentity()
 88 |           shear2d[0,2] = math.tan(math.radians(45.0))
 89 |           cob_inverse = rs.XformChangeBasis(cplane, rs.WorldXYPlane())
 90 |           temp = rs.XformMultiply(shear2d, cob)
 91 |           xform = rs.XformMultiply(cob_inverse, temp)
 92 |           rs.TransformObjects( objs, xform, True )
 93 |     See Also:
 94 |       XformCPlaneToWorld
 95 |       XformWorldToCPlane
 96 |     """
 97 |     initial_plane = rhutil.coerceplane(initial_plane, True)
 98 |     final_plane = rhutil.coerceplane(final_plane, True)
 99 |     xform = Rhino.Geometry.Transform.ChangeBasis(initial_plane, final_plane)
100 |     if not xform.IsValid: return scriptcontext.errorhandler()
101 |     return xform
102 | 
103 | 
104 | def XformChangeBasis2(x0,y0,z0,x1,y1,z1):
105 |     """Returns a change of basis transformation matrix of None on error
106 |     Parameters:
107 |       x0,y0,z0 (vector): initial basis
108 |       x1,y1,z1 (vector): final basis
109 |     Returns:
110 |       transform: The 4x4 transformation matrix if successful
111 |       None: if not successful
112 |     Example:
113 |     See Also:
114 |     """
115 |     x0 = rhutil.coerce3dvector(x0, True)
116 |     y0 = rhutil.coerce3dvector(y0, True)
117 |     z0 = rhutil.coerce3dvector(z0, True)
118 |     x1 = rhutil.coerce3dvector(x1, True)
119 |     y1 = rhutil.coerce3dvector(y1, True)
120 |     z1 = rhutil.coerce3dvector(z1, True)
121 |     xform = Rhino.Geometry.Transform.ChangeBasis(x0,y0,z0,x1,y1,z1)
122 |     if not xform.IsValid: return scriptcontext.errorhandler()
123 |     return xform
124 | 
125 | 
126 | def XformCompare(xform1, xform2):
127 |     """Compares two transformation matrices
128 |     Parameters:
129 |       xform1, xform2 = matrices to compare
130 |     Returns:
131 |         number:
132 |         -1 if xform1<xform2
133 |          1 if xform1>xform2
134 |          0 if xform1=xform2
135 |     Example:
136 |       import rhinoscriptsyntax as rs
137 |       xform0 = rs.XformZero()
138 |       xform1 = rs.XformIdentity()
139 |       print(rs.XformCompare(xform0, xform1))
140 |     See Also:
141 |       IsXformIdentity
142 |       IsXformSimilarity
143 |       IsXformZero
144 |     """
145 |     xform1 = rhutil.coercexform(xform1, True)
146 |     xform2 = rhutil.coercexform(xform2, True)
147 |     return xform1.CompareTo(xform2)
148 | 
149 | 
150 | def XformCPlaneToWorld(point, plane):
151 |     """Transform point from construction plane coordinates to world coordinates
152 |     Parameters:
153 |       point (point): A 3D point in construction plane coordinates.
154 |       plane (plane): The construction plane
155 |     Returns:
156 |       point: A 3D point in world coordinates
157 |     Example:
158 |       import rhinoscriptsyntax as rs
159 |       plane = rs.ViewCPlane()
160 |       point = rs.XFormCPlaneToWorld([0,0,0], plane)
161 |       if point: print("World point: {}".format(point))
162 |     See Also:
163 |       XformWorldToCPlane
164 |     """
165 |     point = rhutil.coerce3dpoint(point, True)
166 |     plane = rhutil.coerceplane(plane, True)
167 |     return plane.Origin + point.X*plane.XAxis + point.Y*plane.YAxis + point.Z*plane.ZAxis
168 | 
169 | 
170 | def XformDeterminant(xform):
171 |     """Returns the determinant of a transformation matrix. If the determinant
172 |     of a transformation matrix is 0, the matrix is said to be singular. Singular
173 |     matrices do not have inverses.
174 |     Parameters:
175 |       xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
176 |     Returns:
177 |       number: The determinant if successful
178 |       None: if not successful
179 |     Example:
180 |       import rhinoscriptsyntax as rs
181 |       xform = rs.BlockInstanceXform(obj)
182 |       if xform: print(rs.XformDeterminant(xform))
183 |     See Also:
184 |       XformInverse
185 |     """
186 |     xform = rhutil.coercexform(xform, True)
187 |     return xform.Determinant
188 | 
189 | 
190 | def XformDiagonal(diagonal_value):
191 |     """Returns a diagonal transformation matrix. Diagonal matrices are 3x3 with
192 |     the bottom row [0,0,0,1]
193 |     Parameters:
194 |       diagonal_value (number): the diagonal value
195 |     Returns:
196 |       transform: The 4x4 transformation matrix if successful
197 |       None: if not successful
198 |     Example:
199 |       import rhinoscriptsyntax as rs
200 |       def printmatrix(xform):
201 |           for i in range(4):
202 |               print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
203 |       printmatrix(rs.XformDiagonal(3))
204 |     See Also:
205 |       XformIdentity
206 |       XformZero
207 |     """
208 |     return Rhino.Geometry.Transform(diagonal_value)
209 | 
210 | 
211 | def XformIdentity():
212 |     """returns the identity transformation matrix
213 |     Returns:
214 |       transform: The 4x4 transformation matrix
215 |     Example:
216 |       import rhinoscriptsyntax as rs
217 |       def printmatrix(xform):
218 |           for i in range(4):
219 |               print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
220 |       printmatrix(rs.XformIdentity())
221 |     See Also:
222 |       XformDiagonal
223 |       XformZero
224 |     """
225 |     return Rhino.Geometry.Transform.Identity
226 | 
227 | 
228 | def XformInverse(xform):
229 |     """Returns the inverse of a non-singular transformation matrix
230 |     Parameters:
231 |       xform (transform): List or Rhino.Geometry.Transform.  A 4x4 transformation matrix.
232 |     Returns:
233 |       transform: The inverted 4x4 transformation matrix if successful.
234 |       None: if matrix is non-singular or on error.
235 |     Example:
236 |       import rhinoscriptsyntax as rs
237 |       xform = rs.BlockInstanceXform(obj)
238 |       if xform:
239 |           rs.TransformObject( obj, rs.XformInverse(xform) )
240 |     See Also:
241 |       XformDeterminant
242 |     """
243 |     xform = rhutil.coercexform(xform, True)
244 |     rc, inverse = xform.TryGetInverse()
245 |     if not rc: return scriptcontext.errorhandler()
246 |     return inverse
247 | 
248 | 
249 | def XformMirror(mirror_plane_point, mirror_plane_normal):
250 |     """Creates a mirror transformation matrix
251 |     Parameters:
252 |       mirror_plane_point (point): point on the mirror plane
253 |       mirror_plane_normal (vector): a 3D vector that is normal to the mirror plane
254 |     Returns:
255 |       transform: mirror Transform matrix
256 |     Example:
257 |       import rhinoscriptsyntax as rs
258 |       objs = rs.GetObjects("Select objects to mirror")
259 |       if objs:
260 |           plane = rs.ViewCPlane()
261 |           xform = rs.XformMirror(plane.Origin, plane.Normal)
262 |           rs.TransformObjects( objs, xform, True )
263 |     See Also:
264 |       XformPlanarProjection
265 |       XformRotation1
266 |       XformRotation2
267 |       XformRotation3
268 |       XformRotation4
269 |       XformScale
270 |       XformShear
271 |       XformTranslation
272 |     """
273 |     point = rhutil.coerce3dpoint(mirror_plane_point, True)
274 |     normal = rhutil.coerce3dvector(mirror_plane_normal, True)
275 |     return Rhino.Geometry.Transform.Mirror(point, normal)
276 | 
277 | 
278 | def XformMultiply(xform1, xform2):
279 |     """Multiplies two transformation matrices, where result = xform1 * xform2
280 |     Parameters:
281 |       xform1 (transform): List or Rhino.Geometry.Transform.  The first 4x4 transformation matrix to multiply.
282 |       xform2 (transform): List or Rhino.Geometry.Transform.  The second 4x4 transformation matrix to multiply.
283 |     Returns:
284 |       transform: result transformation on success
285 |     Example:
286 |       import rhinoscriptsyntax as rs
287 |       import math
288 |       objs = rs.GetObjects("Select objects to shear")
289 |       if objs:
290 |           cplane = rs.ViewCPlane()
291 |           cob = rs.XformChangeBasis(rs.WorldXYPlane(), cplane)
292 |           shear2d = rs.XformIdentity()
293 |           shear2d[0,2] = math.tan(math.radians(45.0))
294 |           cob_inv = rs.XformChangeBasis(cplane, rs.WorldXYPlane())
295 |           temp = rs.XformMultiply(shear2d, cob)
296 |           xform = rs.XformMultiply(cob_inv, temp)
297 |           rs.TransformObjects( objs, xform, True )
298 |     See Also:
299 |       XformPlanarProjection
300 |       XformRotation1
301 |       XformRotation2
302 |       XformRotation3
303 |       XformRotation4
304 |       XformScale
305 |       XformShear
306 |       XformTranslation
307 |     """
308 |     xform1 = rhutil.coercexform(xform1, True)
309 |     xform2 = rhutil.coercexform(xform2, True)
310 |     return xform1*xform2
311 | 
312 | 
313 | def XformPlanarProjection(plane):
314 |     """Returns a transformation matrix that projects to a plane.
315 |     Parameters:
316 |       plane (plane): The plane to project to.
317 |     Returns:
318 |       transform: The 4x4 transformation matrix.
319 |     Example:
320 |       import rhinoscriptsyntax as rs
321 |       objects = rs.GetObjects("Select objects to project")
322 |       if objects:
323 |           cplane = rs.ViewCPlane()
324 |           xform = rs.XformPlanarProjection(cplane)
325 |           rs.TransformObjects( objects, xform, True )
326 |     See Also:
327 |       XformMirror
328 |       XformRotation1
329 |       XformRotation2
330 |       XformRotation3
331 |       XformRotation4
332 |       XformScale
333 |       XformShear
334 |       XformTranslation
335 |     """
336 |     plane = rhutil.coerceplane(plane, True)
337 |     return Rhino.Geometry.Transform.PlanarProjection(plane)
338 | 
339 | 
340 | def XformRotation1(initial_plane, final_plane):
341 |     """Returns a rotation transformation that maps initial_plane to final_plane.
342 |     The planes should be right hand orthonormal planes.
343 |     Parameters:
344 |       initial_plane (plane): plane to rotate from
345 |       final_plane (plane): plane to rotate to
346 |     Returns:
347 |       transform: The 4x4 transformation matrix.
348 |       None: on error.
349 |     Example:
350 |     See Also:
351 |     """
352 |     initial_plane = rhutil.coerceplane(initial_plane, True)
353 |     final_plane = rhutil.coerceplane(final_plane, True)
354 |     xform = Rhino.Geometry.Transform.PlaneToPlane(initial_plane, final_plane)
355 |     if not xform.IsValid: return scriptcontext.errorhandler()
356 |     return xform
357 | 
358 | 
359 | def XformRotation2(angle_degrees, rotation_axis, center_point):
360 |     """Returns a rotation transformation around an axis
361 |     Parameters:
362 |       angle_degrees (number): rotation angle in degrees
363 |       rotation_axis (vector): rotation axis
364 |       center_point (point): rotation center
365 |     Returns:
366 |       transform: The 4x4 transformation matrix.
367 |       None: on error.
368 |     Example:
369 |     See Also:
370 |     """
371 |     axis = rhutil.coerce3dvector(rotation_axis, True)
372 |     center = rhutil.coerce3dpoint(center_point, True)
373 |     angle_rad = math.radians(angle_degrees)
374 |     xform = Rhino.Geometry.Transform.Rotation(angle_rad, axis, center)
375 |     if not xform.IsValid: return scriptcontext.errorhandler()
376 |     return xform
377 | 
378 | 
379 | def XformRotation3( start_direction, end_direction, center_point ):
380 |     """Calculate the minimal transformation that rotates start_direction to
381 |     end_direction while fixing center_point
382 |     Parameters:
383 |       start_direction, end_direction (vector): 3d vectors
384 |       center_point (point): the rotation center
385 |     Returns:
386 |       transform: The 4x4 transformation matrix.
387 |       None: on error.
388 |     Example:
389 |     See Also:
390 |     """
391 |     start = rhutil.coerce3dvector(start_direction, True)
392 |     end = rhutil.coerce3dvector(end_direction, True)
393 |     center = rhutil.coerce3dpoint(center_point, True)
394 |     xform = Rhino.Geometry.Transform.Rotation(start, end, center)
395 |     if not xform.IsValid: return scriptcontext.errorhandler()
396 |     return xform
397 | 
398 | 
399 | def XformRotation4(x0, y0, z0, x1, y1, z1):
400 |     """Returns a rotation transformation.
401 |     Parameters:
402 |       x0,y0,z0 (vector): Vectors defining the initial orthonormal frame
403 |       x1,y1,z1 (vector): Vectors defining the final orthonormal frame
404 |     Returns:
405 |       transform: The 4x4 transformation matrix.
406 |       None: on error.
407 |     Example:
408 |     See Also:
409 |     """
410 |     x0 = rhutil.coerce3dvector(x0, True)
411 |     y0 = rhutil.coerce3dvector(y0, True)
412 |     z0 = rhutil.coerce3dvector(z0, True)
413 |     x1 = rhutil.coerce3dvector(x1, True)
414 |     y1 = rhutil.coerce3dvector(y1, True)
415 |     z1 = rhutil.coerce3dvector(z1, True)
416 |     xform = Rhino.Geometry.Transform.Rotation(x0,y0,z0,x1,y1,z1)
417 |     if not xform.IsValid: return scriptcontext.errorhandler()
418 |     return xform
419 | 
420 | 
421 | def XformScale(scale, point=None):
422 |     """Creates a scale transformation
423 |     Parameters:
424 |       scale (number|point|vector|[number, number, number]): single number, list of 3 numbers, Point3d, or Vector3d
425 |       point (point, optional): center of scale. If omitted, world origin is used
426 |     Returns:
427 |       transform: The 4x4 transformation matrix on success
428 |       None: on error
429 |     Example:
430 |       import rhinoscriptsyntax as rs
431 |       objs = rs.GetObjects("Select objects to scale")
432 |       if objs:
433 |           xform = rs.XformScale( (3.0,1.0,1.0) )
434 |           rs.TransformObjects( objs, xform, True)
435 |     See Also:
436 |       XformMirror
437 |       XformPlanarProjection
438 |       XformRotation1
439 |       XformRotation2
440 |       XformRotation3
441 |       XformRotation4
442 |       XformShear
443 |       XformTranslation
444 |     """
445 |     factor = rhutil.coerce3dpoint(scale)
446 |     if factor is None:
447 |         if type(scale) is int or type(scale) is float:
448 |             factor = (scale,scale,scale)
449 |         if factor is None: return scriptcontext.errorhandler()
450 |     if point: point = rhutil.coerce3dpoint(point, True)
451 |     else: point = Rhino.Geometry.Point3d.Origin
452 |     plane = Rhino.Geometry.Plane(point, Rhino.Geometry.Vector3d.ZAxis);
453 |     xf = Rhino.Geometry.Transform.Scale(plane, factor[0], factor[1], factor[2])
454 |     return xf
455 | 
456 | 
457 | def XformScreenToWorld(point, view=None, screen_coordinates=False):
458 |     """Transforms a point from either client-area coordinates of the specified view
459 |     or screen coordinates to world coordinates. The resulting coordinates are represented
460 |     as a 3-D point
461 |     Parameters:
462 |       point (point): 2D point
463 |       view (str, optional): title or identifier of a view. If omitted, the active view is used
464 |       screen_coordinates (bool, optional): if False, point is in client-area coordinates. If True,
465 |       point is in screen-area coordinates
466 |     Returns:
467 |       point: on success
468 |       None: on error
469 |     Example:
470 |       import rhinoscriptsyntax as rs
471 |       point2d = 200,100
472 |       view = rs.CurrentView()
473 |       point = rs.XformScreenToWorld(point2d, view)
474 |       print(point)
475 |     See Also:
476 |       XformWorldToScreen
477 |     """
478 |     point = rhutil.coerce2dpoint(point, True)
479 |     view = __viewhelper(view)
480 |     viewport = view.MainViewport
481 |     xform = viewport.GetTransform(Rhino.DocObjects.CoordinateSystem.Screen, Rhino.DocObjects.CoordinateSystem.World)
482 |     point3d = Rhino.Geometry.Point3d(point.X, point.Y, 0)
483 |     if screen_coordinates:
484 |         screen = view.ScreenRectangle
485 |         point3d.X = point.X - screen.Left
486 |         point3d.Y = point.Y - screen.Top
487 |     point3d = xform * point3d
488 |     return point3d
489 | 
490 | 
491 | def XformShear(plane, x, y, z):
492 |     """Returns a shear transformation matrix
493 |     Parameters:
494 |       plane (plane): plane[0] is the fixed point
495 |       x,y,z (number): each axis scale factor
496 |     Returns:
497 |       transform: The 4x4 transformation matrix on success
498 |     Example:
499 |       import rhinoscriptsyntax as rs
500 |       objects = rs.GetObjects("Select objects to shear")
501 |       if objects:
502 |           cplane = rs.ViewCPlane()
503 |           xform = rs.XformShear(cplane, (1,1,0), (-1,1,0), (0,0,1))
504 |           rs.TransformObjects(objects, xform, True)
505 |     See Also:
506 |       XformMirror
507 |       XformPlanarProjection
508 |       XformRotation1
509 |       XformRotation2
510 |       XformRotation3
511 |       XformRotation4
512 |       XformScale
513 |       XformTranslation
514 |     """
515 |     plane = rhutil.coerceplane(plane, True)
516 |     x = rhutil.coerce3dvector(x, True)
517 |     y = rhutil.coerce3dvector(y, True)
518 |     z = rhutil.coerce3dvector(z, True)
519 |     return Rhino.Geometry.Transform.Shear(plane,x,y,z)
520 | 
521 | 
522 | def XformTranslation(vector):
523 |     """Creates a translation transformation matrix
524 |     Parameters:
525 |       vector (vector): List of 3 numbers, Point3d, or Vector3d.  A 3-D translation vector.
526 |     Returns:
527 |       transform: The 4x4 transformation matrix is successful, otherwise None
528 |     Example:
529 |       import rhinoscriptsyntax as rs
530 |       objs = rs.GetObjects("Select objects to copy")
531 |       if objs:
532 |           xform = rs.XformTranslation([1,0,0])
533 |           rs.TransformObjects( objs, xform, True )
534 |     See Also:
535 |       XformMirror
536 |       XformPlanarProjection
537 |       XformRotation1
538 |       XformRotation2
539 |       XformRotation3
540 |       XformRotation4
541 |       XformScale
542 |       XformShear
543 |     """
544 |     vector = rhutil.coerce3dvector(vector, True)
545 |     return Rhino.Geometry.Transform.Translation(vector)
546 | 
547 | 
548 | def XformWorldToCPlane(point, plane):
549 |     """Transforms a point from world coordinates to construction plane coordinates.
550 |     Parameters:
551 |       point (point): A 3D point in world coordinates.
552 |       plane (plane): The construction plane
553 |     Returns:
554 |       (point): 3D point in construction plane coordinates
555 |     Example:
556 |       import rhinoscriptsyntax as rs
557 |       plane = rs.ViewCPlane()
558 |       point = rs.XformWorldToCPlane([0,0,0], plane)
559 |       if point: print("CPlane point:{}".format(point))
560 |     See Also:
561 |       XformCPlaneToWorld
562 |     """
563 |     point = rhutil.coerce3dpoint(point, True)
564 |     plane = rhutil.coerceplane(plane, True)
565 |     v = point - plane.Origin;
566 |     return Rhino.Geometry.Point3d(v*plane.XAxis, v*plane.YAxis, v*plane.ZAxis)
567 | 
568 | 
569 | def XformWorldToScreen(point, view=None, screen_coordinates=False):
570 |     """Transforms a point from world coordinates to either client-area coordinates of
571 |     the specified view or screen coordinates. The resulting coordinates are represented
572 |     as a 2D point
573 |     Parameters:
574 |       point (point): 3D point in world coordinates
575 |       view (str, optional): title or identifier of a view. If omitted, the active view is used
576 |       screen_coordinates (bool, optional): if False, the function returns the results as
577 |         client-area coordinates. If True, the result is in screen-area coordinates
578 |     Returns:
579 |       (point): 2D point on success
580 |       None: on error
581 |     Example:
582 |       import rhinoscriptsyntax as rs
583 |       point = (0.0, 0.0, 0.0)
584 |       view = rs.CurrentView()
585 |       point2d = rs.XformWorldToScreen(point, view)
586 |       print(point2d)
587 |     See Also:
588 |       XformScreenToWorld
589 |     """
590 |     point = rhutil.coerce3dpoint(point, True)
591 |     view = __viewhelper(view)
592 |     viewport = view.MainViewport
593 |     xform = viewport.GetTransform(Rhino.DocObjects.CoordinateSystem.World, Rhino.DocObjects.CoordinateSystem.Screen)
594 |     point = xform * point
595 |     point = Rhino.Geometry.Point2d(point.X, point.Y)
596 |     if screen_coordinates:
597 |         screen = view.ScreenRectangle
598 |         point.X = point.X + screen.Left
599 |         point.Y = point.Y + screen.Top
600 |     return point
601 | 
602 | 
603 | def XformZero():
604 |     """Returns a zero transformation matrix
605 |     Returns:
606 |       transform: a zero transformation matrix
607 |     Example:
608 |       import rhinoscriptsyntax as rs
609 |       def printmatrix(xform):
610 |           for i in range(4):
611 |               print("[{}, {}, {}, {}]".format(xform[i,0], xform[i,1], xform[i,2], xform[i,3]))
612 |       printmatrix( rs.XformZero() )
613 |     See Also:
614 |       XformDiagonal
615 |       XformIdentity
616 |     """
617 |     return Rhino.Geometry.Transform()
618 | 
```

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

```python
  1 | import math
  2 | 
  3 | import Rhino.Geometry
  4 | 
  5 | import scriptcontext
  6 | 
  7 | import rhinocompat as compat
  8 | from rhinoscript import utility as rhutil
  9 | 
 10 | 
 11 | def __coercelight(id, raise_if_missing=False):
 12 |     light = rhutil.coercegeometry(id)
 13 |     if isinstance(light, Rhino.Geometry.Light): return light
 14 |     if raise_if_missing: raise ValueError("unable to retrieve light from %s"%id)
 15 | 
 16 | 
 17 | def AddDirectionalLight(start_point, end_point):
 18 |     """Adds a new directional light object to the document
 19 |     Parameters:
 20 |       start_point(point): starting point of the light
 21 |       end_point (point): ending point and direction of the light
 22 |     Returns:
 23 |       (guid): identifier of the new object if successful
 24 |     Example:
 25 |       import rhinoscriptsyntax as rs
 26 |       end = rs.GetPoint("End of light vector direction")
 27 |       if end:
 28 |           start = rs.GetPoint("Start of light vector direction", end)
 29 |           if start: rs.AddDirectionalLight( start, end )
 30 |     See Also:
 31 |       IsDirectionalLight
 32 |     """
 33 |     start = rhutil.coerce3dpoint(start_point, True)
 34 |     end = rhutil.coerce3dpoint(end_point, True)
 35 |     light = Rhino.Geometry.Light()
 36 |     light.LightStyle = Rhino.Geometry.LightStyle.WorldDirectional
 37 |     light.Location = start
 38 |     light.Direction = end-start
 39 |     index = scriptcontext.doc.Lights.Add(light)
 40 |     if index<0: raise Exception("unable to add light to LightTable")
 41 |     rc = scriptcontext.doc.Lights[index].Id
 42 |     scriptcontext.doc.Views.Redraw()
 43 |     return rc
 44 | 
 45 | 
 46 | def AddLinearLight(start_point, end_point, width=None):
 47 |     """Adds a new linear light object to the document
 48 |     Parameters:
 49 |       start_point (point): starting point of the light
 50 |       end_point (point): ending point and direction of the light
 51 |       width (number): width of the light
 52 |     Returns:
 53 |       guid: identifier of the new object if successful
 54 |       None: on error
 55 |     Example:
 56 |       import rhinoscriptsyntax as rs
 57 |       start = rs.GetPoint("Light origin")
 58 |       if start:
 59 |           end = rs.GetPoint("Light length and direction", start)
 60 |           if end: rs.AddLinearLight(start, end)
 61 |     See Also:
 62 |       IsLinearLight
 63 |     """
 64 |     start = rhutil.coerce3dpoint(start_point, True)
 65 |     end = rhutil.coerce3dpoint(end_point, True)
 66 |     if width is None:
 67 |         radius=0.5
 68 |         units = scriptcontext.doc.ModelUnitSystem
 69 |         if units!=compat.ENUM_NONE(Rhino.UnitSystem):
 70 |             scale = Rhino.RhinoMath.UnitScale(Rhino.UnitSystem.Inches, units)
 71 |             radius *= scale
 72 |         width = radius
 73 |     light = Rhino.Geometry.Light()
 74 |     light.LightStyle = Rhino.Geometry.LightStyle.WorldLinear
 75 |     light.Location = start
 76 |     v = end-start
 77 |     light.Direction = v
 78 |     light.Length = light.Direction
 79 |     light.Width = -light.Width
 80 |     plane = Rhino.Geometry.Plane(light.Location, light.Direction)
 81 |     xaxis = plane.XAxis
 82 |     xaxis.Unitize()
 83 |     plane.XAxis = xaxis
 84 |     light.Width = xaxis * min(width, v.Length/20)
 85 |     #light.Location = start - light.Direction
 86 |     index = scriptcontext.doc.Lights.Add(light)
 87 |     if index<0: raise Exception("unable to add light to LightTable")
 88 |     rc = scriptcontext.doc.Lights[index].Id
 89 |     scriptcontext.doc.Views.Redraw()
 90 |     return rc
 91 | 
 92 | 
 93 | def AddPointLight(point):
 94 |     """Adds a new point light object to the document
 95 |     Parameters:
 96 |       point (point): the 3d location of the point
 97 |     Returns:
 98 |       guid: identifier of the new object if successful
 99 |     Example:
100 |       import rhinoscriptsyntax as rs
101 |       point = rs.GetPoint("Point light location")
102 |       if point: rs.AddPointLight(point)
103 |     See Also:
104 |       IsPointLight
105 |     """
106 |     point = rhutil.coerce3dpoint(point, True)
107 |     light = Rhino.Geometry.Light()
108 |     light.LightStyle = Rhino.Geometry.LightStyle.WorldPoint
109 |     light.Location = point
110 |     index = scriptcontext.doc.Lights.Add(light)
111 |     if index<0: raise Exception("unable to add light to LightTable")
112 |     rc = scriptcontext.doc.Lights[index].Id
113 |     scriptcontext.doc.Views.Redraw()
114 |     return rc
115 | 
116 | 
117 | def AddRectangularLight(origin, width_point, height_point):
118 |     """Adds a new rectangular light object to the document
119 |     Parameters:
120 |       origin (point): 3d origin point of the light
121 |       width_point (point): 3d width and direction point of the light
122 |       height_point (point): 3d height and direction point of the light
123 |     Returns:
124 |       guid: identifier of the new object if successful
125 |     Example:
126 |       import rhinoscriptsyntax as rs
127 |       rect = rs.GetRectangle(2)
128 |       if rect: rs.AddRectangularLight( rect[0], rect[1], rect[3] )
129 |     See Also:
130 |       IsRectangularLight
131 |     """
132 |     origin = rhutil.coerce3dpoint(origin, True)
133 |     ptx = rhutil.coerce3dpoint(width_point, True)
134 |     pty = rhutil.coerce3dpoint(height_point, True)
135 |     length = pty-origin
136 |     width = ptx-origin
137 |     normal = Rhino.Geometry.Vector3d.CrossProduct(width, length)
138 |     normal.Unitize()
139 |     light = Rhino.Geometry.Light()
140 |     light.LightStyle = Rhino.Geometry.LightStyle.WorldRectangular
141 |     light.Location = origin
142 |     light.Width = width
143 |     light.Length = length
144 |     light.Direction = normal
145 |     index = scriptcontext.doc.Lights.Add(light)
146 |     if index<0: raise Exception("unable to add light to LightTable")
147 |     rc = scriptcontext.doc.Lights[index].Id
148 |     scriptcontext.doc.Views.Redraw()
149 |     return rc
150 | 
151 | 
152 | def AddSpotLight(origin, radius, apex_point):
153 |     """Adds a new spot light object to the document
154 |     Parameters:
155 |       origin (point): 3d origin point of the light
156 |       radius (number):  radius of the cone
157 |       apex_point (point): 3d apex point of the light
158 |     Returns:
159 |       guid: identifier of the new object
160 |     Example:
161 |       import rhinoscriptsyntax as rs
162 |       radius = 5.0
163 |       origin = rs.GetPoint("Base of cone")
164 |       if origin:
165 |           apex = rs.GetPoint("End of cone", origin)
166 |           if apex: rs.AddSpotLight(origin, radius, apex)
167 |     See Also:
168 |       IsSpotLight
169 |       SpotLightHardness
170 |       SpotLightShadowIntensity
171 |     """
172 |     origin = rhutil.coerce3dpoint(origin, True)
173 |     apex_point = rhutil.coerce3dpoint(apex_point, True)
174 |     if radius<0: radius=1.0
175 |     light = Rhino.Geometry.Light()
176 |     light.LightStyle = Rhino.Geometry.LightStyle.WorldSpot
177 |     light.Location = apex_point
178 |     light.Direction = origin-apex_point
179 |     light.SpotAngleRadians = math.atan(radius / (light.Direction.Length))
180 |     light.HotSpot = 0.50
181 |     index = scriptcontext.doc.Lights.Add(light)
182 |     if index<0: raise Exception("unable to add light to LightTable")
183 |     rc = scriptcontext.doc.Lights[index].Id
184 |     scriptcontext.doc.Views.Redraw()
185 |     return rc
186 | 
187 | 
188 | def EnableLight(object_id, enable=None):
189 |     """Enables or disables a light object
190 |     Parameters:
191 |       object_id (guid): the light object's identifier
192 |       enable (bool, optional): the light's enabled status
193 |     Returns:
194 |       bool: if enable is not specified, the current enabled status
195 |       bool: if enable is specified, the previous enabled status
196 |       None: on error
197 |     Example:
198 |       import rhinoscriptsyntax as rs
199 |       id = rs.GetObject("Select light", rs.filter.light)
200 |       if id: rs.EnableLight( id, False )
201 |     See Also:
202 |       IsLight
203 |       IsLightEnabled
204 |       LightColor
205 |       LightCount
206 |       LightName
207 |       LightObjects
208 |     """
209 |     light = __coercelight(object_id, True)
210 |     rc = light.IsEnabled
211 |     if enable is not None and enable!=rc:
212 |         light.IsEnabled = enable
213 |         id = rhutil.coerceguid(object_id)
214 |         if not scriptcontext.doc.Lights.Modify(id, light):
215 |             return scriptcontext.errorhandler()
216 |         scriptcontext.doc.Views.Redraw()
217 |     return rc
218 | 
219 | 
220 | def IsDirectionalLight(object_id):
221 |     """Verifies a light object is a directional light
222 |     Parameters:
223 |       object_id (guid): the light object's identifier
224 |     Returns:
225 |       bool: True or False
226 |     Example:
227 |       import rhinoscriptsyntax as rs
228 |       id = rs.GetObject("Select a light", rs.filter.light)
229 |       if rs.IsDirectionalLight(id):
230 |           print("The object is a directional light.")
231 |       else:
232 |           print("The object is not a directional light.")
233 |     See Also:
234 |       AddDirectionalLight
235 |     """
236 |     light = __coercelight(object_id, True)
237 |     return light.IsDirectionalLight
238 | 
239 | 
240 | def IsLight(object_id):
241 |     """Verifies an object is a light object
242 |     Parameters:
243 |       object_id (guid): the light object's identifier
244 |     Returns:
245 |       bool: True or False
246 |     Example:
247 |       import rhinoscriptsyntax as rs
248 |       id = rs.GetObject("Select a light")
249 |       if rs.IsLight(id):
250 |           print("The object is a light.")
251 |       else:
252 |           print("The object is not a light.")
253 |     See Also:
254 |       EnableLight
255 |       IsLightEnabled
256 |       LightColor
257 |       LightCount
258 |       LightName
259 |       LightObjects
260 |     """
261 |     light = __coercelight(object_id, False)
262 |     return light is not None
263 | 
264 | 
265 | def IsLightEnabled(object_id):
266 |     """Verifies a light object is enabled
267 |     Parameters:
268 |       object_id (guid): the light object's identifier
269 |     Returns:
270 |       bool: True or False
271 |     Example:
272 |       import rhinoscriptsyntax as rs
273 |       id = rs.GetObject("Select a light", rs.filter.light)
274 |       if rs.IsLightEnabled(id):
275 |           print("The light is enabled (on).")
276 |       else:
277 |           print("The light is disabled (off).")
278 |     See Also:
279 |       EnableLight
280 |       IsLight
281 |       LightColor
282 |       LightCount
283 |       LightName
284 |       LightObjects
285 |     """
286 |     light = __coercelight(object_id, True)
287 |     return light.IsEnabled
288 | 
289 | 
290 | def IsLightReference(object_id):
291 |     """Verifies a light object is referenced from another file
292 |     Parameters:
293 |       object_id (guid): the light object's identifier
294 |     Returns:
295 |       bool: True or False
296 |     Example:
297 |       import rhinoscriptsyntax as rs
298 |       id = rs.GetObject("Select a light", rs.filter.light)
299 |       if rs.IsLightReference(id):
300 |           print("The light is a reference object.")
301 |       else:
302 |           print("The light is not a reference object.")
303 |     See Also:
304 |       IsObjectReference
305 |     """
306 |     light = __coercelight(object_id, True)
307 |     return light.IsReference
308 | 
309 | 
310 | def IsLinearLight(object_id):
311 |     """Verifies a light object is a linear light
312 |     Parameters:
313 |       object_id (guid): the light object's identifier
314 |     Returns:
315 |       bool: True or False
316 |     Example:
317 |       import rhinoscriptsyntax as rs
318 |       id = rs.GetObject("Select a light", rs.filter.light)
319 |       if rs.IsLinearLight(id):
320 |           print("The object is a linear light.")
321 |       else:
322 |           print("The object is not a linear light.")
323 |     See Also:
324 |       AddLinearLight
325 |     """
326 |     light = __coercelight(object_id, True)
327 |     return light.IsLinearLight
328 | 
329 | 
330 | def IsPointLight(object_id):
331 |     """Verifies a light object is a point light
332 |     Parameters:
333 |       object_id (guid): the light object's identifier
334 |     Returns:
335 |       bool: True or False
336 |     Example:
337 |       import rhinoscriptsyntax as rs
338 |       id = rs.GetObject("Select a light", rs.filter.light)
339 |       if rs.IsPointLight(id):
340 |           print("The object is a point light.")
341 |       else:
342 |           print("The object is not a point light.")
343 |     See Also:
344 |       AddPointLight
345 |     """
346 |     light = __coercelight(object_id, True)
347 |     return light.IsPointLight
348 | 
349 | 
350 | def IsRectangularLight(object_id):
351 |     """Verifies a light object is a rectangular light
352 |     Parameters:
353 |       object_id (guid): the light object's identifier
354 |     Returns:
355 |       bool: True or False
356 |     Example:
357 |       import rhinoscriptsyntax as rs
358 |       id = rs.GetObject("Select a light", rs.filter.light)
359 |       if rs.IsRectangularLight(id):
360 |           print("The object is a rectangular light.")
361 |       else:
362 |           print("The object is not a rectangular light.")
363 |     See Also:
364 |       AddRectangularLight
365 |     """
366 |     light = __coercelight(object_id, True)
367 |     return light.IsRectangularLight
368 | 
369 | 
370 | def IsSpotLight(object_id):
371 |     """Verifies a light object is a spot light
372 |     Parameters:
373 |       object_id (guid): the light object's identifier
374 |     Returns:
375 |       bool: True or False
376 |     Example:
377 |       import rhinoscriptsyntax as rs
378 |       id = rs.GetObject("Select a light", rs.filter.light)
379 |       if rs.IsSpotLight(id):
380 |           print("The object is a spot light.")
381 |       else:
382 |           print("The object is not a spot light.")
383 |     See Also:
384 |       AddSpotLight
385 |       SpotLightHardness
386 |       SpotLightShadowIntensity
387 |     """
388 |     light = __coercelight(object_id, True)
389 |     return light.IsSpotLight
390 | 
391 | 
392 | def LightColor(object_id, color=None):
393 |     """Returns or changes the color of a light
394 |     Parameters:
395 |       object_id (guid): the light object's identifier
396 |       color (color, optional): the light's new color
397 |     Returns:
398 |       color: if color is not specified, the current color
399 |       color: if color is specified, the previous color
400 |     Example:
401 |       import rhinoscriptsyntax as rs
402 |       id = rs.GetObject("Select a light", rs.filter.light)
403 |       if id: rs.LightColor( id, (0,255,255) )
404 |     See Also:
405 |       EnableLight
406 |       IsLight
407 |       IsLightEnabled
408 |       LightCount
409 |       LightName
410 |       LightObjects
411 |     """
412 |     light = __coercelight(object_id, True)
413 |     rc = light.Diffuse
414 |     if color:
415 |         color = rhutil.coercecolor(color, True)
416 |         if color!=rc:
417 |             light.Diffuse = color
418 |             id = rhutil.coerceguid(object_id, True)
419 |             if not scriptcontext.doc.Lights.Modify(id, light):
420 |                 return scriptcontext.errorhandler()
421 |             scriptcontext.doc.Views.Redraw()
422 |     return rc
423 | 
424 | 
425 | def LightCount():
426 |     """Returns the number of light objects in the document
427 |     Returns:
428 |       number: the number of light objects in the document
429 |     Example:
430 |       import rhinoscriptsyntax as rs
431 |       print("There are {} lights".format(rs.LightCount()))
432 |     See Also:
433 |       EnableLight
434 |       IsLight
435 |       IsLightEnabled
436 |       LightColor
437 |       LightName
438 |       LightObjects
439 |     """
440 |     return scriptcontext.doc.Lights.Count
441 | 
442 | 
443 | def LightDirection(object_id, direction=None):
444 |     """Returns or changes the direction of a light object
445 |     Parameters:
446 |       object_id (guid): the light object's identifier
447 |       direction (vector, optional): the light's new direction
448 |     Returns:
449 |       vector: if direction is not specified, the current direction
450 |       vector: if direction is specified, the previous direction
451 |     Example:
452 |       import rhinoscriptsyntax as rs
453 |       id = rs.GetObject("Select a light", rs.filter.light)
454 |       if id: print( rs.LightDirection(id) )
455 |     See Also:
456 |       IsLight
457 |       LightLocation
458 |     """
459 |     light = __coercelight(object_id, True)
460 |     rc = light.Direction
461 |     if direction:
462 |         direction = rhutil.coerce3dvector(direction, True)
463 |         if direction!=rc:
464 |             light.Direction = direction
465 |             id = rhutil.coerceguid(object_id, True)
466 |             if not scriptcontext.doc.Lights.Modify(id, light):
467 |                 return scriptcontext.errorhandler()
468 |             scriptcontext.doc.Views.Redraw()
469 |     return rc
470 | 
471 | 
472 | def LightLocation(object_id, location=None):
473 |     """Returns or changes the location of a light object
474 |     Parameters:
475 |       object_id (guid): the light object's identifier
476 |       location (point, optional): the light's new location
477 |     Returns:
478 |       point: if location is not specified, the current location
479 |       point: if location is specified, the previous location
480 |     Example:
481 |       import rhinoscriptsyntax as rs
482 |       id = rs.GetObject("Select a light", rs.filter.light)
483 |       if id: rs.AddPoint( rs.LightLocation(id) )
484 |     See Also:
485 |       IsLight
486 |       LightDirection
487 |     """
488 |     light = __coercelight(object_id, True)
489 |     rc = light.Location
490 |     if location:
491 |         location = rhutil.coerce3dpoint(location, True)
492 |         if location!=rc:
493 |             light.Location = location
494 |             id = rhutil.coerceguid(object_id, True)
495 |             if not scriptcontext.doc.Lights.Modify(id, light):
496 |                 return scriptcontext.errorhandler()
497 |             scriptcontext.doc.Views.Redraw()
498 |     return rc
499 | 
500 | 
501 | def LightName(object_id, name=None):
502 |     """Returns or changes the name of a light object
503 |     Parameters:
504 |       object_id (guid): the light object's identifier
505 |       name (str, optional): the light's new name
506 |     Returns:
507 |       str: if name is not specified, the current name
508 |       str: if name is specified, the previous name
509 |     Example:
510 |       import rhinoscriptsyntax as rs
511 |       id = rs.GetObject("Select a light", rs.filter.light)
512 |       if id:
513 |           name = rs.GetString("New light name")
514 |           if name: rs.LightName(id, name)
515 |     See Also:
516 |       EnableLight
517 |       IsLight
518 |       IsLightEnabled
519 |       LightColor
520 |       LightCount
521 |       LightObjects
522 |     """
523 |     light = __coercelight(object_id, True)
524 |     rc = light.Name
525 |     if name and name!=rc:
526 |         light.Name = name
527 |         id = rhutil.coerceguid(object_id, True)
528 |         if not scriptcontext.doc.Lights.Modify(id, light):
529 |             return scriptcontext.errorhandler()
530 |         scriptcontext.doc.Views.Redraw()
531 |     return rc
532 | 
533 | 
534 | def LightObjects():
535 |     """Returns list of identifiers of light objects in the document
536 |     Returns:
537 |       list(guid, ...): the list of identifiers of light objects in the document
538 |     Example:
539 |       import rhinoscriptsyntax as rs
540 |       lights = rs.LightObjects()
541 |       if lights:
542 |           rs.AddLayer( "Lights" )
543 |           for light in lights: rs.ObjectLayer( light, "Lights" )
544 |     See Also:
545 |       EnableLight
546 |       IsLight
547 |       IsLightEnabled
548 |       LightColor
549 |       LightCount
550 |       LightName
551 |     """
552 |     count = scriptcontext.doc.Lights.Count
553 |     rc = []
554 |     for i in range(count):
555 |         rhlight = scriptcontext.doc.Lights[i]
556 |         if not rhlight.IsDeleted: rc.append(rhlight.Id)
557 |     return rc
558 | 
559 | 
560 | def RectangularLightPlane(object_id):
561 |     """Returns the plane of a rectangular light object
562 |     Parameters:
563 |       object_id (guid): the light object's identifier
564 |     Returns:
565 |       plane: the plane if successful
566 |       None: on error
567 |     Example:
568 |       import rhinoscriptsyntax as rs
569 |       id = rs.GetObject("Select a rectangular light", rs.filter.light)
570 |       if id:
571 |           rc = rs.RectangularLightPlane(id)
572 |           if rc:
573 |               plane, extents = rc
574 |               rs.AddPlaneSurface( plane, extents[0], extents[1] )
575 |     See Also:
576 |       IsRectangularLight
577 |     """
578 |     light = __coercelight(object_id, True)
579 |     if light.LightStyle!=Rhino.Geometry.LightStyle.WorldRectangular:
580 |         return scriptcontext.errorhandler()
581 |     location = light.Location
582 |     length = light.Length
583 |     width = light.Width
584 |     direction = light.Direction
585 |     plane = Rhino.Geometry.Plane(location, length, width)
586 |     return plane, (length.Length, width.Length)
587 | 
588 | 
589 | def SpotLightHardness(object_id, hardness=None):
590 |     """Returns or changes the hardness of a spot light. Spotlight hardness
591 |     controls the fully illuminated region.
592 |     Parameters:
593 |       object_id (guid): the light object's identifier
594 |       hardness (number, optional): the light's new hardness
595 |     Returns:
596 |       number: if hardness is not specified, the current hardness
597 |       number: if hardness is specified, the previous hardness
598 |     Example:
599 |       import rhinoscriptsyntax as rs
600 |       id = rs.GetObject("Select a light", rs.filter.light)
601 |       if id: rs.SpotLightHardness(id, 0.75)
602 |     See Also:
603 |       AddSpotLight
604 |       IsSpotLight
605 |       SpotLightRadius
606 |       SpotLightShadowIntensity
607 |     """
608 |     light = __coercelight(object_id, True)
609 |     if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
610 |         return scriptcontext.errorhandler()
611 |     rc = light.HotSpot
612 |     if hardness and hardness!=rc:
613 |         light.HotSpot = hardness
614 |         id = rhutil.coerceguid(object_id, True)
615 |         if not scriptcontext.doc.Lights.Modify(id, light):
616 |             return scriptcontext.errorhandler()
617 |         scriptcontext.doc.Views.Redraw()
618 |     return rc
619 | 
620 | 
621 | def SpotLightRadius(object_id, radius=None):
622 |     """Returns or changes the radius of a spot light.
623 |     Parameters:
624 |       object_id (guid): the light object's identifier
625 |       radius (number, optional): the light's new radius
626 |     Returns:
627 |       number: if radius is not specified, the current radius
628 |       number: if radius is specified, the previous radius
629 |     Example:
630 |       import rhinoscriptsyntax as rs
631 |       id = rs.GetObject("Select a light", rs.filter.light)
632 |       if id: rs.SpotLightRadius(id, 5.0)
633 |     See Also:
634 |       AddSpotLight
635 |       IsSpotLight
636 |       SpotLightHardness
637 |       SpotLightShadowIntensity
638 |     """
639 |     light = __coercelight(object_id, True)
640 |     if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
641 |         return scriptcontext.errorhandler()
642 |     radians = light.SpotAngleRadians
643 |     rc = light.Direction.Length * math.tan(radians)
644 |     if radius and radius!=rc:
645 |         radians = math.atan(radius/light.Direction.Length)
646 |         light.SpotAngleRadians = radians
647 |         id = rhutil.coerceguid(object_id, True)
648 |         if not scriptcontext.doc.Lights.Modify(id, light):
649 |             return scriptcontext.errorhandler()
650 |         scriptcontext.doc.Views.Redraw()
651 |     return rc
652 | 
653 | 
654 | def SpotLightShadowIntensity(object_id, intensity=None):
655 |     """Returns or changes the shadow intensity of a spot light.
656 |     Parameters:
657 |       object_id (guid): the light object's identifier
658 |       intensity (number, optional): the light's new intensity
659 |     Returns:
660 |       number: if intensity is not specified, the current intensity
661 |       number: if intensity is specified, the previous intensity
662 |     Example:
663 |       import rhinoscriptsyntax as rs
664 |       id = rs.GetObject("Select a light", rs.filter.light)
665 |       if id: rs.SpotLightShadowIntensity(id, 0.75)
666 |     See Also:
667 |       AddSpotLight
668 |       IsSpotLight
669 |       SpotLightHardness
670 |       SpotLightRadius
671 |     """
672 |     light = __coercelight(object_id, True)
673 |     if light.LightStyle!=Rhino.Geometry.LightStyle.WorldSpot:
674 |         return scriptcontext.errorhandler()
675 |     rc = light.SpotLightShadowIntensity
676 |     if intensity and intensity!=rc:
677 |         light.SpotLightShadowIntensity = intensity
678 |         id = rhutil.coerceguid(object_id, True)
679 |         if not scriptcontext.doc.Lights.Modify(id, light):
680 |             return scriptcontext.errorhandler()
681 |         scriptcontext.doc.Views.Redraw()
682 |     return rc
683 | 
```

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

```python
  1 | import math
  2 | 
  3 | import System
  4 | 
  5 | import Rhino
  6 | 
  7 | import scriptcontext
  8 | 
  9 | from rhinoscript import utility as rhutil
 10 | 
 11 | 
 12 | def __InstanceObjectFromId(id, raise_if_missing):
 13 |     rhobj = rhutil.coercerhinoobject(id, True, raise_if_missing)
 14 |     if isinstance(rhobj, Rhino.DocObjects.InstanceObject): return rhobj
 15 |     if raise_if_missing: raise ValueError("unable to find InstanceObject")
 16 | 
 17 | 
 18 | def AddBlock(object_ids, base_point, name=None, delete_input=False):
 19 |     """Adds a new block definition to the document
 20 |     Parameters:
 21 |       object_ids ([guid, ....]) objects that will be included in the block
 22 |       base_point (point): 3D base point for the block definition
 23 |       name (str, optional): name of the block definition. If omitted a name will be
 24 |         automatically generated
 25 |       delete_input (bool): if True, the object_ids will be deleted
 26 |     Returns:
 27 |       str: name of new block definition on success
 28 |     Example:
 29 |       import rhinoscriptsyntax as rs
 30 |       objs = rs.GetObjects("Select objects to define block")
 31 |       if objs:
 32 |           point = rs.GetPoint("Block base point")
 33 |           if point:
 34 |               block = rs.AddBlock(objs, point, None, True)
 35 |               rs.InsertBlock(block, point)
 36 |     See Also:
 37 |       InsertBlock
 38 |     """
 39 |     base_point = rhutil.coerce3dpoint(base_point, True)
 40 |     if not name:
 41 |         name = scriptcontext.doc.InstanceDefinitions.GetUnusedInstanceDefinitionName()
 42 |     found = scriptcontext.doc.InstanceDefinitions.Find(name)
 43 |     objects = []
 44 |     for id in object_ids:
 45 |         obj = rhutil.coercerhinoobject(id, True)
 46 |         if obj.IsReference: return
 47 |         ot = obj.ObjectType
 48 |         if ot==Rhino.DocObjects.ObjectType.Light: return
 49 |         if ot==Rhino.DocObjects.ObjectType.Grip: return
 50 |         if ot==Rhino.DocObjects.ObjectType.Phantom: return
 51 |         if ot==Rhino.DocObjects.ObjectType.InstanceReference and found:
 52 |             uses, nesting = obj.UsesDefinition(found.Index)
 53 |             if uses: return
 54 |         objects.append(obj)
 55 |     if objects:
 56 |         geometry = [obj.Geometry for obj in objects]
 57 |         attrs = [obj.Attributes for obj in objects]
 58 |         rc = 0
 59 |         if found:
 60 |           rc = scriptcontext.doc.InstanceDefinitions.ModifyGeometry(found.Index, geometry, attrs)
 61 |         else:
 62 |           rc = scriptcontext.doc.InstanceDefinitions.Add(name, "", base_point, geometry, attrs)
 63 |         if rc>=0:
 64 |             if delete_input:
 65 |                 for obj in objects: scriptcontext.doc.Objects.Delete(obj, True)
 66 |             scriptcontext.doc.Views.Redraw()
 67 |     return name
 68 | 
 69 | 
 70 | def BlockContainerCount(block_name):
 71 |     """Returns number of block definitions that contain a specified
 72 |     block definition
 73 |     Parameters:
 74 |       block_name (str): the name of an existing block definition
 75 |     Returns:
 76 |       number: the number of block definitions that contain a specified block definition
 77 |     Example:
 78 |       import rhinoscriptscriptsyntax as rs
 79 |       block = rs.GetString("Block name to query")
 80 |       if rs.IsBlock(block):
 81 |           count = rs.BlockContainerCount(block)
 82 |           print("This block is nested in {} block(s).".format(count))
 83 |     See Also:
 84 |       BlockContainers
 85 |       IsBlock
 86 |     """
 87 |     return len(BlockContainers(block_name))
 88 | 
 89 | 
 90 | def BlockContainers(block_name):
 91 |     """Returns names of the block definitions that contain a specified block
 92 |     definition.
 93 |     Parameters:
 94 |       block_name (str): the name of an existing block definition
 95 |     Returns:
 96 |       list(str, ...): A list of block definition names
 97 |     Example:
 98 |       import rhinoscriptsyntax as rs
 99 |       blockname = rs.GetString("Block name to query")
100 |       if rs.IsBlock(blockname):
101 |           blocks = rs.BlockContainers(blockname)
102 |           for block in blocks: print(block)
103 |     See Also:
104 |       BlockContainerCount
105 |       IsBlock
106 |     """
107 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
108 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
109 |     containers = idef.GetContainers()
110 |     rc = []
111 |     for item in containers:
112 |         if not item.IsDeleted: rc.append(item.Name)
113 |     return rc
114 | 
115 | 
116 | def BlockCount():
117 |     """Returns the number of block definitions in the document
118 |     Returns:
119 |       number: the number of block definitions in the document
120 |     Example:
121 |       import rhinoscriptsyntax as rs
122 |       count = rs.BlockCount()
123 |       print("There are {} blocks".format(count)
124 |     See Also:
125 |       BlockNames
126 |       IsBlock
127 |     """
128 |     return scriptcontext.doc.InstanceDefinitions.ActiveCount
129 | 
130 | 
131 | def BlockDescription(block_name, description=None):
132 |     """Returns or sets the description of a block definition
133 |     Parameters:
134 |       block_name (str): the name of an existing block definition
135 |       description (str, optional): The new description.
136 |     Returns:
137 |       str: if description is not specified, the current description
138 |       str: if description is specified, the previous description
139 |     Example:
140 |       import rhinoscriptsyntax as rs
141 |       blockname = rs.GetString("Block name to list description")
142 |       if rs.IsBlock(blockname):
143 |           desc = rs.BlockDescription(blockname)
144 |           if desc is None: print("No description")
145 |           else: print(desc)
146 |     See Also:
147 |       IsBlock
148 |     """
149 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
150 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
151 |     rc = idef.Description
152 |     if description: scriptcontext.doc.InstanceDefinitions.Modify( idef, idef.Name, description, True )
153 |     return rc
154 | 
155 | 
156 | def BlockInstanceCount(block_name,where_to_look=0):
157 |     """Counts number of instances of the block in the document.
158 |     Nested instances are not included in the count.
159 |     Parameters:
160 |       block_name (str): the name of an existing block definition
161 |       where_to_look (number, optional):
162 |         0 = get top level references in active document.
163 |         1 = get top level and nested references in active document.
164 |         2 = check for references from other instance definitions
165 |     Returns:
166 |       number: the number of instances of the block in the document
167 |     Example:
168 |       import rhinoscriptsyntax as rs
169 |       blockname = rs.GetString("Block to count")
170 |       if rs.IsBlock(blockname):
171 |           count = rs.BlockInstanceCount(blockname)
172 |           print("{} block(s) found.".format(count))
173 |     See Also:
174 |       BlockInstanceInsertPoint
175 |       BlockInstances
176 |       BlockInstanceXform
177 |       IsBlockInstance
178 |     """
179 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
180 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
181 |     refs = idef.GetReferences(where_to_look)
182 |     return len(refs)
183 | 
184 | 
185 | def BlockInstanceInsertPoint(object_id):
186 |     """Returns the insertion point of a block instance.
187 |     Parameters:
188 |       object_id (guid): The identifier of an existing block insertion object
189 |     Returns:
190 |       point: The insertion 3D point if successful
191 |     Example:
192 |       import rhinoscriptsyntax as rs
193 |       strObject = rs.GetObject("Select block")
194 |       if rs.IsBlockInstance(strObject):
195 |           rs.AddPoint( rs.BlockInstanceInsertPoint(strObject) )
196 |     See Also:
197 |       BlockInstanceCount
198 |       BlockInstances
199 |       BlockInstanceXform
200 |       IsBlockInstance
201 |     """
202 |     instance = __InstanceObjectFromId(object_id, True)
203 |     xf = instance.InstanceXform
204 |     pt = Rhino.Geometry.Point3d.Origin
205 |     pt.Transform(xf)
206 |     return pt
207 | 
208 | 
209 | def BlockInstanceName(object_id):
210 |     """Returns the block name of a block instance
211 |     Parameters:
212 |       object_id (guid): The identifier of an existing block insertion object
213 |     Returns:
214 |       str: the block name of a block instance
215 |     Example:
216 |       import rhinoscriptsyntax as rs
217 |       strObject = rs.GetObject("Select block")
218 |       if rs.IsBlockInstance(strObject):
219 |           print(rs.BlockInstanceName(strObject))
220 |     See Also:
221 |       BlockInstanceCount
222 |       BlockInstances
223 |       BlockInstanceXform
224 |       IsBlockInstance
225 |     """
226 |     instance = __InstanceObjectFromId(object_id, True)
227 |     idef = instance.InstanceDefinition
228 |     return idef.Name
229 | 
230 | 
231 | def BlockInstances(block_name,where_to_look=0):
232 |     """Returns the identifiers of the inserted instances of a block.
233 |     Parameters:
234 |       block_name (str): the name of an existing block definition
235 |       where_to_look (number, optional):
236 |         0 = get top level references in active document.
237 |         1 = get top level and nested references in active document.
238 |         2 = check for references from other instance definitions
239 |     Returns:
240 |       list(guid, ...): Ids identifying the instances of a block in the model.
241 |     Example:
242 |       import rhinoscriptsyntax as rs
243 |       strBlock = rs.GetString("Block to select")
244 |       if rs.IsBlock(strBlock):
245 |           arrObjects = rs.BlockInstances(strBlock)
246 |           if arrobjects:
247 |               rs.SelectObjects(arrObjects)
248 |     See Also:
249 |       BlockInstanceCount
250 |       BlockInstanceInsertPoint
251 |       BlockInstanceXform
252 |       IsBlockInstance
253 |     """
254 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
255 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
256 |     instances = idef.GetReferences(where_to_look)
257 |     return [item.Id for item in instances]
258 | 
259 | 
260 | def BlockInstanceXform(object_id):
261 |     """Returns the location of a block instance relative to the world coordinate
262 |     system origin (0,0,0). The position is returned as a 4x4 transformation
263 |     matrix
264 |     Parameters:
265 |       object_id (guid): The identifier of an existing block insertion object
266 |     Returns:
267 |       transform: the location, as a transform matrix, of a block instance relative to the world coordinate
268 |     system origin
269 |     Example:
270 |       import rhinoscriptsyntax as rs
271 |       obj = rs.GetObject("Select block to query")
272 |       if rs.IsBlockInstance(obj):
273 |           arrMatrix = rs.BlockInstanceXform(obj)
274 |           if arrMatrix is not None:
275 |               pointId = rs.AddPoint([0,0,0])
276 |               rs.TransformObject( pointId, arrMatrix)
277 |     See Also:
278 |       BlockInstanceCount
279 |       BlockInstanceInsertPoint
280 |       BlockInstances
281 |       IsBlockInstance
282 |     """
283 |     instance = __InstanceObjectFromId(object_id, True)
284 |     return instance.InstanceXform
285 | 
286 | 
287 | def BlockNames( sort=False ):
288 |     """Returns the names of all block definitions in the document
289 |     Parameters:
290 |       sort (bool): True to return a sorted list
291 |     Returns:
292 |       list(str, ...): the names of all block definitions in the document
293 |     Example:
294 |       import rhinoscriptsyntax as rs
295 |       names = rs.BlockNames(True)
296 |       if names:
297 |           for name in names: print(name)
298 |     See Also:
299 |       BlockCount
300 |       IsBlock
301 |     """
302 |     ideflist = scriptcontext.doc.InstanceDefinitions.GetList(True)
303 |     rc = [item.Name for item in ideflist]
304 |     if(sort): rc.sort()
305 |     return rc
306 | 
307 | 
308 | def BlockObjectCount(block_name):
309 |     """Returns number of objects that make up a block definition
310 |     Parameters:
311 |       block_name (str): name of an existing block definition
312 |     Returns:
313 |       number: the number of objects that make up a block definition
314 |     Example:
315 |       import rhinoscriptsyntax as rs
316 |       count = rs.BlockObjectCount()
317 |       print("There are {} blocks".format(count))
318 |     See Also:
319 |       BlockNames
320 |       BlockObjects
321 |       IsBlock
322 |     """
323 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
324 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
325 |     return idef.ObjectCount
326 | 
327 | 
328 | def BlockObjects(block_name):
329 |     """Returns identifiers of the objects that make up a block definition
330 |     Parameters:
331 |       block_name (str): name of an existing block definition
332 |     Returns:
333 |       list(guid, ...): list of identifiers on success
334 |     Example:
335 |       import rhinoscriptsyntax as rs
336 |       strBlock = rs.GetString("Block name to list identifiers")
337 |       if rs.IsBlock(strBlock):
338 |           objects = rs.BlockObjects(strBlock)
339 |           if objects:
340 |               for item in objects: print(item)
341 |     See Also:
342 |       BlockNames
343 |       BlockObjectCount
344 |       IsBlock
345 |     """
346 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
347 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
348 |     rhobjs = idef.GetObjects()
349 |     return [obj.Id for obj in rhobjs]
350 | 
351 | 
352 | def BlockPath(block_name):
353 |     """Returns path to the source of a linked or embedded block definition.
354 |     A linked or embedded block definition is a block definition that was
355 |     inserted from an external file.
356 |     Parameters:
357 |       block_name (str): name of an existing block definition
358 |     Returns:
359 |       str: path to the linked block on success
360 |     Example:
361 |       import rhinoscriptsyntax as rs
362 |       strBlock = rs.GetString("Block name to list path")
363 |       if rs.IsBlockEmbedded(strBlock):
364 |           print(rs.BlockPath(strBlock))
365 |     See Also:
366 |       IsBlock
367 |       IsBlockEmbedded
368 |     """
369 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
370 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
371 |     return idef.SourceArchive
372 | 
373 | 
374 | def BlockStatus(block_name):
375 |     """Returns the status of a linked block
376 |     Parameters:
377 |         block_name (str): Name of an existing block
378 |     Returns:
379 |       number: the status of a linked block
380 |         Value Description
381 |         -3    Not a linked block definition.
382 |         -2    The linked block definition's file could not be opened or could not be read.
383 |         -1    The linked block definition's file could not be found.
384 |          0    The linked block definition is up-to-date.
385 |          1    The linked block definition's file is newer than definition.
386 |          2    The linked block definition's file is older than definition.
387 |          3    The linked block definition's file is different than definition.
388 |     Example:
389 |       import rhinoscriptsyntax as rs
390 |       block = rs.GetString("Block name to list description")
391 |       if rs.IsBlock(block):
392 |           status = rs.BlockStatus(block)
393 |           print("block status for {} is {}".format(block, status))
394 |     See Also:
395 |       IsBlock
396 |     """
397 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
398 |     if not idef: return -3
399 |     return int(idef.ArchiveFileStatus)
400 | 
401 | 
402 | def DeleteBlock(block_name):
403 |     """Deletes a block definition and all of it's inserted instances.
404 |     Parameters:
405 |       block_name (str): name of an existing block definition
406 |     Returns:
407 |       bool: True or False indicating success or failure
408 |     Example:
409 |       import rhinoscriptsyntax as rs
410 |       strBlock = rs.GetString("Block name to delete")
411 |       if rs.IsBlock(strBlock):
412 |           rs.DeleteBlock(strBlock)
413 |     See Also:
414 |       BlockNames
415 |       ExplodeBlockInstance
416 |       IsBlock
417 |     """
418 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
419 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
420 |     rc = scriptcontext.doc.InstanceDefinitions.Delete(idef.Index, True, False)
421 |     scriptcontext.doc.Views.Redraw()
422 |     return rc
423 | 
424 | 
425 | def ExplodeBlockInstance(object_id, explode_nested_instances=False):
426 |     """Explodes a block instance into it's geometric components. The
427 |     exploded objects are added to the document
428 |     Parameters:
429 |       object_id (guid): The identifier of an existing block insertion object
430 |       explode_nested_instances (bool, optional): By default nested blocks are not exploded.
431 |     Returns:
432 |       list(guid, ...): identifiers for the newly exploded objects on success
433 |     Example:
434 |       import rhinoscriptsyntax as rs
435 |       strObject = rs.GetObject("Select block instance to explode")
436 |       if rs.IsBlockInstance(strObject):
437 |           rs.ExplodeBlockInstance(strObject)
438 |     See Also:
439 |       DeleteBlock
440 |       IsBlockInstance
441 |     """
442 |     instance = __InstanceObjectFromId(object_id, True)
443 |     guids = scriptcontext.doc.Objects.AddExplodedInstancePieces(instance, explodeNestedInstances=explode_nested_instances, deleteInstance=True)
444 |     if guids:
445 |       scriptcontext.doc.Views.Redraw()
446 |     return guids
447 | 
448 | 
449 | def InsertBlock( block_name, insertion_point, scale=(1,1,1), angle_degrees=0, rotation_normal=(0,0,1) ):
450 |     """Inserts a block whose definition already exists in the document
451 |     Parameters:
452 |       block_name (str): name of an existing block definition
453 |       insertion_point (point): insertion point for the block
454 |       scale ({number, number, number]): x,y,z scale factors
455 |       angle_degrees (number, optional): rotation angle in degrees
456 |       rotation_normal (vector, optional): the axis of rotation.
457 |     Returns:
458 |       guid: id for the block that was added to the doc
459 |     Example:
460 |     See Also:
461 |     """
462 |     insertion_point = rhutil.coerce3dpoint(insertion_point, True)
463 |     rotation_normal = rhutil.coerce3dvector(rotation_normal, True)
464 |     angle_radians = math.radians(angle_degrees)
465 |     trans = Rhino.Geometry.Transform
466 |     move = trans.Translation(insertion_point[0],insertion_point[1],insertion_point[2])
467 |     scale = trans.Scale(Rhino.Geometry.Plane.WorldXY, scale[0], scale[1], scale[2])
468 |     rotate = trans.Rotation(angle_radians, rotation_normal, Rhino.Geometry.Point3d.Origin)
469 |     xform = move * scale * rotate
470 |     return InsertBlock2( block_name, xform )
471 | 
472 | 
473 | def InsertBlock2(block_name, xform):
474 |     """Inserts a block whose definition already exists in the document
475 |     Parameters:
476 |       block_name (str): name of an existing block definition
477 |       xform (transform): 4x4 transformation matrix to apply
478 |     Returns:
479 |       guid: id for the block that was added to the doc on success
480 |     Example:
481 |     See Also:
482 |     """
483 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
484 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
485 |     xform = rhutil.coercexform(xform, True)
486 |     id = scriptcontext.doc.Objects.AddInstanceObject(idef.Index, xform )
487 |     if id!=System.Guid.Empty:
488 |         scriptcontext.doc.Views.Redraw()
489 |         return id
490 | 
491 | 
492 | def IsBlock(block_name):
493 |     """Verifies the existence of a block definition in the document.
494 |     Parameters:
495 |       block_name (str): name of an existing block definition
496 |     Returns:
497 |       bool: True or False
498 |     Example:
499 |       import rhinoscriptsyntax as rs
500 |       strBlock = rs.GetString("Block name")
501 |       if rs.IsBlock(strBlock):
502 |           print("The block definition exists.")
503 |       else:
504 |           print("The block definition does not exist.")
505 |     See Also:
506 |       IsBlockEmbedded
507 |       IsBlockInstance
508 |       IsBlockInUse
509 |       IsBlockReference
510 |     """
511 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
512 |     return (idef is not None)
513 | 
514 | 
515 | def IsBlockEmbedded(block_name):
516 |     """Verifies a block definition is embedded, or linked, from an external file.
517 |     Parameters:
518 |       block_name (str): name of an existing block definition
519 |     Returns:
520 |       bool: True or False
521 |     Example:
522 |       import rhinoscriptsyntax as rs
523 |       strBlock = rs.GetString("Block name")
524 |       if rs.IsBlock(strBlock):
525 |           if rs.IsBlockEmbedded(strBlock):
526 |               print("The block definition is embedded.")
527 |           else:
528 |               print("The block definition is not embedded.")
529 |       else:
530 |           print("The block definition does not exist.")
531 |     See Also:
532 |       IsBlock
533 |       IsBlockInstance
534 |       IsBlockInUse
535 |       IsBlockReference
536 |     """
537 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
538 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
539 |     ut = Rhino.DocObjects.InstanceDefinitionUpdateType
540 |     return (idef.UpdateType==ut.Embedded or idef.UpdateType==ut.Static or idef.UpdateType==ut.LinkedAndEmbedded)
541 | 
542 | 
543 | def IsBlockInstance(object_id):
544 |     """Verifies an object is a block instance
545 |     Parameters:
546 |       object_id (guid): The identifier of an existing block insertion object
547 |     Returns:
548 |       bool: True or False
549 |     Example:
550 |       import rhinoscriptsyntax as rs
551 |       obj = rs.GetObject("Select block instance")
552 |       if rs.IsBlockInstance(obj):
553 |           print("The object is a block instance.")
554 |       else:
555 |           print("The object is not a block instance.")
556 |     See Also:
557 |       IsBlock
558 |       IsBlockEmbedded
559 |       IsBlockInUse
560 |       IsBlockReference
561 |     """
562 |     return  __InstanceObjectFromId(object_id, False) is not None
563 | 
564 | 
565 | def IsBlockInUse(block_name, where_to_look=0):
566 |     """Verifies that a block definition is being used by an inserted instance
567 |     Parameters:
568 |       block_name (str): name of an existing block definition
569 |       where_to_look (number, optional): One of the following values
570 |            0 = Check for top level references in active document
571 |            1 = Check for top level and nested references in active document
572 |            2 = Check for references in other instance definitions
573 |     Returns:
574 |       bool: True or False
575 |     Example:
576 |       import rhinoscriptsyntax as rs
577 |       strBlock = rs.GetString("Block name")
578 |       if rs.IsBlock(strBlock):
579 |           if rs.IsBlockInUse(strBlock):
580 |               print("The block definition is in use.")
581 |           else:
582 |               print("The block definition is not in use.")
583 |       else:
584 |           print("The block definition does not exist.")
585 |     See Also:
586 |       IsBlock
587 |       IsBlockInstance
588 |       IsBlockEmbedded
589 |       IsBlockReference
590 |     """
591 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
592 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
593 |     return idef.InUse(where_to_look)
594 | 
595 | 
596 | def IsBlockReference(block_name):
597 |     """Verifies that a block definition is from a reference file.
598 |     Parameters:
599 |       block_name (str): name of an existing block definition
600 |     Returns:
601 |       bool: True or False
602 |     Example:
603 |       import rhinoscriptsyntax as rs
604 |       strBlock = rs.GetString("Block name")
605 |       if rs.IsBlock(strBlock):
606 |           if rs.IsBlockReference(strBlock):
607 |               print("The block definition is a reference definition.")
608 |           else:
609 |               print("The block definition is not a reference definition.")
610 |       else:
611 |           print("The block definition does not exist.")
612 |     See Also:
613 |       IsBlock
614 |       IsBlockEmbedded
615 |       IsBlockInUse
616 |       IsBlockInstance
617 |     """
618 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
619 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
620 |     return idef.IsReference
621 | 
622 | 
623 | def RenameBlock( block_name, new_name ):
624 |     """Renames an existing block definition
625 |     Parameters:
626 |       block_name (str): name of an existing block definition
627 |       new_name (str): name to change to
628 |     Returns:
629 |       bool: True or False indicating success or failure
630 |     Example:
631 |       import rhinoscriptsyntax as rs
632 |       strOldBlock = rs.GetString("Old block name")
633 |       if strOldBlock:
634 |           strNewBlock = rs.GetString("New block name")
635 |           if strNewBlock:
636 |               rs.RenameBlock (strOldBlock, strNewBlock)
637 |     See Also:
638 |       BlockNames
639 |       IsBlock
640 |     """
641 |     idef = scriptcontext.doc.InstanceDefinitions.Find(block_name)
642 |     if not idef: raise ValueError("%s does not exist in InstanceDefinitionsTable"%block_name)
643 |     description = idef.Description
644 |     rc = scriptcontext.doc.InstanceDefinitions.Modify(idef, new_name, description, False)
645 |     return rc
646 | 
```

