@Manuel said in Copy info from one Object to other Object:
This is a python bug; it works as expected when using c++.
I will open a bug report and we will try to fix the issue as soon as possible.
Still having this bug on 2024.4
@Manuel said in Copy info from one Object to other Object:
This is a python bug; it works as expected when using c++.
I will open a bug report and we will try to fix the issue as soon as possible.
Still having this bug on 2024.4
Hi @ops !
Take a look to my version of @ferdinands solution. I was made some fixes to the code. Hope you find it usefull.
find_close_point_on_spline.c4d
It would have been better if you have included line numbers in your stack trace, as without them I have to guess...
Error messages going not in traceback format
Here is a sample plugin with same issue.
odatafieldsexample.zip
Hello there!
After updating to Cinema 4D 2024.4 my plugin causes this Exception:
ReferenceError: the object 'c4d.modules.mograph.FieldLayer' is not alive
The above exception was the direct cause of the following exception:
SystemError: <function VTexterData.CheckDirty at 0x4b3546450> returned a result with an exception set
It happens after adding some fieldlayer to the Field List. What is problem it can be?
Here is my CheckDirty func:
def get_field_layers(op):
"""
Returns all field layers that are referenced in a field list.
Source: https://plugincafe.maxon.net/topic/11809/iterating-trough-field-list/2?_=1678357010902
"""
def flatten_tree(node):
""" Listifies a GeListNode tree. """
r = []
while node:
r.append(node)
for child in node.GetChildren():
r += flatten_tree(child)
mask = node.GetMaskHead()
if mask:
for child in mask.GetChildren():
r += flatten_tree(child)
node = node.GetNext()
return r
# get the GeListHead for the FieldList
root = op.GetLayersRoot()
if root is None:
return []
# Get the first node under the GeListHead
first = root.GetFirst()
if first is None:
return []
# traverse the graph
return flatten_tree(first)
def CheckDirty(self, op, doc):
fdirty = 0
desc = op.GetDescription(c4d.DESCFLAGS_DESC_NONE)
bc = desc.GetParameterI(c4d.VFTAG_TEXT_ANIMATOR_TRANSFORM, None)
if not bc:
return
fenabled = [t[c4d.VFTAG_TEXT_ANIMATOR_ENABLE] for t in op.GetTags() if t.CheckType(c4d.Tvfanimatortag)]
get_tvalue = lambda i: fenabled[i] if i < len(fenabled) else False #get correct value in case if tags count != axes count
tfields = [op[c4d.VFTAG_TEXT_ANIMATOR_FIELDS + i] for i in range(len(bc[c4d.DESC_CYCLE])) if get_tvalue(i)]
if not tfields:
return
for f in tfields:
if not f or not f.HasContent(): continue
fdirty += f.GetDirty(doc)
for l in get_field_layers(f):
if not l.IsAlive(): continue
if l.GetTypeName() in ('Time','Decay','Delay') and l.GetStrength() > 0.0:
fdirty += doc.GetTime().GetFrame(doc.GetFps())
continue
fdirty += l.GetDirty(c4d.DIRTYFLAGS_ALL)
lobject = l.GetLinkedObject(doc)
if lobject:
fdirty += lobject.GetDirty(c4d.DIRTYFLAGS_MATRIX | c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_DESCRIPTION)
fdirty += op.GetDirty(c4d.DIRTYFLAGS_MATRIX)
if fdirty != self.lastFieldsDirty:
self.lastFieldsDirty = fdirty
op.SetDirty(c4d.DIRTYFLAGS_DATA)
@Dunhou You must use text shaping library to get glyphs outlines and convert it to bezier curves.
Hello guys!
I using this nice appoach to convert eps text data to spline using AI (Adobe Illustrator) importer. But it seems there is some memory leak because the amount of memory increases every time. How it can be fixed?
Here is a test file. Thank you!
gen_eps2.c4d
@ferdinand Thank very much! i'll check what can i do.
Hello guys!
I need to connect an C lang written lib to make some calculation during getting spline object. Here is a raw example with some details in a comments. Important part: cache created inside lib object. It must be existing during livetime of the Object and free before removing. What is best way to implement this approach? Thx!
from ctypes import *
class MyPluginData(c4d.plugins.ObjectData):
"""SomeObject Generator"""
self.Init(node, isCloneInit):
# It must be called once on object creation and can't be rewritten
lib = CDLL('my_lib.so') #or dll on Windows
self.Free(node):
""" If your class has a destructor it is called as usual after this function. """
# It must be called on system sleep, app close, object deletion etc.
# to avoid memory leaks
lib.cleanup()
self.GetContour(op, doc, lod, bt):
""" Here we using lib by calling some lib.foo() and lib.bar()"""
# During the execution lib object creates some cache that must be cleaned up after object destruction
data = lib.foo()
# process data
return some_spline
I have a Adobe Illustrator file contents generated by code not saved in a disk. Now i need to import it into Cinema 4D as a document. Is it possible open in Cinema 4D data not from file but from memory?
Found some SDK examples here but have no idea how to save text data to c4d.storage.MemoryFileStruct correctly to open it with LoadDocument after that.
Here is my .ai file code example:
%!PS-Adobe-3.0
%%BoundingBox: 0 0 330 700
%%Pages: 1
%%EndComments
0 setgray
0 setlinecap
1 setlinewidth
0 setlinejoin
10 setmiterlimit
[] 0 setdash
%%EndProlog
%%Page: 1 1
newpath
81 387 m
80 384 80 382 81 381 c
82 379 84 379 88 379 c
151 379 l
154 379 156 379 157 381 c
158 382 158 384 158 387 c
151 635 l
151 637 150 639 149 640 c
148 641 146 642 144 642 c
95 642 l
92 642 90 641 89 640 c
88 639 88 637 88 635 c
81 387 l
177 0 m
171 0 169 2 169 7 c
161 314 l
160 318 157 321 153 321 c
86 321 l
81 321 79 318 79 314 c
70 7 l
70 2 67 0 62 0 c
17 0 l
14 0 12 0 11 2 c
10 3 10 5 10 8 c
27 615 l
27 645 34 666 48 680 c
62 693 84 700 114 700 c
125 700 l
155 700 176 693 190 680 c
204 666 211 645 212 615 c
229 8 l
229 5 228 3 227 2 c
226 0 224 0 222 0 c
177 0 l
closepath
stroke
%%Trailer
Thx!
Hello guys!
Here is my old versions Python Node code that was working perfectly before v2024:
import c4d
def main():
global Color,Alpha,AlphaGradient
Color = Alpha = c4d.Vector()
AlphaGradient = Gradient.GetAlphaGradient()
irs = c4d.modules.render.InitRenderStruct()
if Gradient.InitRender(irs):
Color = Gradient.CalcGradientPixel(Position)
Gradient.FreeRender()
if AlphaGradient and AlphaGradient.InitRender(irs):
Alpha = AlphaGradient.CalcGradientPixel(Position)
AlphaGradient.FreeRender()
Now following a new API changes this code:
import c4d
def main():
global Color,Alpha,AlphaGradient
Color = Alpha = c4d.Vector()
AlphaGradient = Gradient.GetAlphaGradient()
irs = c4d.modules.render.InitRenderStruct()
if Gradient:
Color = Gradient.PrepareRenderData(irs).CalcGradientPixel(Position)
if AlphaGradient:
Alpha = AlphaGradient.PrepareRenderDataWithAlpha(irs).CalcGradientPixel(Position)
Traceback (most recent call last):
File "Gradient", line 14, in main
Exception: no converter found for 'net.maxon.interface.gradientrenderdata-C'
How it works a new Gradient now?
@baca Thank you! Works like a charm!
Hello!
In R2024 for NodeData plugins Init method now requires isCloneInit argument. But now, after code changing, older versions gives an error:
TypeError: Init() takes exactly 3 arguments (2 given)
Is there a way to make this new code feature compatible with older Cinema 4D versions? Now I have to create two pypv files: up_to_2024.pypv and 2024_and_after.pypv. Which is not convinient for developement obviously.
Thank you!
Trying to test in R2024 this SDK example from Github gets error:
Traceback (most recent call last):
File "scriptmanager", line 60, in <module>
File "scriptmanager", line 46, in main
TypeError: argument 1 must be c4d.Vector4d, not ColorA64
Seems that datatype was changed but with no log in changelist and colorchooser API documentation.
Hello guys!
I’m working on a plugin which there may be exceptions and there is a need to notify the user. As I understand from this information, gui message windows cannot be shown because of threading issues. But you can use Messages. As shown here and here. So the question is: how do I make this correct when using the GetContour or GVO method with ObjectData plugin? There is a proper way to "trigger Messages method" inside the GVO? I now is it possible to use c4d.MSG_DESCRIPTION_POSTSETPARAMETER but in this case exceptions may occurs in different scenarios that not depends from plugin GUI.
Thank you!
def GetContour(self, node, doc, lod, bt):
# Checks if there is an active object
if node is None:
raise RuntimeError("node is None, should never happens, that means there is no generator.")
try:
spline = self.GenerateSpline(node, doc)
except Exception as e:
# Disable generator flag
node[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False
# Wrong way to show message ????
c4d.gui.MessageDialog(str(e))
# Return empty spline
return c4d.BaseObject(c4d.Ospline)
return spline
@ferdinand Thank for your response!
I finally decided to simple check fieldlist without editing it. I hope this is legal.
def CheckFieldListHasContent(doc, fieldlist):
if not fieldlist.HasContent():
return False
for f in get_field_layers(fieldlist):
if f.CheckType(c4d.FLfield) and not f.GetLinkedObject(doc):
f.Remove()
return fieldlist.HasContent()
Re: Fieldlist HasContent() GetCount() bug workaround
Hello guys!
I think i've found the solution how to fix FieldsLists with "ghost" layers (without linked FieldObjects, deleted in OM). I want to apply it to fix my ObjectPlugin FieldLists but i do not know how to make it securely. Maybe after each object deletion in Cinema 4D scene? How to implement this? There better solution?
Here is a code that works for me:
def get_field_layers(op):
"""
Returns all field layers that are referenced in a field list.
Source: https://developers.maxon.net/forum/topic/11809/iterating-trough-field-list/2?_=1678357010902
"""
def flatten_tree(node):
""" Listifies a GeListNode tree. """
r = []
while node:
r.append(node)
for child in node.GetChildren():
r += flatten_tree(child)
node = node.GetNext()
return r
# get the GeListHead for the FieldList
root = op.GetLayersRoot()
if root is None:
return []
# Get the first node under the GeListHead
first = root.GetFirst()
if first is None:
return []
# traverse the graph
return flatten_tree(first)
def CleanUpFieldListDeadLayers(doc, fieldlist):
for f in get_field_layers(fieldlist):
if f.CheckType(c4d.FLfield) and not f.GetLinkedObject(doc):
f.Remove()
return fieldlist
def main():
fixed_fieldlist = CleanUpFieldListDeadLayers(doc,op[c4d.MYPLUGIN_FIELDLIST])
op[c4d.MYPLUGIN_FIELDLIST] = fixed_fieldlist
if __name__ == '__main__':
main()
@ferdinand Thank you! That was TranslateDescID issue!
I found out strange behavior in my plugin with a Fieldlist UI.
Thank you @ferdinand!
Will try to found out the workaround.