Fix build errors for .NET 7.0 / Rhino 9 WIP

- Target .NET 7.0 for Rhino 9 WIP compatibility
- Fix Sphere volume calculation (manual formula)
- Fix BooleanDifference API signature
- Replace IGH_BakeAwareObject with IGH_GeometricGoo for baking
- Fix anonymous type declarations in GrasshopperHandler

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
architeur
2025-12-29 21:19:27 +01:00
parent e066f9fce5
commit f9d6715056
3 changed files with 52 additions and 60 deletions

View File

@@ -221,7 +221,8 @@ namespace RhinoMCP
var id = doc.Objects.AddSphere(sphere); var id = doc.Objects.AddSphere(sphere);
doc.Views.Redraw(); doc.Views.Redraw();
return new { success = true, id = id.ToString(), radius, volume = sphere.Volume() }; var volume = (4.0 / 3.0) * Math.PI * radius * radius * radius;
return new { success = true, id = id.ToString(), radius, volume };
} }
private static object CreateBox(RhinoDoc doc, JObject p) private static object CreateBox(RhinoDoc doc, JObject p)
@@ -548,7 +549,7 @@ namespace RhinoMCP
.Where(b => b != null) .Where(b => b != null)
.ToList(); .ToList();
var result = Brep.CreateBooleanDifference(baseBrep, subtractBreps!, doc.ModelAbsoluteTolerance); var result = Brep.CreateBooleanDifference(new[] { baseBrep }, subtractBreps!, doc.ModelAbsoluteTolerance);
if (result == null || result.Length == 0) if (result == null || result.Length == 0)
return new { error = "Boolean difference failed" }; return new { error = "Boolean difference failed" };

View File

