Exemple #1
0
    def expand_object(self, obj, recursive=False):
        ensure_type(obj, c4d.BaseObject)
        mg = obj.GetMg()
        
        if isinstance(obj, c4d.PointObject):
            for p in obj.GetAllPoints():
                self.expand(p * mg)
        else:
            mp = obj.GetMp()
            bb = obj.GetRad()
    
            V = c4d.Vector
    
            self.expand(V(mp.x + bb.x, mp.y + bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y + bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x + bb.x, mp.y + bb.y, mp.z - bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y + bb.y, mp.z - bb.z) * mg)
    
            self.expand(V(mp.x + bb.x, mp.y - bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y - bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x + bb.x, mp.y - bb.y, mp.z - bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y - bb.y, mp.z - bb.z) * mg)

        if recursive:
            for child in obj.GetChildren():
                self.expand_object(child, True)
Exemple #2
0
def vbbmid(vectors):
    r"""
    Returns the mid-point of the bounding box spanned by the list
    of vectors. This is different to the arithmetic middle of the
    points.

    *Changed in 1.3.0*:

        - Moved to :mod:`c4dtools.math`.
        - Raises *ValueError* if *vectors* is not a sequence type
          or is empty.

    Returns: :class:`c4d.Vector`
    """

    ensure_type(vectors, collections.Sequence, name='vectors')
    vectors = tuple(vectors)
    if not vectors:
        raise ValueError('An empty sequence is not accepted.')

    min = Vector(vectors[0])
    max = Vector(min)
    for v in vectors:
        vmin(min, v)
        vmax(max, v)

    return (min + max) * 0.5
Exemple #3
0
    def expand_object(self, obj, recursive=False):
        ensure_type(obj, c4d.BaseObject)
        mg = obj.GetMg()

        if isinstance(obj, c4d.PointObject):
            for p in obj.GetAllPoints():
                self.expand(p * mg)
        else:
            mp = obj.GetMp()
            bb = obj.GetRad()

            V = c4d.Vector

            self.expand(V(mp.x + bb.x, mp.y + bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y + bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x + bb.x, mp.y + bb.y, mp.z - bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y + bb.y, mp.z - bb.z) * mg)

            self.expand(V(mp.x + bb.x, mp.y - bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y - bb.y, mp.z + bb.z) * mg)
            self.expand(V(mp.x + bb.x, mp.y - bb.y, mp.z - bb.z) * mg)
            self.expand(V(mp.x - bb.x, mp.y - bb.y, mp.z - bb.z) * mg)

        if recursive:
            for child in obj.GetChildren():
                self.expand_object(child, True)
Exemple #4
0
    def __init__(self, p, d):
        r"""
        *New in 1.3.0*.

        Initialize the line with one point on the line and its direction
        vector. Both, *p* and *d* may be iterables. In this case, they must
        be iterables with one to three elements because they will be extracted
        to the :class:`c4d.Vector` constructor.

        The direction vector is normalized. The vectors are copied internally.

        :param p: An element of the line (:class:`c4d.Vector`)
        :param d: The direction vector of the line (:class:`c4d.Vector`)
        """

        if isinstance(p, collections.Sequence):
            p = Vector(*p)
        if isinstance(d, collections.Sequence):
            d = Vector(*d)

        ensure_type(p, Vector, name='p')
        ensure_type(d, Vector, name='d')

        self.p = Vector(p)
        self.d = d.GetNormalized()
Exemple #5
0
    def load_container(self, dialog, container, genlist=False):
        r"""
        Just like :meth:`load_dict` but *container* is a
        :class:`c4d.BaseContainer` instance. If *genlist* is True, a list of
        names is generated that have been set from the passed *data*.
        """

        ensure_type(container, BaseContainer)

        # Rework the data dictionary to associate the symbols
        # with the datatypes.
        data = {}
        for name, (symbol, datatype, default) in self._data.iteritems():
            data[symbol] = datatype, name

        names = []
        for symbol, value in container:
            try:
                datatype, name = data[symbol]
            except KeyError:
                continue

            value = datatype.from_container(symbol, container)
            datatype.set_value(dialog, symbol, value)

            if genlist:
                names.append(name)

        return names
Exemple #6
0
def vbbmid(vectors):
    r"""
    Returns the mid-point of the bounding box spanned by the list
    of vectors. This is different to the arithmetic middle of the
    points.

    *Changed in 1.3.0*:

        - Moved to :mod:`c4dtools.math`.
        - Raises *ValueError* if *vectors* is not a sequence type
          or is empty.

    Returns: :class:`c4d.Vector`
    """

    ensure_type(vectors, collections.Sequence, name='vectors')
    vectors = tuple(vectors)
    if not vectors:
        raise ValueError('An empty sequence is not accepted.')

    min = Vector(vectors[0])
    max = Vector(min)
    for v in vectors:
        vmin(min, v)
        vmax(max, v)

    return (min + max) * 0.5
