{"id":19548535,"url":"https://github.com/goswinr/rhino.scripting","last_synced_at":"2025-04-26T20:30:58.230Z","repository":{"id":65959052,"uuid":"273531220","full_name":"goswinr/Rhino.Scripting","owner":"goswinr","description":"A complete reimplementation of the Rhino-Script-Syntax in F#","archived":false,"fork":false,"pushed_at":"2025-04-24T05:50:17.000Z","size":24557,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-24T06:32:28.439Z","etag":null,"topics":["csharp","fsharp","rhino","rhino3d","rhinocommon","rhinopython","rhinoscript"],"latest_commit_sha":null,"homepage":"https://goswinr.github.io/Rhino.Scripting/","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goswinr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-06-19T15:48:16.000Z","updated_at":"2025-04-24T05:50:21.000Z","dependencies_parsed_at":"2024-01-07T02:12:38.225Z","dependency_job_id":"7f9455a8-4ffb-499d-ac4e-5da619c8391b","html_url":"https://github.com/goswinr/Rhino.Scripting","commit_stats":{"total_commits":690,"total_committers":2,"mean_commits":345.0,"dds":"0.024637681159420333","last_synced_commit":"7b810db4d85825504afff9bfc7104a62d1d75d5f"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FRhino.Scripting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FRhino.Scripting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FRhino.Scripting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FRhino.Scripting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goswinr","download_url":"https://codeload.github.com/goswinr/Rhino.Scripting/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251051277,"owners_count":21528786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","fsharp","rhino","rhino3d","rhinocommon","rhinopython","rhinoscript"],"created_at":"2024-11-11T03:56:08.024Z","updated_at":"2025-04-26T20:30:58.217Z","avatar_url":"https://github.com/goswinr.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"![logo](https://raw.githubusercontent.com/goswinr/Rhino.Scripting/main/Docs/img/logo.png)\n# Rhino.Scripting\n\n[![Rhino.Scripting on nuget.org](https://img.shields.io/nuget/v/Rhino.Scripting)](https://www.nuget.org/packages/Rhino.Scripting/)\n[![Build Status](https://github.com/goswinr/Rhino.Scripting/actions/workflows/build.yml/badge.svg)](https://github.com/goswinr/Rhino.Scripting/actions/workflows/build.yml)\n[![Docs Build Status](https://github.com/goswinr/Rhino.Scripting/actions/workflows/docs.yml/badge.svg)](https://github.com/goswinr/Rhino.Scripting/actions/workflows/docs.yml)\n[![Check dotnet tools](https://github.com/goswinr/Rhino.Scripting/actions/workflows/outdatedDotnetTool.yml/badge.svg)](https://github.com/goswinr/Rhino.Scripting/actions/workflows/outdatedDotnetTool.yml)\n[![license](https://img.shields.io/github/license/goswinr/Rhino.Scripting)](LICENSE.md)\n![code size](https://img.shields.io/github/languages/code-size/goswinr/Rhino.Scripting.svg)\n\nRhino.Scripting is a complete re-implementation of the original **RhinoScript syntax** in and for F# (and C#).\u003cbr\u003e\nBefore this repo, the high-level RhinoScript API was only available for VBScript and (Iron-)Python.\u003cbr\u003e\nThis repo enables the use of the RhinoScriptSyntax in F# and C#\u003cbr\u003e\ntogether with all the great coding experience and editor tooling that come with F# and C#, like:\u003cbr\u003e\n- automatic code completion while typing.\u003cbr\u003e\n- automatic error checking and highlighting in the background.\u003cbr\u003e\n- type info on mouse over.\u003cbr\u003e\n- type safety even without type annotation (= type inference in F#).\u003cbr\u003e\n\n## What is RhinoScript?\n\nRhinoScript provides application scripting for the [Rhino3D](https://www.rhino3d.com/) CAD app.\u003cbr\u003e\nRhinoScript has [more than 900 functions](https://developer.rhino3d.com/api/RhinoScriptSyntax/) to control all kinds of aspects of automating Rhino3D.\u003cbr\u003e\nIt was originally implemented in 2002 in VBScript.\u003cbr\u003e\nExtensive documentation on the original VBScript-based version is available [here](https://developer.rhino3d.com/guides/rhinoscript/).\n\nIn 2010, all functions from [RhinoScript were reimplemented in IronPython](https://developer.rhino3d.com/guides/#rhinopython) (Python running on .NET).\u003cbr\u003e\nThis allowed the use of a modern, rich, and dynamically typed programming language with a huge standard library and \u003cbr\u003e\nalso access to all functions of the underlying .NET Framework as well as the [RhinoCommon SDK](https://developer.rhino3d.com/guides/rhinocommon/).\n\n## What is this repo?\n\nThis repo has [all original  RhinoScript functions](https://developer.rhino3d.com/api/RhinoScriptSyntax/) reimplemented in [F#](https://fsharp.org/).\u003cbr\u003e\nIt is literally a translation of [the open-source IronPython rhinoscriptsyntax](https://github.com/mcneel/rhinoscriptsyntax) implementation to F#.\u003cbr\u003e\n[You can see all 900+ methods in this repo in the docs](https://goswinr.github.io/Rhino.Scripting/reference/rhino-scripting-rhinoscriptsyntax.html).\n\nA few minor bugs from the Python implementation are fixed and a few extra methods and optional parameters were added.\u003cbr\u003e\nI have been using this library extensively for my own professional scripting needs since 2019.\u003cbr\u003e\nIf you have problems, questions, or find a bug, please open an [issue](https://github.com/goswinr/Rhino.Scripting/issues).\n\n## Get started\n\nThe recommended scripting use case is via [Fesh](https://github.com/goswinr/Fesh.Rhino), the dedicated F# scripting editor for Rhino.\u003cbr\u003e\nHowever, you can use this library just as well in the new Rhino 8 [ScriptEditor](https://www.rhino3d.com/features/developer/scripting/#refreshed-editor--new-in-8-) with C# or in independently compiled F#, C#, or VB.net projects.\n\n### Get started in F#\n\nFirst reference the assemblies.\n```fsharp\n#r \"nuget: Rhino.Scripting, 0.10.0\"\n```\n\nThe main namespace is  `Rhino.Scripting`.\u003cbr\u003e\nThe main class of this library is called `RhinoScriptSyntax` it has all ~900 functions as static methods.\u003cbr\u003e\nIn F# you can create an alias like this:\n\n```fsharp\nopen Rhino.Scripting\ntype rs = RhinoScriptSyntax\n```\n\nthen use any of the RhinoScript functions like you would in Python or VBScript.\u003cbr\u003e\nThe `CoerceXXXX` functions will help you create types if you are too lazy to fully specify them.\n\n```fsharp\nlet pl = rs.CoercePlane(0 , 80 , 0) // makes World XY plane at point\nrs.AddText(\"Hello, Fesh\", pl, height = 50.)\n```\n\nFor F# scripting the [Rhino.Scripting.Fsharp](https://github.com/goswinr/Rhino.Scripting.Fsharp) provides useful extensions and curried functions for piping and partial application.\n\n### Get started in C#\nYou can use it via the new Rhino 8 [ScriptEditor](https://www.rhino3d.com/features/developer/scripting/#refreshed-editor--new-in-8-).\nFirst reference the assemblies.\n\n```csharp\n#r \"nuget: FSharp.Core, 9.0.201\" // when used in Rhino 8 ScriptEditor all dependencies need to be added explicitly\n#r \"nuget: Rhino.Scripting, 0.10.0\"\n```\nThe main namespace is  `Rhino.Scripting`.\u003cbr\u003e\nThe main class of this library is called `RhinoScriptSyntax` it has all ~900 functions as static methods.\u003cbr\u003e\nIn C# you can create an alias like this:\n\n```csharp\nusing rs = Rhino.Scripting.RhinoScriptSyntax;\n```\n\nthen you can use it like the RhinoScriptSyntax in Python:\n```csharp\nvar pt =  rs.GetObject(\"Select an Object\");\nrs.ObjectColor(pt, System.Drawing.Color.Blue);\n```\n\n\n## How about the dynamic types and optional parameters from VBScript and Python?\nMany RhinoScript functions take variable types of input parameters.\u003cbr\u003e\nThis is implemented with method overloads.\u003cbr\u003e\nMany RhinoScript functions have optional parameters.\u003cbr\u003e\nThese are also implemented as optional method parameters.\u003cbr\u003e\nMany RhinoScript functions are getters and setters at the same time.\u003cbr\u003e\nDepending on if an argument is provided or not, the function acts as a getter or setter.\u003cbr\u003e\nThis is also implemented with method overloads.\n\n### Example\nFor example `rs.ObjectLayer` can be called in several ways:\n\nTo get the layer of one object, returns a string:\u003cbr\u003e\n```fsharp\nrs.ObjectLayer(guid)\n```\nTo set the layer of one object (fails if layer does not exist), no return value:\u003cbr\u003e\n```fsharp\nrs.ObjectLayer(guid, string)\n```\nTo set the layer of one object, and create the layer if it does not exist yet, no return value:\u003cbr\u003e\n```fsharp\nrs.ObjectLayer(guid, string, createLayerIfMissing = true )\n```\nTo set the layer of several objects (fails if layer does not exist), no return value:\u003cbr\u003e\n```fsharp\nrs.ObjectLayer(list of guids, string)\n```\nTo set the layer of several objects, and create the layer if it does not exist yet, no return value:\u003cbr\u003e\n```fsharp\nrs.ObjectLayer(list of guids, string, createLayerIfMissing = true )\n```\n\nThese are implemented with 3 overloads and  `Optional` and `DefaultParameterValue` parameters:\n```fsharp\n    ///\u003csummary\u003eReturns the full layer name of an object.\n    /// parent layers are separated by \u003cc\u003e::\u003c/c\u003e.\u003c/summary\u003e\n    ///\u003cparam name=\"objectId\"\u003e(Guid) The identifier of the object\u003c/param\u003e\n    ///\u003creturns\u003e(string) The object's current layer.\u003c/returns\u003e\n    static member ObjectLayer(objectId:Guid) : string = //GET\n        let obj = RhinoScriptSyntax.CoerceRhinoObject(objectId)\n        let index = obj.Attributes.LayerIndex\n        State.Doc.Layers.[index].FullPath\n\n    ///\u003csummary\u003eModifies the layer of an object ,\n    ///     optionally creates layer if it does not exist yet.\u003c/summary\u003e\n    ///\u003cparam name=\"objectId\"\u003e(Guid) The identifier of the object\u003c/param\u003e\n    ///\u003cparam name=\"layer\"\u003e(string) Name of an existing layer\u003c/param\u003e\n    ///\u003cparam name=\"createLayerIfMissing\"\u003e(bool) Optional,\n    ///     Default Value: \u003cc\u003efalse\u003c/c\u003e Set true to create Layer\n    ///     if it does not exist yet.\u003c/param\u003e\n    ///\u003cparam name=\"allowAllUnicode\"\u003e(bool) Optional,\n    ///     Allow Ambiguous Unicode characters too \u003c/param\u003e\n    ///\u003cparam name=\"collapseParents\"\u003e(bool) Optional,\n    ///     Collapse parent layers in Layer UI \u003c/param\u003e\n    ///\u003creturns\u003e(unit) void, nothing.\u003c/returns\u003e\n    static member ObjectLayer( objectId:Guid\n                             , layer:string\n                             ,[\u003cOPT;DEF(false)\u003e]createLayerIfMissing:bool\n                             ,[\u003cOPT;DEF(false:bool)\u003e]allowAllUnicode:bool\n                             ,[\u003cOPT;DEF(false:bool)\u003e]collapseParents:bool) : unit = //SET\n        let obj = RhinoScriptSyntax.CoerceRhinoObject(objectId)\n        let layerIndex =\n            if createLayerIfMissing then\n                UtilLayer.getOrCreateLayer(layer, UtilLayer.randomLayerColor,\n                    UtilLayer.ByParent, UtilLayer.ByParent,\n                    allowAllUnicode,collapseParents).Index\n            else\n                RhinoScriptSyntax.CoerceLayer(layer).Index\n        obj.Attributes.LayerIndex \u003c- layerIndex\n        obj.CommitChanges() |\u003e ignore\n        State.Doc.Views.Redraw()\n\n    ///\u003csummary\u003eModifies the layer of multiple objects, optionally creates\n    ///     layer if it does not exist yet.\u003c/summary\u003e\n    ///\u003cparam name=\"objectIds\"\u003e(Guid seq) The identifiers of the objects\u003c/param\u003e\n    ///\u003cparam name=\"layer\"\u003e(string) Name of an existing layer\u003c/param\u003e\n    ///\u003cparam name=\"createLayerIfMissing\"\u003e(bool) Optional,\n    ///     Default Value: \u003cc\u003efalse\u003c/c\u003e Set true to create Layer\n    ///     if it does not exist yet.\u003c/param\u003e\n    ///\u003cparam name=\"allowUnicode\"\u003e(bool) Optional,\n    ///     Allow Ambiguous Unicode characters too \u003c/param\u003e\n    ///\u003cparam name=\"collapseParents\"\u003e(bool) Optional,\n    ///     Collapse parent layers in Layer UI \u003c/param\u003e\n    ///\u003creturns\u003e(unit) void, nothing.\u003c/returns\u003e\n    static member ObjectLayer( objectIds:Guid seq\n                             , layer:string\n                             , [\u003cOPT;DEF(false)\u003e]createLayerIfMissing:bool\n                             , [\u003cOPT;DEF(false:bool)\u003e]allowUnicode:bool\n                             , [\u003cOPT;DEF(false:bool)\u003e]collapseParents:bool) : unit = //MULTISET\n        let layerIndex =\n            if createLayerIfMissing then\n                UtilLayer.getOrCreateLayer(layer,\n                    UtilLayer.randomLayerColor, UtilLayer.ByParent,\n                    UtilLayer.ByParent, allowUnicode, collapseParents).Index\n            else\n                RhinoScriptSyntax.CoerceLayer(layer).Index\n        for objectId in objectIds do\n            let obj = RhinoScriptSyntax.CoerceRhinoObject(objectId)\n            obj.Attributes.LayerIndex \u003c- layerIndex\n            obj.CommitChanges() |\u003e ignore\n        State.Doc.Views.Redraw()\n```\n\n\n## Full API Documentation\n\n[goswinr.github.io/Rhino.Scripting](https://goswinr.github.io/Rhino.Scripting)\n\n## .NET Framework or .NET Core?\n\nThis library is currently only targeting .NET Framework 4.8.\u003cbr\u003e\nHowever, it should work in .NET 7.0 or higher as well as per [the offical guidelines](https://developer.rhino3d.com/guides/rhinocommon/moving-to-dotnet-7/#migrating-your-plugin)\n\nBut I can not be compiled for net7.0.\nC# allows a project with RhinoCommon to compile targeting net7, but arguably it shouldn't.\nF# is stricter and does not allow this. See [dotnet/fsharp#17295 (comment)](https://github.com/dotnet/fsharp/issues/17295#issuecomment-2158893769)\n\nSo this libary is waiting for a [RhinoCommon Nuget](https://www.nuget.org/packages/RhinoCommon/#supportedframeworks-body-tab) nuget properly targeting `net7.0`.\nIt is actually planned but seems to be tricky because of some hacks from the past:\nhttps://mcneel.myjetbrains.com/youtrack/issue/RH-77311/Add-.NET-7-target-to-nuget-packages\n\n\n\n## Build from source\nTo build this library from source you need the .NET SDK 7 or higher installed\u003cbr\u003e\nThen just run in the root folder:\n```bash\ndotnet build ForPublishing.fsproj\n```\n\nThis will first combine all `Scripting_*.fs` files into one file and compile it.\u003cbr\u003e\nThis is neede because F# type extension are not visible from C# editor tooling.\n\n## Edit the source\nWhile having all 900 methods on one class in one file is needed for publishing via `ForPublishing.fsproj` \u003cbr\u003e\nit is not ideal for editing.\u003cbr\u003e\nThe source is split into several files imitating the structure of the original Python implementation.\u003cbr\u003e\nOpen the project `ForEditing.fsproj` to edit the source.\u003cbr\u003e\n\n\n## Changelog\n\nsee [CHANGELOG.md](https://github.com/goswinr/Rhino.Scripting/blob/main/CHANGELOG.md)\n\n## Thread Safety\nWhile the main Rhino Document is officially not thread safe, this library can be used from any thread.\u003cbr\u003e\nIf running async this library will automatically marshal all calls that affect the UI to the main Rhino UI thread \u003cbr\u003e\nand wait for switching back till completion on UI thread.\u003cbr\u003e\nModifying the Rhino Document from a background thread is actually OK as long as there is only one thread doing it.\u003cbr\u003e\nThe main reason to use this library async is to keep the Rhino UI and Fesh scripting editor UI responsive while doing long running operations.\n\n## Contributing\nContributions are welcome even for small things like typos. If you have problems with this library please submit an issue.\n\n## License\n[MIT](https://github.com/goswinr/Rhino.Scripting/blob/main/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoswinr%2Frhino.scripting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoswinr%2Frhino.scripting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoswinr%2Frhino.scripting/lists"}