History in script

Hi,

using RCommon with Py or C# even for a simple script like curve offset, Rhino does not store history.
there is a way to do it?

ps another method, besides using Rhino commands with rs.Command

Yes there are history recording methods in RhinoCommon. It is a bit complicated. I’ll see if I can find a sample.

https://developer.rhino3d.com/api/rhinocommon/rhino.docobjects.tables.objecttable/transformwithhistory

1 Like

thanks @Helvetosaur :+1:

History is quite convoluted to script.
Here’s a sample from Dale: rhino-developer-samples/rhinocommon/cs/SampleCsCommands/SampleCsHistory.cs at 7 · mcneel/rhino-developer-samples · GitHub

thanks @Gijs @Helvetosaur for reply,

in recent days I have done various tests following the links posted, but since I have just started with C# I can’t find the solution to the problem.

If it’s not too much to ask, could you give me some guidance with a simple example, even just a few lines, to start recording History?

ps I’m using editscript in Rh8

I don’t know any C#, I only know Python really. And the only history I used is via TransformWithHistory - the link I posted above.

Here is a sample python script which makes a quad mirror with the mirrored objects being history related to the original (if history is enabled).

"""Script to mirror objects in X and Y around a point (relative to active CPlane).
Pays attention to current history state. Script by Mitch Heynick 06.09.19"""

import rhinoscriptsyntax as rs
import Rhino.ApplicationSettings.HistorySettings as hs
import scriptcontext as sc

def QuadMirror():
    objs=rs.GetObjects("Select objects to quad mirror",preselect=True)
    if not objs: return
    m_pt=rs.GetPoint("Pick point to mirror around")
    if not m_pt: return
    hist=hs.RecordingEnabled
    
    plane=rs.ViewCPlane()
    plane.Origin=m_pt
    rs.EnableRedraw(False)
    xform_x=rs.XformMirror(plane.Origin,plane.XAxis)
    xform_y=rs.XformMirror(plane.Origin,plane.YAxis)
    if hist:
        x_copy=[sc.doc.Objects.TransformWithHistory(obj,xform_x) for obj in objs]
    else:
        x_copy=[sc.doc.Objects.Transform(obj,xform_x,False) for obj in objs]
    if x_copy:
        objs+=x_copy
        if hist:
            y_copy=[sc.doc.Objects.TransformWithHistory(obj,xform_y) for obj in objs]
        else:
            y_copy=[sc.doc.Objects.Transform(obj,xform_y,False) for obj in objs]
        if y_copy:
            objs+=y_copy
            rs.SelectObjects(objs)
QuadMirror()
1 Like

@0904 is the sample script from Dale not working for you? If you get stuck, please send the code you are trying to run.

As mentioned, recording History is quite convoluted to set up. So it’s not this easy:

thanks @Helvetosaur for code example, and @Gijs thanks availability

