Welcome to the c4dtools documentation!

c4dtools - A utility library for the Cinema 4D Python API

The c4dtools module is a thin Python library created by Niklas Rosenstein. It provides functions and classes for the everyday work with Python in Cinema 4D. The most significant feature is the cached parsing of dialog symbols, see c4dtools.prepare().

c4dtools.prepare(filename, c4dres, cache_symbols=True, libfolder_name='lib', resfolder_name='res', parse_descriptions=False)[source]

Call this function from a Cinema 4D python plugin-file (*.pyp) to set up convenient data that can be used from the plugin.

import c4d
import c4dtools

res, imp = c4dtools.prepare(__file__, __res__)

# ...
Parameters :
  • filename: Just pass the __file__ variable from the plugins global scope.
  • c4dres: The c4d.plugins.GeResource instance from the plugin’s scope.
  • cache_symbols: True by default. Defines wether the resource symbols will be cached.
  • libfolder_name: The name of the folder the plugin related libraries are stored. The returned Importer instance will be able to load python modules and packages from this directory.
  • resfolder_name: The name of the plugins resource folder. This usually does not need to be changed as the name of this folder is defined by Cinema 4D.
  • parse_descriptions: False by default. When True, description resource symbols will parsed additionally to the dialog resource symbols. Note that strings can not be loaded from symbols of description resources.
Returns:

A tuple of two elements.

  1. c4dtools.resource.Resource instance.
  2. c4dtools.utils.Importer instance.

c4dtools.utils

class c4dtools.utils.AtomDict[source]

New in 1.2.6.

This class implements a subset of the dictionary interface but without the requirement of the __hash__() method to be implemented. It is using comparing objects directly with the == operator instead.

class c4dtools.utils.FileChangedChecker(filename)[source]

This class keeps track of a file on the local filesystem and tell you if the specific file has changed since the last time the FileChangedChecker was asked this question.

It can run in two modes: pushing or pulling. With pulling, we mean to request the information whether the file has changed or not. With pushing, we mean to get notified when the file has changed. Pushing comes in connection with threading. Only one thread can be run from on FileChangedChecker instance.

Example for pulling:

f = FileChangedChecker(my_filename)
# ...
if f.has_changed():
    print ("File %s has changed since `f` has been created." %
           f.filename)

Example for pushing:

f = FileChangedChecker(my_filename)
def worker(f):
    print ("File %s has changed since `f` has been created." %
           f.filename)
f.run_in_background(worker)
class Worker(checker, callback, period)[source]

This is the worker class instantiated by the FileChangedChecker to run in the background.

FileChangedChecker.has_changed()[source]

This method returns True when file pointed to by the stored filename has changed since the last time the FileChangedChecker was asked for.

Note: When the file has not changed since the initialization
of the FileChangedChecker instance, this method will return False (i.e. the first call to this function will tell you the file has not changed).
FileChangedChecker.run_in_background(callback, period=0.5)[source]

Start a new thread invoking the callable callback passing the FileChangedChecker instance when the file it points to has changed. period defines the time in seconds that passes until the next time the thread checks for the change.

Raises: RuntimeError when a thread is still running for this
instance.
FileChangedChecker.stop_background(join=False)[source]

Stops the background operation started with run_in_background(). When join evaluates to True, this method will wait until the thread has stopped working before terminating.

Raises: RuntimeError when no thread has been started yet.

FileChangedChecker.worker_ended(worker)[source]

Not public. This method is called by a FileChangedChecker.Worker instance to dispose the worker from the list of not yet disposed workers.

Raises: RuntimeError if worker is not in the list of not yet
disposed workers. TypeError if worker is not an instance of FileChangedChecker.Worker.
class c4dtools.utils.Filename(filename)[source]

A wrapper class for the os.path module.

iglob(*glob_exts)[source]

Returns a generator yielding all filenames that were found by globbing the filename joined with the passed *glob_exts.

suffix(new_suffix=None)[source]

Called with no arguments, this method returns the suffix of the filename. When passing a string, the suffix will be exchanged to the passed suffix.

Raises: TypeError when new_suffix is not None and not a string.

class c4dtools.utils.Importer(high_priority=False, use_sys_path=True)[source]

Use this class to enable importing modules from specific directories independent from sys.path.

high_priority

When this value is True, the paths defined in the importer are prepended to the original paths in sys.path. If False, they will be appended. Does only have an effect when use_sys_path is True.

use_sys_path

