Rhino WIP Feature: ArrayCurve

Nice new feature!
As others said, It would be nice to see similar UI/UX for many other commands, even the most basic ones (for example curve fillet, you have to guess the radius, try, undo, try again etc etc) where having similar “gumball” handles to adjust the parameters would be awesome.

Will those new types of “draggable UI elements” (gumball arrows) be exposed in Rhinocommon c# ?:heart_eyes:


Anyway:

Spacing is surely interesting, and I guess it’s evaluated from the BBox size along the X axis?

So to get a “packed” aspect in this case^ you have to manually set negative spacing of -4.37 … right?
Problem is that when the user try to rotate the shape to an orientation with a smaller BBox X size, you might get a “division by zero” and get infinite amount of pieces, because X get similar to S:


An this results in a hard freeze.
ESC key doesn’t help.

See the Object count:
arraycurve_divisionByZero
This ^ is funny to play with, but is this actually needed?
Maybe a “center-center distance” would result in a more uniform UX? I don’t know.
(usually with grasshopper I do a center-center distance logic…)

So… maybe to avoid this set a “safety lock” for maximum amount of objects in the array that require the user to toggle it when sure about the result.

Or , simply change the logic of the yellow handle from “spacing” to “center-center distance”, so it will keep the amount of elements while rotation/pitch/roll are being edited…
… but this too will require the UI to prevent a possibile “divide by zero” scenario.


Anyway this case returns the first element slightly misaligned compared to the rest:
(visible also in the .gif above)


ArrayCurve first element misaligned.3dm (658.4 KB)
And it seems to happens evertime with those geometries…
9.0.26034.12305, 2026-02-03

1 Like

They already are. I’m going to write up a “Rhino WIP Feature” post on that topic very soon

3 Likes

The command understands infinite negative spacing and wont divide by zero and hard caps to a 99% negative width max and has a hard coded negative threshold for 0 thickness curves (like a line along a curve with 0 spacing or negative spacing).

However, if you ask it for 50,000 objects it will try regardless if your computer can handle it. ESC will work by the time v9 ships.

If you don’t want the bounding box rotations uncheck the Box Rotation Spacing check box and then the objects will spin in place instead of moving based on their bounds.

0546

Hopefully this graphic helps you to visualize how spacing works. The spacing is at the dots. Relax spacing is off. Relax spacing is going to take your spacing value + any remaining length of the span and divide it among the results so that the start/end objects fall centered or to the edges of the span depending if On Ends is enabled or disabled.

Your odd ball misaligned block is a known issue with RhinoCommon’s frame finding routine and is on the short list to be fixed. Change the crv seam location and it should fix it.

3 Likes

Nice!

Totally missed that, sorry. I’d make that unchecked by default…

Super.


In the meantime I recycled a method I’m using to find quick “stacking” distance for a mesh in a direction (X):
(It uses the obsolete MeshMeshFast method… I didn’t manage to make it faster with other methods…)
arraycurve_0 spacing
find mesh stack X size.gh (23.2 KB)
This would be a “0 spacing” array… maybe…

4 Likes

mesh intersectors, no matter how well optimized, really sock a performance hit on big collections.

Oh yeah, I meant to just do the evaluation just once in linear X direction (after rotations and scaling) and then use the found value to do the whole array.

Anyway, nevermind, the tool is already very nice! :grinning_face:

1 Like

_testUnleashSuperGumball confirmed! :smiley:

1 Like

Very good (You have made this tool native for all surface types.), in my opinion, you are moving in the right direction.Consider adding a feature that helps resize objects along a curve, as shown in the video, second 0,55 . https://youtu.be/-jbPiVxyrEs

2 Likes

do you mean mid point scaling and graduated tapers?

10 Likes

Hi @Trav

It’s Perfect!

I would probably recommend to have same for Rotation.

I mean, similar to Start-Mid-End point scaling.

Could be useful.

1 Like

Yeah, that was actually considered, but felt like a lot of feature creep and would grow the already massive dialog even more, but we’ll see how it goes, might make a great addition in the future.

Cool. I thought there wasn’t. )

1 Like

Is that possible to make foldable sections on the dialog, folded by default?

The person who wants to have those features in will not be scared of complex dialog.

The regular person won’t see these options and have simple dialog.

The other way is make a switch between simple/advanced interface.

Like Windows Calculator has Standard/Scientific.

