Hi @baca,
your solution does not work because you are not reaching deep enough into the cache of the object. You have to actually grab the LineObject
data. In case of generators like a Cloner
that will be a more complex structure. The complexity of Cinema 4D's caches has been discussed recently here.
There is also the basedocument_read_animated_mesh.py github example which covers the topic of cache evaluation. Below you will find a version of your file which makes use of a part of that example to do what you want to do. But there are other hurdles to overcome, for details see attached file.
Cheers,
Ferdinand
the file: py-dynamics-cache.c4d
the code:
"""Example for retrieving the simulation caches of generators.
As discussed in:
https://plugincafe.maxon.net/topic/13159
Related Python SDK examples:
basedocument_read_animated_mesh_r16.py
"""
import c4d
def CacheIterator(op, types=None):
"""An iterator for the elements of a BaseObject cache.
Handles both "normal" and deformed caches and has the capability to
filter by node type.
Args:
op (c4d.BaseObject): The node to walk the cache for.
types (Union[list, tuple, None], optional): A collection of type IDs
from one of which a yielded node has to be derived from. Will yield
all node types if None. Defaults to None.
Yields:
c4d.BaseObject: A cache element of op.
Raises:
TypeError: On argument type violations.
"""
if not isinstance(op, c4d.BaseObject):
msg = "Expected a BaseObject or derived class, got: {0}"
raise TypeError(msg.format(op.__class__.__name__))
if not isinstance(types, (tuple, list, type(None))):
msg = "Expected a tuple, list or None, got: {0}"
raise TypeError(msg.format(types.__class__.__name__))
# Try to retrieve the deformed cache of the object
temp = op.GetDeformCache()
if temp is not None:
# If there is a deformed cache we iterate over him, a deformed cache
# can also contain deformed cache e.g. in case of a nested deformer.
for obj in CacheIterator(temp, types):
yield obj
# Try to retrieve the cache of the Object
temp = op.GetCache()
if temp is not None:
# If there is a cache iterates over its, a cache can also contain
# deformed cache e.g. an instance, have a cache of its linked object
# but if this object is deformed, then you have a deformed cache as
# well.
for obj in CacheIterator(temp, types):
yield obj
# If op is not a generator / modifier
if not op.GetBit(c4d.BIT_CONTROLOBJECT):
# Yield op if it is derived from one of the passed type symbols.
if types is None or any([op.IsInstanceOf(t) for t in types]):
yield op
# Then finally iterates over the child of the current object to retrieve
# all objects e.g. in a cloner set to Instance mode, all clones is a new
# object.
temp = op.GetDown()
while temp:
for obj in CacheIterator(temp, types):
yield obj
temp = temp.GetNext()
def main():
"""Entry point.
"""
# Get your user data.
source = op[c4d.ID_USERDATA, 1]
if source is None:
return
# A null to parent all the deformed splines to.
null = c4d.BaseList2D(c4d.Onull)
# Iterate over the cache of the object to get all the line objects
# contained in the cache.
for line in CacheIterator(source, types=[c4d.Oline]):
# We should really not return cloned LineObjects, as this was just a
# simplification I made, but instead create new splines for them.
# Compute the local transform for the new object.
ml = ~source.GetMg() * line.GetMg()
# Get all the points from the line object.
points = line.GetAllPoints()
# Create a new linear spline, copy all point data over and attach it
# to the null.
spline = c4d.SplineObject(pcnt=len(points),
type=c4d.SPLINETYPE_LINEAR)
spline.SetAllPoints(points)
if op[c4d.ID_USERDATA, 2]:
spline = line.GetClone(0)
spline.InsertUnder(null)
spline.SetMl(ml)
# This solution does not handle properly LineObject instances with
# multiple segments. This also affects the ability to evaluate if
# the original spline was a closed spline. Both information can be
# found in the Tsegment tag hosted by the cache generating
# SplineObject. For that you would have modify the CacheIterator
# function to also return the cache generator node for each
# LineObject cache.
#
# Or when you are sure that you only have 1-segmented splines and
# want them to be always open/closed, you can of course also just
# hard code your desired result.
return null