@@ -37,8 +37,7 @@ namespace RhinoMCP
private static GH_Document? GetActiveDocument() private static GH_Document? GetActiveDocument()
{ {
var editor = Instances.ActiveCanvas?.Document; return Instances.ActiveCanvas?.Document;
return editor;
} }
private static object OpenDefinition(JObject p) private static object OpenDefinition(JObject p)
@@ -53,7 +52,7 @@ namespace RhinoMCP
if (Instances.ActiveCanvas == null) if (Instances.ActiveCanvas == null)
{ {
RhinoApp.RunScript("_Grasshopper", false); RhinoApp.RunScript("_Grasshopper", false);
System.Threading.Thread.Sleep(1000); // Wait for GH to open System.Threading.Thread.Sleep(1000);
} }
var io = new GH_DocumentIO(); var io = new GH_DocumentIO();
@@ -94,23 +93,21 @@ namespace RhinoMCP
foreach (var obj in doc.Objects) foreach (var obj in doc.Objects)
{ {
var info = new Dictionary<string, object> var instanceGuid = obj.InstanceGuid.ToString();
{ var name = obj.Name ?? "";
["instance_guid"] = obj.InstanceGuid.ToString(), var nickname = obj.NickName ?? "";
["name"] = obj.Name ?? "", var category = obj.Category ?? "";
["nickname"] = obj.NickName ?? "", var subcategory = obj.SubCategory ?? "";
["category"] = obj.Category ?? "", var posX = obj.Attributes.Pivot.X;
["subcategory"] = obj.SubCategory ?? "", var posY = obj.Attributes.Pivot.Y;
["position"] = new { x = obj.Attributes.Pivot.X, y = obj.Attributes.Pivot.Y }
};
if (obj is GH_NumberSlider slider) if (obj is GH_NumberSlider slider)
{ {
sliders.Add(new sliders.Add(new
{ {
info["instance_guid"], instance_guid = instanceGuid,
info["nickname"], nickname = nickname,
info["position"], position = new { x = posX, y = posY },
current_value = slider.CurrentValue, current_value = slider.CurrentValue,
min_value = (double)slider.Slider.Minimum, min_value = (double)slider.Slider.Minimum,
max_value = (double)slider.Slider.Maximum, max_value = (double)slider.Slider.Maximum,
@@ -121,9 +118,9 @@ namespace RhinoMCP
{ {
toggles.Add(new toggles.Add(new
{ {
info["instance_guid"], instance_guid = instanceGuid,
info["nickname"], nickname = nickname,
info["position"], position = new { x = posX, y = posY },
value = toggle.Value value = toggle.Value
}); });
} }
@@ -131,38 +128,38 @@ namespace RhinoMCP
{ {
panels.Add(new panels.Add(new
{ {
info["instance_guid"], instance_guid = instanceGuid,
info["nickname"], nickname = nickname,
info["position"], position = new { x = posX, y = posY },
text = panel.UserText text = panel.UserText
}); });
} }
else if (obj is IGH_Component component) else if (obj is IGH_Component component)
{ {
var inputs = component.Params.Input.Select(p => new var inputs = component.Params.Input.Select(param => new
{ {
name = p.Name, name = param.Name,
nickname = p.NickName, nickname = param.NickName,
type = p.TypeName, type = param.TypeName,
source_count = p.SourceCount source_count = param.SourceCount
}).ToList(); }).ToList();
var outputs = component.Params.Output.Select(p => new var outputs = component.Params.Output.Select(param => new
{ {
name = p.Name, name = param.Name,
nickname = p.NickName, nickname = param.NickName,
type = p.TypeName, type = param.TypeName,
recipient_count = p.Recipients.Count recipient_count = param.Recipients.Count
}).ToList(); }).ToList();
components.Add(new components.Add(new
{ {
info["instance_guid"], instance_guid = instanceGuid,
info["name"], name = name,
info["nickname"], nickname = nickname,
info["category"], category = category,
info["subcategory"], subcategory = subcategory,
info["position"], position = new { x = posX, y = posY },
inputs, inputs,
outputs outputs
}); });
@@ -197,7 +194,6 @@ namespace RhinoMCP
if (slider == null) if (slider == null)
return new { error = $"Slider '{sliderName}' not found" }; return new { error = $"Slider '{sliderName}' not found" };
// Clamp value to slider range
var min = (double)slider.Slider.Minimum; var min = (double)slider.Slider.Minimum;
var max = (double)slider.Slider.Maximum; var max = (double)slider.Slider.Maximum;
value = Math.Max(min, Math.Min(max, value)); value = Math.Max(min, Math.Min(max, value));
@@ -257,7 +253,6 @@ namespace RhinoMCP
var doc = GetActiveDocument(); var doc = GetActiveDocument();
if (doc == null) if (doc == null)
{ {
// Try to open Grasshopper
RhinoApp.RunScript("_Grasshopper", false); RhinoApp.RunScript("_Grasshopper", false);
System.Threading.Thread.Sleep(1000); System.Threading.Thread.Sleep(1000);
doc = GetActiveDocument(); doc = GetActiveDocument();
@@ -270,7 +265,6 @@ namespace RhinoMCP
var x = position?["x"]?.Value<float>() ?? 0; var x = position?["x"]?.Value<float>() ?? 0;
var y = position?["y"]?.Value<float>() ?? 0; var y = position?["y"]?.Value<float>() ?? 0;
// Find component by name in the component server
var proxy = Instances.ComponentServer.FindObjectByName(componentName, true, true); var proxy = Instances.ComponentServer.FindObjectByName(componentName, true, true);
if (proxy == null) if (proxy == null)
return new { error = $"Component '{componentName}' not found" }; return new { error = $"Component '{componentName}' not found" };
@@ -312,17 +306,14 @@ namespace RhinoMCP
var targetId = p["target_component"]?.ToString() ?? ""; var targetId = p["target_component"]?.ToString() ?? "";
var targetInput = p["target_input"]?.ToString() ?? ""; var targetInput = p["target_input"]?.ToString() ?? "";
// Find source component
var sourceObj = FindComponent(doc, sourceId); var sourceObj = FindComponent(doc, sourceId);
if (sourceObj == null) if (sourceObj == null)
return new { error = $"Source component '{sourceId}' not found" }; return new { error = $"Source component '{sourceId}' not found" };
// Find target component
var targetObj = FindComponent(doc, targetId); var targetObj = FindComponent(doc, targetId);
if (targetObj == null) if (targetObj == null)
return new { error = $"Target component '{targetId}' not found" }; return new { error = $"Target component '{targetId}' not found" };
// Get output parameter
IGH_Param? outputParam = null; IGH_Param? outputParam = null;
if (sourceObj is IGH_Component sourceComp) if (sourceObj is IGH_Component sourceComp)
{ {
@@ -337,7 +328,6 @@ namespace RhinoMCP
if (outputParam == null) if (outputParam == null)
return new { error = $"Output '{sourceOutput}' not found on source component" }; return new { error = $"Output '{sourceOutput}' not found on source component" };
// Get input parameter
IGH_Param? inputParam = null; IGH_Param? inputParam = null;
if (targetObj is IGH_Component targetComp) if (targetObj is IGH_Component targetComp)
{ {
@@ -352,7 +342,6 @@ namespace RhinoMCP
if (inputParam == null) if (inputParam == null)
return new { error = $"Input '{targetInput}' not found on target component" }; return new { error = $"Input '{targetInput}' not found on target component" };
// Create connection
inputParam.AddSource(outputParam); inputParam.AddSource(outputParam);
doc.NewSolution(true); doc.NewSolution(true);
Instances.ActiveCanvas?.Refresh(); Instances.ActiveCanvas?.Refresh();
@@ -370,13 +359,11 @@ namespace RhinoMCP
private static IGH_DocumentObject? FindComponent(GH_Document doc, string identifier) private static IGH_DocumentObject? FindComponent(GH_Document doc, string identifier)
{ {
// Try to find by GUID
if (Guid.TryParse(identifier, out var guid)) if (Guid.TryParse(identifier, out var guid))
{ {
return doc.Objects.FirstOrDefault(o => o.InstanceGuid == guid); return doc.Objects.FirstOrDefault(o => o.InstanceGuid == guid);
} }
// Try to find by name or nickname
return doc.Objects.FirstOrDefault(o => return doc.Objects.FirstOrDefault(o =>
o.Name == identifier || o.NickName == identifier); o.Name == identifier || o.NickName == identifier);
} }
@@ -436,7 +423,6 @@ namespace RhinoMCP
if (rhinoDoc == null) if (rhinoDoc == null)
return new { error = "No active Rhino document" }; return new { error = "No active Rhino document" };
// Ensure layer exists
var layerIndex = rhinoDoc.Layers.FindByFullPath(layerName, -1); var layerIndex = rhinoDoc.Layers.FindByFullPath(layerName, -1);
if (layerIndex < 0) if (layerIndex < 0)
layerIndex = rhinoDoc.Layers.Add(layerName, Color.Black); layerIndex = rhinoDoc.Layers.Add(layerName, Color.Black);
@@ -447,7 +433,6 @@ namespace RhinoMCP
{ {
if (obj is IGH_Component component) if (obj is IGH_Component component)
{ {
// Skip if we're looking for a specific component
if (!string.IsNullOrEmpty(componentName) && if (!string.IsNullOrEmpty(componentName) &&
component.Name != componentName && component.Name != componentName &&
component.NickName != componentName) component.NickName != componentName)
@@ -457,21 +442,25 @@ namespace RhinoMCP
{ {
foreach (var item in output.VolatileData.AllData(true)) foreach (var item in output.VolatileData.AllData(true))
{ {
if (item is Grasshopper.Kernel.Types.IGH_BakeAwareData bakeAware) if (item is Grasshopper.Kernel.Types.IGH_GeometricGoo goo && goo.IsValid)
{
var geo = goo.ScriptVariable() as Rhino.Geometry.GeometryBase;
if (geo != null)
{ {
var attributes = new Rhino.DocObjects.ObjectAttributes var attributes = new Rhino.DocObjects.ObjectAttributes
{ {
LayerIndex = layerIndex LayerIndex = layerIndex
}; };
Guid objId; var objId = rhinoDoc.Objects.Add(geo, attributes);
if (bakeAware.BakeGeometry(rhinoDoc, attributes, out objId)) if (objId != Guid.Empty)
bakedCount++; bakedCount++;
} }
} }
} }
} }
} }
}
rhinoDoc.Views.Redraw(); rhinoDoc.Views.Redraw();
@@ -501,7 +490,8 @@ namespace RhinoMCP
} }
else else
{ {
success = io.SaveAs(filePath); doc.FilePath = filePath;
success = io.Save();
} }
return new { success, file_path = filePath }; return new { success, file_path = filePath };

View File

@@ -2,9 +2,10 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>latest</LangVersion> <UseWindowsForms>true</UseWindowsForms>
<!-- Rhino Plugin Settings --> <!-- Rhino Plugin Settings -->
<EnableDynamicLoading>true</EnableDynamicLoading> <EnableDynamicLoading>true</EnableDynamicLoading>