nr.c4d.utils

Common utility functions related to the Cinema 4D API.

General Functions

nr.c4d.utils.serial_info()[source]

Retrieve the serial information for the current instance of Cinema 4D.

Returns:A tuple of (sinfo, is_multi). The sinfo is the dictionary returned by c4d.GeGetSerialInfo(). is_multi is True when it’s a multi license.
nr.c4d.utils.flush_console()[source]

Flush the Cinema 4D scripting console.

nr.c4d.utils.update_viewport()[source]

Shortcut for using c4d.DrawViews() to update the Cinema 4D viewport. Check the source code for the flags that are passed to the function.

Iterators

nr.c4d.utils.walk_hierarchy(node, yield_depth=False, _depth=0)[source]

Iterator for walking over the hierarchy of a c4d.BaseList2D node. node can also be a list, in which case all items of the list are walked. If yield_depth is True, a tuple with the second item being the index of the depth is yielded instead of only the nodes.

for obj in walk_hierarchy(doc.GetObjects()):
  print(obj.GetName())
Parameters:
  • node – A c4d.BaseList2D object or list of such.
  • yield_depth – If True, the generator yields tuples of (node, depth) instead of only the current node.
Returns:

A generator yielding the nodes of the hierarchy, or tuples of such.

nr.c4d.utils.walk_timeline(doc, start, end, update=True)[source]

Iterate over each frame in the document from start to end and yield the current frame number while redrawing the viewport if update is True. The document time will be reset to the original time at the end of the iteration.

for frame in iter_timeline(doc, 0, 100):
  pass  # process current frame here
Parameters:
  • doc – The c4d.BaseDocument to iterate in.
  • start – The start time, either c4d.BaseTime or a frame number.
  • end – The end time, either c4d.BaseTime or a frame number.
  • update – If True, the viewport is updated with update_viewport() and c4d.GeSyncMessage() before the current frame number is passed to the caller. This is usually desired.
nr.c4d.utils.walk_container(bc)[source]

Walk over all entries in the c4d.BaseContainer. Usually, you would do this with __iter__(), but it poses two issues:

  1. If a subcontainer is yielded, it is actually a copy of that container
  2. If a datatype in the container can not be represented in Python, it will raise an AttributeError

This function uses GetIndexId() to iterate over all entries. However, this in turn poses the restriction that containers with multiple entries for the same ID can not be handled properly and only the first value for that ID is yielded.

nr.c4d.utils.walk_shaders(node)[source]

Walk over the shader-list of a c4d.BaseList2D node. It is safe to remove shaders during iteration.

Document Helpers

nr.c4d.utils.remove_document(doc, new_active_doc=None)[source]

The Cinema 4D API only provides a KillDocument function that not only removes the specified c4d.BaseDocument from the document list, but really kills it, ie. it can not be used anymore aftert the function is called.

This function only removes the document from the Cinema 4D document list so that it is still valid and can be accessed from Python.

Parameters:
  • doc – The c4d.BaseDocument to remove.
  • new_active_doc – If specified, this will become the new active Cinema 4D document. Otherwise, the next document of doc will be used (C4D default behaviour) or a new empty document is created if none exists.

TemporaryDocument Objects

class nr.c4d.utils.TemporaryDocument[source]

The TemporaryDocument provides, as the name implies, a temporary c4d.documents.BaseDocument that can be used to perform operations in an isolated environment such as calling modeling commands or c4d.CallCommand().

When the TemporaryDocument is created, it is not immediately activated. To do so, one must call the attach() method or use it as a context-manager. When the document is no longer needed, the context-manager will close the document and remove it from the Cinema 4D document list or detach() must be called manually. The TemporaryDocument can be re-used after it has been closed.

Use the get() method to obtain the wrapped BaseDocument or catch the return value of the context-manager.

Note

If detach() was not called after attach() and the TemporaryDocument is being deleted via the garbage collector, a RuntimeWarning will be issued but the document will not be detached.

Important

The TemporaryDocument will not expect that the internal BaseDocument might actually be removed by any other mechanism but the detach() method.

attach()[source]

Attaches the temporary document to the Cinema 4D document list. It will also be promoted to be the active document. A call to detach() must be paired with attach().

The document that is active before this method is called will be saved and promoted back to being the active document with calling detach().

Returns self for method-chaining.

detach(do_recall=True)[source]