When this value is True, the original paths from sys.path are used additionally to the paths defined in the imported.

add(*paths)[source]

Add the passed strings to the search-path for importing modules. Raises TypeError if non-string object was passed. Passed paths are automatically expanded.

import_(name)[source]

Import the module with the given name from the directories added to the Importer. The loaded module will not be inserted into sys.modules.

is_local(module)[source]

Returns True if the passed module object can be found in the paths defined in the importer, False if not.

class c4dtools.utils.PolygonObjectInfo[source]

New in 1.2.5.

This class stores the points and polygons of a polygon-object and additionally computes it’s normals and polygon-midpoints.

init(op)[source]

Initialize the instance. op must be a c4d.PolygonObject instance.

class c4dtools.utils.Watch[source]

Utility class for measuring execution-time of code-blocks implementing the with-interface.

>>> with Watch() as w:
...     time_intensive_code()
...
>>> w.delta
4.32521002
delta[source]

Returns the difference between the time Watch.start() has been and Watch.stop() has been called. If Watch.stop() has not yet been invoked, the current time is used.

Raises: RuntimeError when Watch.start() has not been called
before.
reset()[source]

Reset the information and return the Watch into a state where time measuring has not been started yet.

start()[source]

Start the time measuring.

started[source]

Returns True when the Watch has been started.

stop()[source]

Stop the time measuring.

Raises :RuntimeError when Watch.start() was not called before.
stopped[source]

Returns True when the Watch has been stopped.

c4dtools.utils.assert_type(x, *types, **kwargs)

New in 1.2.5.

This function is similar to the built-in isinstance() function in Python. It accepts an instance of a class as first argument, namely x, and checks if it is an instance of one of the passed types. The types must not be encapsulated in a tuple (which is in contrast to the isinstance() method).

This function raises a TypeError exception with a proper error message when x is not an instance of the passed *types.

Changed in 1.2.8: Renamed from assert_type to ensure_type. Added **kwargs parameter. Pass name as keyword-argument for adding the parameter name that was wrong in the message.

c4dtools.utils.bl_iterator(obj, safe=False)[source]

New in 1.2.8. Yields the passed object and all following objects in the hierarchy (retrieved via GetNext()). When the safe parameter is True, the next object will be retrieved before yielding to allow the yielded object to be moved in the hierarchy and iteration continues as if the object was not moved in hierarchy.

c4dtools.utils.candidates(value, obj, callback=<function <lambda> at 0x03AE0670>)[source]

Searches for value in obj and returns a list of all keys where the callback returns True, being passed value as first argument, the value to compare it with as the second argument and the name of the attribute as the third.

Returns: list of str

c4dtools.utils.change_suffix(filename, new_suffix)[source]

Replaces the suffix of the passed filename with new_suffix.

c4dtools.utils.clsname(obj)[source]

Return the name of the class of the passed object. This is a shortcut for obj.__class__.__name__.

c4dtools.utils.current_state_to_object(op, container=<c4d.BaseContainer instance at 0x03B8A0D0>)[source]

Makes the passed c4d.BaseObject instance an editable object by applieng a modeling command on it. The returned object’s hierarchy will consist of Null-Objects and editable objects only.

container is an argument assigned a new c4d.BaseContainer to optimize speed and memory usage, but you can pass your own c4d.BaseContainer in case you want to pass any additional information to the c4d.utils.SendModelingCommand function.

Example code for the Script Manager:

import c4dtools

def main():
    obj = c4dtools.utils.current_state_to_object(op)
    doc.InsertObject(obj)
    c4d.EventAdd()

main()

Raises: TypeError if op is not a c4d.BaseObject instance. Returns: c4d.BaseObject

c4dtools.utils.ensure_type(x, *types, **kwargs)[source]

New in 1.2.5.

This function is similar to the built-in isinstance() function in Python. It accepts an instance of a class as first argument, namely x, and checks if it is an instance of one of the passed types. The types must not be encapsulated in a tuple (which is in contrast to the isinstance() method).

This function raises a TypeError exception with a proper error message when x is not an instance of the passed *types.

Changed in 1.2.8: Renamed from assert_type to ensure_type. Added **kwargs parameter. Pass name as keyword-argument for adding the parameter name that was wrong in the message.

c4dtools.utils.ensure_value(x, *values, **kwargs)[source]

New in 1.2.8.

This function checks if the value x is in *values. If this does not result in True, ValueError is raised.

