New custom snapping with RhinoCommon

Hi Scripting Guru.

I’m trying to create a RhinoCommon script for snapping to the highest points in a cluster of points. I’m at loss for word trying to fix this error for the past week. I even used ChatGPT to diagnose these 2 persistent errors. So far no dice. Any advice? Thanks in advance!

CS0019 'Operator ‘==’ cannot be applied to operands of type ‘method group’ and ‘int’
CS8602 Dereference of a possibly null reference.


using System;
using Rhino;
using Rhino.Geometry;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Input.Custom;

public class DynamicSnapCommand : Command
{
    public override string EnglishName => "DynamicSnapCommand";

    // To track if the command is running or not
    private bool _isRunning;

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
        // Define the snap radius (100mm)
        double snapRadius = 100.0;

        // Start running the dynamic snap
        _isRunning = true;
        RhinoApp.WriteLine("Dynamic snapping is now active. Press ESC to stop.");

        // Event-based method is better than continuous loops
        while (_isRunning)
        {
            // Track mouse movement and snap logic
            var activeView = doc.Views.ActiveView;

            // Check if the active view and viewport are not null
            if (activeView == null || activeView.ActiveViewport == null)
            {
                RhinoApp.WriteLine("No active view or viewport.");
                return Result.Failure;
            }

            // Use GetPoint to track user input (mouse position)
            var gp = new GetPoint();
            gp.SetCommandPrompt("Select point for snapping");

            gp.Get(); // This ensures we capture the mouse position or user input

            // Check if the user canceled or accepted the command
            if (gp.CommandResult() != Result.Success)  // Ensure you're calling the method (gp.CommandResult())
            {
                RhinoApp.WriteLine("Failed to get point.");
                return Result.Failure;
            }

            var mousePos = gp.Point(); // This is the point selected by the user (mouse position)

            // Retrieve the points in the model space
            var pointObjs = doc.Objects.FindByObjectType(ObjectType.Point);
            if (pointObjs == null || pointObjs.Count == 0)
            {
                RhinoApp.WriteLine("No points found in the model space.");
                return Result.Failure;
            }

            // Find the highest point within 100mm radius
            Point3d? snapPoint = null;
            double maxZ = double.MinValue;

            foreach (var pointObj in pointObjs)
            {
                var point = pointObj.Geometry as Point;
                if (point == null) continue;

                double distance = point.Location.DistanceTo(mousePos);
                if (distance <= snapRadius)
                {
                    if (point.Location.Z > maxZ)
                    {
                        maxZ = point.Location.Z;
                        snapPoint = point.Location; // Store the highest Z within range
                    }
                }
            }

            // If a valid snap point is found, display the result
            if (snapPoint.HasValue)  // Correctly check if snapPoint has a value
            {
                RhinoApp.WriteLine($"Snapping to the highest point at {snapPoint.Value}");
            }
            else
            {
                RhinoApp.WriteLine("No valid snap points found within the defined radius.");
            }

            // Check for user input or stop conditions (ESC key press)
            if (gp.CommandResult() == Result.Cancel)  // Ensure you're calling the method (gp.CommandResult())
            {
                _isRunning = false;
                RhinoApp.WriteLine("Dynamic snapping stopped.");
            }

            // Allow Rhino to update its UI (this is equivalent to allowing the program to update the screen during a loop)
            RhinoApp.Wait();
        }

        return Result.Success;
    }
}

Hi @IceTea ,

Not a guru but how about using your conditional to check if the point(s) is valid… and then adding it as a snap point for your GetPoint operation via AddSnapPoint or AddSnapPoints?

https://developer.rhino3d.com/api/rhinocommon/rhino.input.custom.getpoint/addsnappoints

Hope that helps!

1 Like

Count is not a property but an extension method from LINQ. It is pointObjecs.Count(). You need to also do: using System.Linq; at the top.

Yes, don’t rely on glorified search engines to actually understand code. Your editor should have already showed you there is a problem with Count, and at the latest when compiling. For instance this code in our Script Editor will show the message

Then adding System.Linq will show:


which already should tell you that you are trying to compare a method and an int.

1 Like

Thanks Michael!! I followed your advice and after a week of playing around with it. I finally got the codes to compile without any issue.

Now, i’m hoping to have my custom snap to show up on the Osnap toolbar along with the other default snapping options. Is that doable with RhinoCommon? any advice is greatly appreciated! thanks again!!

Thanks Nathan. You’re right, CHATGPT just lead me round and round and gave me all sorts of wrong advice. I followed your advice and finally got the codes to compile after messing with it for a week.

i’m hoping to have my custom snap to show up on the Osnap toolbar along with the other default snapping options. Is that doable with RhinoCommon? any advice is greatly appreciated! thanks again!!

There is no way to add entries to the OSnap panel.