Spline User Data Presets
-
Hello forum,
In my User Data, I have a customized shape as my Spline DataType. I want to keep this custom shape and be able to rebuild as a preset in my plugin. It would function like the 'Save Preset...' and 'Load Preset...' buttons.
There must be a way to save all the points and tangents in the spline DataType to rebuild the it with python? How would I do this?
Thank You for any thoughts.
-
Hi,
I have recently shown here how to react to user data button clicks in a scripting tag. You could (de-)serialize your
c4d.SplineData
with the buildin Python modulejson
(link). Also thec4d.SplineData
type already does 50% of the work for you asGetKnots()
returns a dictionary which you could serialize directly viajson.dumps()
.Cheers
zipit -
Ah, GetKnots() has the data that I need. Thank you for that.
I also see I SetKnot() is read only. The only way to get around that is sending the GetKey data to json then back again?
There must be a simpler way of using GetKnots() data and pasting on to a new Spline DataType. -
or can I place the GetKnots() data into my .res file? That would work for my plugin too.
-
Hi,
I am sorry, I did overlook that you were writing a plugin, because I answered a few scripting questions before and you were talking about user data.
A few assumptions:
- I assume you are writing as description resource based plugin data type like or
ObjectData
orTagData
and not a dialog resource based type likeCommandData
orTooldata
. - I am still not quite clear on what you want to do, but i assume you want to be able to store N amount of spline presets for your plugin, right?
A few answers:
- If you only want to store exactly one preset and do use a description resource, you could actually just let the user use the build in feature "save as default" of the attribute manger.
- No, you can not define any storage logic in a
res
file. They are purely meant to define the interface layer of your plugin. Anything data/logic layer related goes into your code. - You could either store your plugin settings globally in the
WorldContainer
. Check outc4d.SetWorldContainer()
andc4d.GetWorldContainer()
for that. - Or you could store the settings locally (per document) via
BaseDocument.GetDocumentData()
andBaseDocument.SetDocumentData()
. - In both cases (3. and 4.) you need to register a plugin ID under which you can store your settings.
- Serializing the data yourself could still be advantageous depending on what you are trying to do.
Cheers
zipit - I assume you are writing as description resource based plugin data type like or
-
Thank You for the thorough reply.
Yes, I am writing a python tag and running it through Prototype Converter. The goal is to create a plugin tag that adds custom animation curves to the transforms of objects such as cubes and circles etc.
I haven't looked into it yet but WorldContainer looks like its getting me there. I am assuming there is an easy way to save all of the carefully preset UserData (GUISplines) that I have created and keep it in the plugin for a new animator to use out of the box.(Sorry, I'm learning a lot all at once here coming from C# in Unity3D. )
-
Hello,
thanks again for @zipit and the answer.I would like to add a couple of words.
The best way should be to store them in the Content Browser, but it's not available in Python, only C++
So that depend if you want your setting to be available only for the document (use Document BaseContainer). For setting that are available independently from the document, you can use the WorldContainer (even if it's to store "preferences" and not librairies)
you can also retrieves each knots (SplineData.GetKnots()) and save them to an Hyperfile (@zipit talked about json but hyperfile are also a good way)
Of course, If you want just one default "starting" state you can do that in your Init() function
Don't forget that with cinema4D, users can also use "Set to default" or save Tags presets. And as you said, they can also use the regular load preset and save preset
And you can also share content librairies.
also about how to use the forum :
For your next threads, please help us keeping things organised and clean. I know it's not your priority but it really simplify our work here.
- Q&A New Functionality.
- How to Post Questions especially the tagging part.
I've added the tags and marked this thread as a question so when you considered it as solved, please change the state :
Cheers,
Manuel -
Thank You @zipit and @m_magalhaes,
You have given me some great leads to solve my problem. It's pretty clear I am in over my head. More code samples in the API would really help a beginner like me. I have done a lot of searching around Hyperfiles and BaseContainers but not finding a solution, mostly due to my lack of familiarity of the sdk.
This is the last problem I need to solve in order to use my Tag Plugin.
Here is another take:
I can easily save the splinedata to a file and load it into a blank splineGui like a charm. Can I somehow keep that file in my plugin directory and load it onto the specific user data on initialization of the plugin?Thanks again.
-
Hello,
About the examples, with the release of R21 there will be a bit more examples. You can still have a look at the c++ examples, you will have some class name and function that can be translate to python.you can't because there's a dialogbox opened by this command. You can't avoid it.
About the hyperfile you have an example on the hyperfile documentation page
I did write an quick example with splinedata, you can simply use ReadData/WriteData
I didn't add comment, you just pick the data and write it. (of course you don't need the LoadDialog)def Read(): path = st.LoadDialog(type=c4d.FILESELECTTYPE_ANYTHING, title="Please Select the file") hf = st.HyperFile() #spdata = op[c4d.ID_USERDATA,1] spdata = None if hf.Open(ident=0, filename=path, mode=c4d.FILEOPEN_READ, error_dialog=c4d.FILEDIALOG_NONE): spdata = hf.ReadData() else: raise ValueError("can't open file") op[c4d.ID_USERDATA,1] = spdata c4d.EventAdd() def Write(): path = st.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING, title="Please Select the file") hf = st.HyperFile() spdata = op[c4d.ID_USERDATA,1] if hf.Open(ident=0, filename=path, mode=c4d.FILEOPEN_WRITE, error_dialog=c4d.FILEDIALOG_NONE): writeDone = hf.WriteData(spdata) else: raise ValueError("error loading the file")
I did try to open directly the file saved with the command but the result is not totally an hyperfile.
Cheers,
Manuel -
Hello again,
After digging a bit you can add a key parameter on your
Open
function. And write the Version of cinema4D retrieved withGetC4DVersion
That way, you can read/write hyperfile to save your SplineData with script and/or using the load/save menu (when right clicking on the parameter)Of course on that example the selected object (op) have a UserData (id 1) that is a spline type.
import c4d from c4d import gui from c4d import storage as st, gui # Welcome to the world of Python def Read(path): hf = st.HyperFile() spdata = None if hf.Open(ident=1885434477, filename=path, mode=c4d.FILEOPEN_READ, error_dialog=c4d.FILEDIALOG_NONE): c4dVersion = hf.ReadInt32() spdata = hf.ReadData() else: raise ValueError("can't open file") op[c4d.ID_USERDATA,1] = spdata def Write(path): hf = st.HyperFile() spdata = op[c4d.ID_USERDATA,1] if hf.Open(ident=1885434477, filename=path, mode=c4d.FILEOPEN_WRITE, error_dialog=c4d.FILEDIALOG_NONE): hf.WriteInt32(c4d.GetC4DVersion()) writeDone = hf.WriteData(spdata) else: raise ValueError("error openging the file") # Execute main() if __name__=='__main__': path = st.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING, title="Please Select the file") Write(path) spdata = op[c4d.ID_USERDATA,1] spdata.DeleteAllPoints() op[c4d.ID_USERDATA,1] = spdata Read(path) c4d.EventAdd()
Cheers
Manuel -
Thank You @m_magalhaes very helpful! I succeeded. I should have been able to figure this out from the example in the API.
I've used the code basically as you have it with my spline datas saved in different hyperfiles. I then load that data from my tag.Thanks again.