1 Like

Yeah for sure, there’s all kinds of ways to try to solve the complication puzzle.

Questo è un comando fantastico!

Molti altri strumenti in Rhino dovrebbero prendere spunto da questo. L’interattività col “gioco” delle maniglie dovrebbe essere la norma.

Più interattività significa maggiore libertà, modellazione più sciolta, disinvolta, meno rigidità nella costruzione di forme e strutture.

3 Likes

Please, consider using expandable/collapsible sub-options to save menu space. :slight_smile: This is the easiest approach. No wonder that recently it was implemented in some new tools in Rhino 9 WIP, so the code is already there and you just have to apply it to other tools with tall pop-up windows. The Rhino Options panel uses a similar approach since many years.

You can either use arrows to expand the sub-options, or simply click on the name of the sub-option to expand it or shrink it. It’s described in this proposal here:

I guess that most users will not need the “Sizes” option (scale), as well as a few others, so being able to set the menu at a minimum size (and remember the state during the session, unless it’s changed by the user again) will leave more viewport space.

3 Likes

Not sure if it’s just a bug in the video capturing or it’s an actual issue, but I noticed that your last video had several moments with a short lag when you tried to drag the scale handle. Is that a real lag in Rhino 9 WIP? If so, could it be improved?

A similar lag is seen in Rhino 7 when the Mouse ToolTips option is activated.

test.3dm (399.9 KB) There is a problem with how Block type objects are displayed during operation. It is also necessary to resolve the issue of assigning groups to new objects. In particular, they should be assigned separately to each individual item if they are in a group, rather than including groups in a single group.

private List PreserveGroupStructurePerTransform(
List sourceObjects,
List transformedGuids,
int transformCount)
{
List newGroupIndices = new List();

        // Dictionary: key = index of the old group, value = list of objects in this group
        Dictionary<int, List<int>> originalGroups = new Dictionary<int, List<int>>();

        // We collect information about original groups
        for (int i = 0; i < sourceObjects.Count; i++)
        {
            RhinoObject obj = sourceObjects[i];
            if (obj != null && obj.Attributes.GroupCount > 0)
            {
                int[] groups = obj.GetGroupList();
                foreach (int groupIndex in groups)
                {
                    if (!originalGroups.ContainsKey(groupIndex))
                    {
                        originalGroups[groupIndex] = new List<int>();
                    }
                    originalGroups[groupIndex].Add(i); // we preserve the object index
                }
            }
        }

        // For each original group
        foreach (var kvp in originalGroups)
        {
            int oldGroupIndex = kvp.Key;
            List<int> objectIndices = kvp.Value; // indexes of objects that were in this group

            // For EVERY transformation, we create a NEW group
            for (int transIdx = 0; transIdx < transformCount; transIdx++)
            {
                int newGroupIndex = Rhino.RhinoDoc.ActiveDoc.Groups.Add();
                newGroupIndices.Add(newGroupIndex);

                // Add all objects that were in the original group to the new group.
                foreach (int objIdx in objectIndices)
                {
                    // Calculate the index of the transformed object
                    // objIdx - index of the original object
                    // transIdx - transformation inde
                    int transformedIndex = objIdx * transformCount + transIdx;

                    if (transformedIndex < transformedGuids.Count)
                    {
                        Guid guid = transformedGuids[transformedIndex];
                   
                        RhinoObject newObj = Rhino.RhinoDoc.ActiveDoc.Objects.FindId(guid);

                        newObj.Attributes.RemoveFromAllGroups();  //Remove FromAll Groups

                        if (newObj != null)
                        {
                            newObj.Attributes.AddToGroup(newGroupIndex);
                            newObj.CommitChanges();
                        }
                    }
                }
            }
        }

        return newGroupIndices;
    }

I use this approach for my tools. In my opinion, this is a correct distribution of groups.

1 Like

Shift key dragging snaps…

Yeah the preview mesh conduit is still a work in progress such is the case with block instances. That’s on the short list to implement and yeah, the nested groups can be independent per object. History is still a mess too, all things being worked on before 9 ships. RH-92358 RH-92359

3 Likes

This looks great. Especially the posibility to use Blocks. AutoCAD has an option to insert Blocks on a Curve as part of the Divide/Messure commands. That would also be nice to have in Rhino 8. Orientation of the Block relative to the curvature or not.