Exemple #7
0
    def __init__(self, p, d):
        r"""
        *New in 1.3.0*.

        Initialize the line with one point on the line and its direction
        vector. Both, *p* and *d* may be iterables. In this case, they must
        be iterables with one to three elements because they will be extracted
        to the :class:`c4d.Vector` constructor.

        The direction vector is normalized. The vectors are copied internally.

        :param p: An element of the line (:class:`c4d.Vector`)
        :param d: The direction vector of the line (:class:`c4d.Vector`)
        """

        if isinstance(p, collections.Sequence):
            p = Vector(*p)
        if isinstance(d, collections.Sequence):
            d = Vector(*d)

        ensure_type(p, Vector, name='p')
        ensure_type(d, Vector, name='d')

        self.p = Vector(p)
        self.d = d.GetNormalized()
Exemple #8
0
    def __init__(self, fields, op, do_caching=True):
        super(UserDataSetAndGet, self).__init__()

        ensure_type(fields, dict)
        ensure_type(op, c4d.BaseList2D)

        self._fields = copy.copy(fields)
        self._op = op
        self._cache = {}
        self._do_caching = do_caching
Exemple #9
0
    def __init__(self, fields, op, do_caching=True):
        super(UserDataSetAndGet, self).__init__()

        ensure_type(fields, dict)
        ensure_type(op, c4d.BaseList2D)

        self._fields = copy.copy(fields)
        self._op = op
        self._cache = {}
        self._do_caching = do_caching
Exemple #10
0
    def register_datatype(self, datatype):
        r"""
        Register a new data-type that will be available for the :meth:`add`
        method.
        """

        ensure_type(datatype, Datatype)
        if not datatype.identifier:
            raise ValueError('passed Datatype instance has not identifier set.')
        if datatype.identifier in self._types:
            raise RuntimeError('passed Datatype identifier already occupied.')

        self._types[datatype.identifier] = datatype
Exemple #11
0
    def load_dict(self, dialog, data, genlist=False):
        r"""
        Set values from a Python dictionary to the dialog. If *genlist*
        is True, a list of names is generated that have been set from
        the passed *data*.
        """

        ensure_type(data, dict)

        names = []
        for name, value in data.iteritems():
            symbol, datatype, default = self._data[name]
            datatype.set_value(dialog, symbol, value)

            if genlist:
                names.append(name)

        return names
Exemple #12
0
    def intersection(self, line, precision=PRECISION):
        r"""
        *New in 1.3.0*.

        Calculates the intersection point of the calling and the passed
        *line*.

        :param line: The complementary line to check for intersection with
                the calling line.
        :param precision: The allowed deviation between the components of
                the linear factors.
        :return: :class:`c4d.Vector` if the lines intersect, ``None`` if
                they do not.

        .. seealso:: :func:`line_intersection`
        """

        ensure_type(line, Line, name='line')
        return line_intersection(self.p, self.d, line.p, line.d, precision)
Exemple #13
0
    def intersection(self, line, precision=PRECISION):
        r"""
        *New in 1.3.0*.

        Calculates the intersection point of the calling and the passed
        *line*.

        :param line: The complementary line to check for intersection with
                the calling line.
        :param precision: The allowed deviation between the components of
                the linear factors.
        :return: :class:`c4d.Vector` if the lines intersect, ``None`` if
                they do not.

        .. seealso:: :func:`line_intersection`
        """

        ensure_type(line, Line, name='line')
        return line_intersection(self.p, self.d, line.p, line.d, precision)
Exemple #14
0
    def add_symbols(self, symbols):
        r"""
        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.
        """

        utils.ensure_type(symbols, dict)

        res_symbols = self.symbols
        for key, value in symbols.iteritems():
            utils.ensure_type(key, basestring, name='dict-key')
            utils.ensure_type(value, int, name='dict-value')
            if key in res_symbols and res_symbols[key] != value:
                msg = 'key %r already defined in the resource and ' \
                      'the value differs from the updating symbols.'
                raise KeyError(msg % key)
            if value > self.highest_symbol:
                self.highest_symbol = value

        res_symbols.update(symbols)
Exemple #15
0
    def add_symbols(self, symbols):
        r"""
        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.
        """

        utils.ensure_type(symbols, dict)

        res_symbols = self.symbols
        for key, value in symbols.iteritems():
            utils.ensure_type(key, basestring, name='dict-key')
            utils.ensure_type(value, int, name='dict-value')
            if key in res_symbols and res_symbols[key] != value:
                msg = 'key %r already defined in the resource and ' \
                      'the value differs from the updating symbols.'
                raise KeyError(msg % key)
            if value > self.highest_symbol:
                self.highest_symbol = value

        res_symbols.update(symbols)