Pass name as keyword-argument to specify the parameter name that was given wrong in the message.

c4dtools.utils.file_changed(original, copy)[source]

Returns True when the filename pointed by original was modified before the last time copy was modified, False otherwise.

c4dtools.utils.flush_console(id=13957)[source]

Flushes the Cinema 4D console.

c4dtools.utils.func_attr(**attrs)[source]

New in 1.2.6.

This decorator must be called, passing attributes to be stored in the decorated function.

c4dtools.utils.get_material_objects(doc)[source]

New in 1.2.6.

This function goes through the complete object hierarchy of the passed c4d.BaseDocument and all materials with the objects that carry a texture-tag with that material. The returnvalue is an AtomDict instance. The keys of the dictionary-like object are the materials in the document, their associated values are lists of c4d.BaseObject. Note that an object can occure twice in the same list when the object has two tags with the same material on it.

Parameters:docc4d.BaseDocument
Returns:AtomDict
c4dtools.utils.get_root_module(modname, suffixes=['pyc', 'pyo', 'py'])[source]

New in 1.2.6.

Returns the root-file or folder of a module filename. The return-value is a tuple of (root_path, is_file).

c4dtools.utils.get_shader_bitmap(shader, irs=None)[source]

A bitmap can be retrieved from a c4d.BaseShader instance of type Xbitmap using its GetBitmap() method. This method must however be wrapped in calls to InitRender() and FreeRender().

This function initializes rendering of the passed shader, retrieves the bitmap and frees it.

Return :c4d.BaseBitmap or None.
c4dtools.utils.iter_container(container, callback=None, level=0)[source]

Iterate over the passed container being a c4d.BaseContainer instance recursively. The callback will be called for each key-value pair. The default callback will print out the values in the container.

The callback is passed the containers key, value and stack-level.

Returns :None
Raises :TypeError when callback is not callable.
c4dtools.utils.join_polygon_objects(objects, dest_mat=None)[source]

New in 1.2.8. This function creates one polygon object from the passed list objects containing c4d.PolygonObject instances. Any other type of object is ignored.

The returned polygon-object is located at the global world center.

# TODO: Add description for parameters.

c4dtools.utils.serial_info()[source]

New in 1.2.7.

Returns serial-information of the user. Returns (sinfo, is_multi). is_multi indicates whether the sinfo is a multilicense information or not.

c4dtools.utils.update_editor()[source]

A shortcut for

c4d.DrawViews(
        c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD |
        c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK)

Can be used to update the editor, useful for going through the frames of a document and doing backing or similar stuff.

Returns :The return-value of c4d.DrawViews().
c4dtools.utils.vbbmid(vectors)[source]

Returns the mid-point of the bounding box spanned by the list of vectors. This is different to the arithmetic middle of the points.

Returns: c4d.Vector

c4dtools.utils.vmax(dest, test)[source]

For each component of the vectors dest and test, this function writes the upper value of each pairs into the respective component of dest.

c4dtools.utils.vmin(dest, test)[source]

For each component of the vectors dest and test, this function writes the lower value of each pairs into the respective component of dest.

c4dtools.helpers

This module defines content that has a rather generic purpose, unlike the contents of the c4dtools.utils module.

class c4dtools.helpers.Attributor(dict_=None)[source]

Instances of this class will allow setting and getting any value from the dictionary passed on construction. The dictionary is stored in the dict_ slot of the instance.

c4dtools.plugins

class c4dtools.plugins.Command[source]

This class is wrapping the CommandData class to make the registration of plugins of this kind easier. Subclasses are automatically registered on c4dtools.plugins.main() unless autoregister evaluates to False.

An instance of a subclass of this class must provide the following attributes to be successfully registered:

  • PLUGIN_ID
  • PLUGIN_NAME
  • PLUGIN_HELP
  • PLUGIN_INFO [optional]
  • PLUGIN_ICON [optional]
register()[source]

This method registers the plugin to Cinema 4D by using the data set in the instances attributes. See the class-documentation for more information.

c4dtools.plugins.gather_subclasses(clazz)[source]

Returns a list of all subclasses that require to be registered.

c4dtools.plugins.main()[source]

Gathers all subclasses of the plugin classes in this module and registers them to Cinema 4D unless autoregister evaluates to False.

c4dtools.library

This module implements functionality for making it possible for plugins to interface with each other, i.e. one plugin may depend on the functionality of another plugin (even developed from different developers).