Detaches the temporary document from the Cinema 4D document list and promotes the previous active document back to its original status unless do_recall is False.

Returns self for method-chaining.

get()[source]

Returns the internal BaseDocument object.

is_attached()[source]

Returns True if this TemporaryDocument is attached, that is, inside the Cinema 4D document list, and False if it’s not.

UndoHandler Objects

class nr.c4d.utils.UndoHandler[source]

The UndoHandler is a useful class to temporarily apply changes to components of Cinema 4D objects, tags, materials, nodes, documents etc. and revert them at a specific point.

Internally, the UndoHandler simply stores a list of callables that are called upon revert(). All methods that store the original state of a node simply append a callable to it. Custom callables can be added with custom().

container(node)[source]

Grabs a copy of the nodes c4d.BaseContainer and restores it upon revert().

custom(target)[source]

Adds a custom callable object that is invoked when revert() is called. It must accept no arguments.

full(node)[source]

Gets a complete copy of node and restores its complete state upon revert(). This is like using c4d.UNDOTYPE_CHANGE with c4d.documents.BaseDocument.AddUndo() except that it does not include the hierarchical location. For that, you can use the location().

location(node)[source]

Tracks the hierarchical location of node and restores it upon revert(). This method only supports materials, tags and objects. This will also remove nodes that were not inserted any where before.

matrix(op)[source]

Restores ops current matrix upon revert().

revert()[source]

Reverts back to the original states that have been kept track of with this UndoHandler and flushes these states.

Object Helpers

nr.c4d.utils.duplicate_object(obj, n=None)[source]

Duplicate obj and return it. If n is not None, it must be a number. If a number is specified, this function creates n duplicates instead and returns a list of the duplicates.

This function uses the Cinema 4D “Duplicate” tool to create the copies of obj. In many cases, this is more desirable than using GetClone since the c4d.AliasTrans class is only available since R17.

Parameters:
  • obj – The c4d.BaseObject to clone.
  • n – None if a single clone should be created and returned, o a number in which case a list of n duplicates will be returned.
Returns:

A list of the cloned objects or a single object if n was None.

Raises:

RuntimeError – If obj is not inserted in a c4d.BaseDocument or if the objects could not be cloned.

nr.c4d.utils.move_axis(obj, new_axis)[source]

Simulate the “Axis Move” mode in Cinema 4D. This function moves the axis of a c4d.BaseObject to the specified new_axis in local space. Child objects will remain at their original position relative to global space. If obj is a c4d.PointObject, same applies for the object’s points.

import c4d
from nr.c4d.utils import move_axis

# Rotate the axis of an object by 45 Degrees around the X axis.
doc.AddUndo(c4d.UNDOTYPE_HIERARCHY_PSR, op)
mat = op.GetMl() * c4d.utils.MatrixRotX(c4d.utils.Rad(45))
move_axis(op, mat)
Parameters:

PolygonObjectInfo Objects

class nr.c4d.utils.PolygonObjectInfo(op, points=False, polygons=False, normals=False, midpoints=False, vertex_normals=False)[source]

This class stores the points and polygons of a c4d.PolygonObject and computes the normals and polygon middle points.

Parameters:
  • op – The c4d.PolygonObject to initialize the object for.
  • points – True if the object points should be stored.
  • polygons – True if the object polygons should be stored.
  • normals – True if the object normals should be computed.
  • midpoints – True if the polygon midpoints should be computed.
  • vertex_normals – True if the vertex normals should be computed (implies the normals parameter).
points

The points of the object.

polygons

The polygons of the object.

normals

The polygon normals, if enabled.

vertex_normals

The vertex normals, if enabled.

midpoints

The polygon midpoints, if enabled.

pointcount
polycount

Bitmap Helpers

nr.c4d.utils.load_bitmap(filename)[source]

Loads a c4d.bitmaps.BaseBitmap from the specified filename and returns it or None if the file could not be loaded.

Parameters:filenamestr – The file to load the image from.
Returns:c4d.BaseBitmap – The loaded bitmap or None.

Other

nr.c4d.utils.find_root(node)[source]

Finds the top-most object of the hierarchy of node and returns it. Note that this could very well be the node passed to this function.

Parameters:node – A c4d.BaseList2D object or an object that implements the hierarchy interface.
Returns:The node at the root of the hierarchy.