Exemple #16
0
def prepare(filename=None,
            c4dres=None,
            cache=True,
            libfolder_name='lib',
            resfolder_name='res',
            parse_description=False,
            imp_store_modules=True):
    r"""
    Call this function from a Cinema 4D python plugin-file (``*.pyp``) to
    set up convenient data that can be used from the plugin.

    .. code-block:: python

        import c4d
        import c4dtools

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

        # ...

    :param filename:

        Just pass the ``__file__`` variable from the plugins global
        scope.

        *New in 1.3.0*: Default value added. The filename will
        be retrieved using the globals of the frame that has called
        the function if *None* was passed.

    :param c4dres:

        The :class:`c4d.plugins.GeResource` instance from the
        plugin's scope.

        *New in 1.2.6*: Default value added. The plugin resource
        will be retrieved using the globals of the frame that
        has called the function if *None* was passed.

    :param cache:

        True by default. Defines wether the resource symbols will
        be cached.

    :param 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.

    :param 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.

    :param parse_description:

        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.

    :param imp_store_modules:

        Passed to the constructor of the returned :class:`Importer`,
        defining whether imported modules are stored or not.

    :return:

        A tuple of two elements:

        - :class:`c4dtools.resource.Resource`
        - :class:`c4dtools.utils.Importer`

    *New in 1.3.0*: Added *imp_store_modules* parameter.
    """

    globals_ = sys._getframe().f_back.f_globals
    if filename is None:
        filename = globals_.get('__file__', None)
        if not filename:
            raise ValueError('filename could not be retrieved from the '
                             'calling frame.')
    if c4dres is None:
        c4dres = globals_.get('__res__', None)

    utils.ensure_type(filename, basestring, name='filename')
    utils.ensure_type(c4dres,
                      c4d.plugins.GeResource,
                      type(None),
                      name='c4dres')

    path = helpers.Attributor()
    path.root = os.path.dirname(filename)
    path.res = resfolder_name
    path.lib = libfolder_name

    if not os.path.isabs(path.res):
        path.res = os.path.join(path.root, path.res)
    if not os.path.isabs(path.lib):
        path.lib = os.path.join(path.root, path.lib)

    imp = importer.Importer(store_modules=imp_store_modules)
    if os.path.isdir(path.lib):
        imp.add(path.lib)

    res = resource.Resource.from_resource_folder(path.res, c4dres, cache,
                                                 parse_description)
    return (res, imp)
Exemple #17
0
def prepare(filename=None, c4dres=None, cache=True,
            libfolder_name='lib', resfolder_name='res',
            parse_description=False, imp_store_modules=True):
    r"""
    Call this function from a Cinema 4D python plugin-file (``*.pyp``) to
    set up convenient data that can be used from the plugin.

    .. code-block:: python

        import c4d
        import c4dtools

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

        # ...

    :param filename:

        Just pass the ``__file__`` variable from the plugins global
        scope.

        *New in 1.3.0*: Default value added. The filename will
        be retrieved using the globals of the frame that has called
        the function if *None* was passed.

    :param c4dres:

        The :class:`c4d.plugins.GeResource` instance from the
        plugin's scope.

        *New in 1.2.6*: Default value added. The plugin resource
        will be retrieved using the globals of the frame that
        has called the function if *None* was passed.

    :param cache:

        True by default. Defines wether the resource symbols will
        be cached.

    :param 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.

    :param 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.

    :param parse_description:

        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.

    :param imp_store_modules:

        Passed to the constructor of the returned :class:`Importer`,
        defining whether imported modules are stored or not.

    :return:

        A tuple of two elements:

        - :class:`c4dtools.resource.Resource`
        - :class:`c4dtools.utils.Importer`

    *New in 1.3.0*: Added *imp_store_modules* parameter.
    """

    globals_ = sys._getframe().f_back.f_globals
    if filename is None:
        filename = globals_.get('__file__', None)
        if not filename:
            raise ValueError('filename could not be retrieved from the '
                             'calling frame.')
    if c4dres is None:
        c4dres = globals_.get('__res__', None)

    utils.ensure_type(filename, basestring, name='filename')
    utils.ensure_type(c4dres, c4d.plugins.GeResource, type(None), name='c4dres')

    path = helpers.Attributor()
    path.root = os.path.dirname(filename)
    path.res = resfolder_name
    path.lib = libfolder_name

    if not os.path.isabs(path.res):
        path.res = os.path.join(path.root, path.res)
    if not os.path.isabs(path.lib):
        path.lib = os.path.join(path.root, path.lib)

    imp = importer.Importer(store_modules=imp_store_modules)
    if os.path.isdir(path.lib):
        imp.add(path.lib)

    res = resource.Resource.from_resource_folder(path.res, c4dres, cache,
                                                 parse_description)
    return (res, imp)