A Python plugin may create a Library class that will be (automatically) registered to the c4dtools.library mmodule. This library can then be loaded from another plugin to establish a Python-level communication between these plugins. As the plugin initialization order can not be controlled from Python, and there may also exist a circular reference to libraries of two or more plugins, references to libraries are always lazy and loaded on-request.

Example library:

import c4dtools

class MyLibrary(c4dtools.library.Library):

    class Meta:
        # Here comes meta information.
        pass

    def on_create(self):
        print "MyLibrary has been created."

    def on_install(self, name):
        print "MyLibrary has been installed under the name %s." % name

    def get_stuff(self):
        return "This is from MyLibrary!"

Nothing more needs to be done. The library is automatically registered with the name 'MyLibrary'. The name the library is registered with can be changed by defining name=’libname’ in the Meta section. When registration should be prevented, one needs to define abstract=True in the Meta section.

This library can now be loaded from another Python unit.

import c4dtools
MyLibrary = c4dtools.load_library('MyLibrary')
print MyLibrary.get_stuff()
class c4dtools.library.LazyLibrary(libname)[source]

This class is representing a lazy reference to a library. The actual library will be loaded on the first request.

class c4dtools.library.Library[source]

This is the base class for library objects. It’s metaclass LibraryMeta will automatically turn methods into classmethods and will disallow the instantiaton of the class.

class c4dtools.library.LibraryMeta[source]

This is the meta-class of the Library class. It implements automatically registering the Library when the class is created, except it is marked as abstract.

One can mark a Library as abstract when defining a meta-object on class-level that contains an attribute abstract that evaluates to True. A library must be marked abstract explicitly. An abstract library will not be registered.

Example:

class MyLibrary(Library):
    class Meta:
        abstract = True
    # ...
classmethod get_library(name)[source]

Finds and returns an installed library with the passed name.

Raises: LibraryNotFound when there is not library with this
name installed.
on_create()[source]

This class method is called when the library class instance was created.

on_install(name)[source]

This class method is called when the library is installed. This method will not be called when the library is marked as abstract.

exception c4dtools.library.LibraryNotFound[source]

This exception is thrown when a requested library was not found.

c4dtools.library.load_library(name, lazy=False)[source]

Load a library. Returns a Library instance unless lazy does not evaluate to True. If lazy is True, a LazyLibrary instance will be returned.

c4dtools.resource

class c4dtools.resource.Resource(dirname, c4dres, symbols={})[source]

An instance of this class is used to store the symbols of a C4D symbols file and several other information to work with the resource of a plugin, such as easily grabbing files from that folder, etc.

dirname

The directory name of the resource-folder. Not garuanteed to exist!

c4dres

The c4d.plugins.GeResource object passed on construction. This is usually the __res__ variable passed through from a Python plugin.

string

A StringLoader instance associated with the resource object. Used to load resource strings.

# Load a resource-string with the IDC_MYSTRING symbol-name
# without formatting arguments.
res.string.IDC_MYSTRING()

# Or call the str() function on the returned ResourceString
# instance.
str(res.string.IDC_MYSTRING)

# Format the resource string by replacing the hashes in
# the string with the passed arguments.
res.string.IDC_FILENOTFOUND(filename)

# Unpack the tuple returned by the `both` property.
# Shortcut for:
#   container.SetString(
#       res.IDC_CONTEXTMENU_1,
#       res.string.IDC_CONTEXTMENU_1())
container.SetString(*res.string.IDC_CONTEXTMENU_1.both)
changed

This attribute is set by the load() function and is only True when the resource was cached and has changed, therefore the cache was rebuilt. When symbol-caching is deactivated, this attribute will always be False.

add_symbols(symbols)[source]

Add the dictionary symbols to the resources symbols.

Raises: TypeError if symbols is not a dict instance.
KeyError if a key in symbols is already defined in the resource and their value differs.
file(*path_parts)[source]

Concatenate the resource folders path with the passed filename.

get(name)[source]

Returns the value of the symbol with the passed name, or raises KeyError if no symbol was found.

get_symbol_name(id_)[source]

Returns the name of the passed symbol id.

class c4dtools.resource.ResourceString(id, c4dres)[source]

This class represents a resource-string loaded from plugin resource.

both[source]

Returns a tuple of the (id, string) where string is loaded from the plugin’s resource.

class c4dtools.resource.StringLoader(resource)[source]