the commands I often use are subcrv mirror offset and others similar to these, to facilitate the combination of multiple commands at the same time, I create scripts (first in Py now with Rh8 I’m switching to C#) that combine the sequences of these commands to my liking. I started by experimenting with this code in RCommon to create a curve offset:

but I noticed that even with the story recorder activated, this operation started via script is not recorded, and therefore I asked the question here on the forum before committing myself to writing a code in C# and then not being able to use it since for me it is essential to maintain the story as it happens using normal commands in Rhino. I hope that for the commands mentioned initially above, recording via script is feasible and not too complex. I believed/hoped that it was only necessary to start the recording and not manage the events as @Helvetosaur so everything becomes more complex but I like challenges, I just hope it’s doable.

in C# I managed to adapt and make work a couple of my codes that I had done in Py in the past so I became familiar with C#, but for Dale’s code I couldn’t even understand how to use it and above all how to start it. . .

1 Like

Offset is not a transformation of the original, so you would need to do a complete history record to have the offset related to the original. I don’t know how to do that. The transformation part however can be history enabled via the method I outlined above.

1 Like

ok so there are some problems to verify the correct functioning before trying to write codes with a purpose that I cannot put into practice. thanks :+1:

thanks @Helvetosaur and @dale for the latest answers

if I understand how it works correctly, I should insert the linked example file into a C# code written with Visual Studio, in this way on the main page I write the action of the command I intend to execute, at the same time the @dale code recommended to me by @Gijs records the history complete with the command itself? (Before I do this, I need to create an RHP plug-in and add it to Rhino)

@0904 yes, if you run that sample from Visual Studio, it will generate a rhp on the fly when you are debugging, which makes it easier to test.
Meanwhile, @eirannejad added a YT to make it possible to use those classes in script editor
RH-79423 Script Editor project to support Rhino Command class implementation in scripts

1 Like

wonderful @Gijs :+1:
thanks for the wonderful news
as soon as possible it will be wonderful to do all this

Hi Dale, sorry for being dense about this, but are there any ways we could make the plugin in python and still have History? Obviously by using Rhino Common commands where needed?
Or is Rhino handling plugins generated by Python differently than plugins made in C++/C# ?

Based on my understanding of history calling commands it would make sense that a plugin written in any language could work with history as long as the plugin adds commands to Rhino.
But this could obviously be a simplified understanding (I am known for those… :wink: )

I don’t program often enough to want to convert to a more complex language, so a way to access history through python generated plugins would be awesome.

I guess what I would really like was if Rhino’s history was implemented in a way that any command would could be history enabled by a simple string and that Rhino automatically stored the inputdata, the command ran and the result in it’s own database, under the hood. So if we ran the command with history enabled then Rhino would just re run the command by it self if changes was detected. Obviously some commands should not support history, so it should be activated by the coder.

I would presume rhino would need a new history function, called ‘autoupdate’ or something to support this.

History is a fantastic ability and is what sets Grasshopper apart from Python for inhouse development IMO, so I would love to see this implemented in an easy to access manner for both me and other new scripters. I would love to hear your take on this.

1 Like

premise: I don’t know all the features of Rhino

but from what I understand, memorizing all the commands executed in history would mean having a
parametric CAD and as far as I know Rhino is not, and I don’t think the development is in this direction.
(I personally have never heard of any news on this)

Some time ago I asked if it was possible to set the storage of the axis in the history history of the Mirror
command so that if you move the axis the object linked to the Mirror/Symmetry adapts accordingly.

ps it would be fantastyc to have all the actions related to the story.

Thanks for you reply 0904.

I would say it is in a gray area; Grasshopper is, and Archicad and Lands rely on a magic hookup with grasshopper to do their magic, and Rhino has the ability to let you use the underlying tools that history uses but only if you make a plugin and with C++ or C# as I understand it. So based on that it “is”, but native Rhino modelling isn’t, and history for users is a half baked integration.

As you say having the ability to affect the parameters of history objects, like plane for mirror, number of objects for polar array, curves for loft etc would be a huge step forward, and these values are in the document, but out of reach for both users and scripters. And this has been wished for since history was introduced in v4 beta.

HI Holo,

I agree that Rhino falls into a gray area in this regard,
but history cannot be equated with parimetrization .
if we talk about parimetrization, in addition to modifying the child objects based on the changes of the parents, we should also modify the various parameters which should always be stored and accessible.

example: I create a curve, I create an offset of 10
I modify the parent curve, the child offset is modified ok
but I can’t change the distance of Offset 11, 12 etc etc
I need to delete the first Offset and run the command again

as you said it is true that Rhino is closer to parimetrization via Grasshopper, but even in this case if I remember correctly (I hope I’m not wrong) in a discussion it was specified that even in GH it is not true parimetrization

1 Like

Hi @Holo,

Currently, I don’t believe so. Because history is command based, you might consider writing a plug-in, which isn’t all that difficult.

– Dale