This class is used for conveniently loading strings from the c4d_strings.str file. It is basically a wrapper for the c4d.plugin.GeLoadString function. Accessing an attribute on an instance of this class will return a callable object accepting the same parameters as the previously mentioned API call, but with the symbol-id already passed.

c4dtools.resource.load(filename, use_cache=True, cache_suffix='cache')[source]

Load the symbols of a Cinema 4D resource file. The symbols will be loaded directly from the symbols file when use_cache is False. In the other case, the symbols are loaded from the cached symbols if the symbols haven’t changed since the cache has been generated. If the cache is not available, it will be generated when use_cache is True.

The advantage of caching the symbols in a seperate file is the improved speed of reading in the symbols.

Returns :(symbols_dict, changed)
Raises :OSError if filename does not exist or does not point to a file.
c4dtools.resource.parse_symbols(string)[source]

Parse symbols from the passed string containing the enumerations to load.

c4dtools.resource.menuparser

New in 1.2.0.

This module implements parsing a Menu-resources and rendering them to a dialog. The following is an example resource file:

# Write comments like in Python.
MENU MENU_FILE {
    MENU_FILE_OPEN;
    MENU_FILE_SAVE;
    --------------;         # Adds a separator.
    COMMAND COMMAND_ID;     # Uses GeDialog.MenuAddCommand().
    COMMAND 5159;           # Same here.

    # Create a sub-menu.
    MENU_FILE_RECENTS {
        # Will be filled programatically.
    }
}
# More menus may follow ...

The symbols in the menu resource must be defined in the plugin resource created by c4dtools.prepare(). You can also pass your own c4dtools.resource.Resource instance.

This is how to read the menu resource:

res, imp = c4dtools.prepare(__file__, __res__)

class MyDialog(c4d.gui.GeDialog):

    MENU_FILE = res.file('menu', 'my_menu.menu')
    RECENTS_START = 1000000

    def CreateLayout(self):
        menu = c4dtools.resource.menuparser.parse_file(self.MENU_FILE)
        recents = menu.find_node(res.MENU_FILE_RECENTS)

        item_id = self.RECENTS_START
        for fn in get_recent_files(): # arbitrary function
            node = c4dtools.resource.menuparser.MenuItem(item_id, str(fn))
            recents.add(node)

        # Render the menu on the dialog, passing the dialog itself
        # and the c4dtools resource.
        self.MenuFlushAll()
        menu.render(self, res)
        self.MenuFinished()

        # ...
        return True

Warning

The c4dtools.resource.menuparser module requires the scan module. This is why this module is not imported implicitly with the c4dtools module. You have to import it explicitly:

import c4dtools.resource.menuparser
# or
from c4dtools.resource import menuparser

The scan module can be obtained from github. The minimum version required is 0.4.5.

class c4dtools.resource.menuparser.MenuContainer(symbol)[source]

This class represents a container for Cinema 4D dialog menus containg menu commands. The class can be rendered recursively on a dialog to create such a menu.

symbol

The resource-symbol for the menu-container that can be used to obtain the name of the menu. No sub-menu will be created with rendering the instance when this value evaluates to False (eg. None value).

class c4dtools.resource.menuparser.MenuItem(id, string)[source]

This class represents an item added via c4d.gui.GeDialog.MenuAddString(). It is not created from this module but may be used create dynamic menus.

id

The integral number of the symbol to add.

string

The menu-commands item string.

c4dtools.resource.menuparser.parse_and_prepare(filename, dialog, res)[source]

Like parse_file(), but renders the parsed menus to the dialog.

c4dtools.resource.menuparser.parse_file(filename)[source]

Parse a *.menu file from the local file-system. Returns a list of MenuContainer objects.

c4dtools.resource.menuparser.parse_fileobject(fl)[source]

Parse a file-like object. Returns a list of MenuContainer objects.

c4dtools.resource.menuparser.parse_string(data)[source]

Parse a *.menu formatted string. Returns a list of of MenuContainer objects.

c4dtools.misc

Miscellaneous packages.

c4dtools.misc.boundingbox

Utility for computing the bounding-box spanned by a couple of vectors or by c4d.BaseObject instances.

class c4dtools.misc.boundingbox.AABB(min_v=Vector(), max_v=Vector(), translation_matrix=Matrix())[source]

This class makes it easy to compute the bounding-box of a set of points or even objects. AABB is short for “axis-aligned bounding-box”.

Example for Script Manager:

from c4dtools.misc.boundingbox import AABB
box = AABB()
box.expand(op, recursive=True)
print box.midpoint
print box.size

The bounding box is always calculated from global coordinates and is translated with the matrix in the translation_matrix slot. The translation can not be performed after expansion of the bounding- box, the translation_matrix must therefore be set before expand() or expand_point() is called.

from c4dtools.misc.boundingbox import AABB
box = AABB(translation_matrix=~op.GetMg())
box.expand(mg, recursive=True)
print box.midpoint
print box.size
expand(obj, recursive=False)[source]

Expand the bounding-box by the passed c4d.BaseObject instance. The method can optionally continue recursively.

Raises: TypeError when obj is not an instance of
c4d.BaseObject.
expand_point(point)[source]

Expand the bounding-box by the passed c4d.Vector representing a point in the 3-dimensional space.

Raises: TypeError when point is not an instance of
c4d.Vector.
midpoint[source]

Calcuates and returns the midpoint of the bounding-box yet created.

size[source]

Returns the size of the bounding-box yet created. The size plus the midpoint of the bounding-box is the upper-right-front corner of the box.

c4dtools.misc.graphnode

Thin wrapper for interacting with XPresso Node UI.

class c4dtools.misc.graphnode.GraphNode(node)[source]

This class is a thin wrapper for the c4d.modules.graphview.GvNode class providing an easy interface for accessing and modifieng the visual appeareance of an XPresso node in the XPresso editor.

Currently, only accessing the position and size is supported.

get_graphcontainer(container)[source]

This method returns the container containing the graphdata for the node in the XPresso grap based on the GvNode s container.

position[source]

Returns the visual position of the node as c4d.Vector.

size[source]

Returns the visual size of the node as c4d.Vector. The container IDs differ for extended and standart view mode. The size is read/set according the to view mode the node is currently assigned to.

view[source]

Returns the type of view of the node. Either VIEW_MINIMIZED, VIEW_STANDART, VIEW_EXTENDED or VIEW_FULLSCREEN.

Note: Still not sure how the locking is specified in the container,
it is however defined in the View section in the GUI.
view_position[source]

Returns the position of the “camera” that is “looking” onto the nodes as c4d.Vector.

zoom[source]

Returns the zoom of the XPresso nodes graphview. This value is only has effect for XGroups. The zoom is a floating-point value, 100% represented as 1.0.

c4dtools.misc.graphnode.find_nodes_mid(nodes)[source]

Finds the mid-point of the passed list of c4dtools.misc.graphnode.GraphNode instances.

c4dtools.misc.graphnode.find_selected_nodes(root)[source]

Finds the group of selected nodes in the XPresso Manager and returns a list of GvNode objects.

c4dtools.misc.userdata

Module for interacting with Cinema 4D’s UserData interface.

class c4dtools.misc.userdata.UserDataSetAndGet(fields, op, do_caching=True)[source]

This class manages userdata-value retrieval and storing. It accepts a dictionary associating the attribute-name and the userdata’s sub-id on initialization and the c4d.BaseList2D object to use for retrival and storing.

The values can optionally be cached to improve value retrieval.

from c4dtools.misc.userdata import UserDataSetAndGet as UDSG
data = UDSG({
    'count': 1,
    'link': 2,
}, op)
print data.count
print data.link
# Equal to
print op[c4d.ID_USERDATA, 1]
print op[c4d.ID_USERDATA, 2]
clear_cache()[source]

Clear the cached values. Call this in case the host object’s parameters have changed by not using the instance of this class.

c4dtools.misc.normalalign

New in 1.2.5.

This module implements a function for checking the alignment of the normals of a polygon-object.

c4dtools.misc.normalalign.align_object_normals(op, info=None, logger=None)[source]

Align the passed polygon-object’s normals to point to the outside of the object. The same algorithmic restrictions as for test_object_normals() apply. The parameters do also equal.

c4dtools.misc.normalalign.test_object_normals(op, info=None, logger=None)[source]

Tests the polygon-object op‘s normals if they’re pointing to the in or outside of the object. Returns a list of boolean variables where each index defines wether the associated polygon’s normal is pointing into the right direction or not.

The algorithm works best on completely closed shapes with one segment only. The polygon-object should also be valid, therefore not more than two polygons per edge, etc. The results might be incorrect with an invalid mesh structure.

Parameters:
  • op – A c4d.PolygonObject instance to test.
  • info – A PolygonObjectInfo instance for the passed object, or None to generate on demand.
Returns:

list of bool and the PolygonObjectInfo instance.

Indices and tables