Source code for c4dtools.misc.boundingbox

# coding: utf-8
#
# Copyright (c) 2012-2013, Niklas Rosenstein
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met: 
# 
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer. 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution. 
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be interpreted
# as representing official policies,  either expressed or implied, of
# the FreeBSD Project.
r"""
c4dtools.misc.boundingbox
~~~~~~~~~~~~~~~~~~~~~~~~~

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

import c4d
import copy
from c4dtools.utils import clsname, vmin, vmax

[docs]class AABB(object): r""" 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: .. code-block:: python 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. .. code-block:: python from c4dtools.misc.boundingbox import AABB box = AABB(translation_matrix=~op.GetMg()) box.expand(mg, recursive=True) print box.midpoint print box.size """ def __init__(self, min_v=c4d.Vector(0), max_v=c4d.Vector(0), translation_matrix=c4d.Matrix()): super(AABB, self).__init__() self.min_v = copy.copy(min_v) self.max_v = copy.copy(max_v) self.translation_matrix = copy.copy(translation_matrix)
[docs] def expand(self, obj, recursive=False): r""" Expand the bounding-box by the passed :class:`c4d.BaseObject` instance. The method can optionally continue recursively. Raises: TypeError when *obj* is not an instance of :class:`c4d.BaseObject`. """ if not isinstance(obj, c4d.BaseObject): raise TypeError('expected c4d.BaseObject, got %s.' % clsname(obj)) matrix = obj.GetMg() mp = obj.GetMp() bb = obj.GetRad() v = c4d.Vector self.expand_point(v(mp.x + bb.x, mp.y + bb.y, mp.z + bb.z) * matrix) self.expand_point(v(mp.x - bb.x, mp.y + bb.y, mp.z + bb.z) * matrix) self.expand_point(v(mp.x + bb.x, mp.y + bb.y, mp.z - bb.z) * matrix) self.expand_point(v(mp.x - bb.x, mp.y + bb.y, mp.z - bb.z) * matrix) self.expand_point(v(mp.x + bb.x, mp.y - bb.y, mp.z + bb.z) * matrix) self.expand_point(v(mp.x - bb.x, mp.y - bb.y, mp.z + bb.z) * matrix) self.expand_point(v(mp.x + bb.x, mp.y - bb.y, mp.z - bb.z) * matrix) self.expand_point(v(mp.x - bb.x, mp.y - bb.y, mp.z - bb.z) * matrix) if recursive: for child in obj.GetChildren(): self.expand(child, True)
[docs] def expand_point(self, point): r""" 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. """ vmin(self.min_v, point * self.translation_matrix) vmax(self.max_v, point * self.translation_matrix)
@property
[docs] def midpoint(self): r""" Calcuates and returns the midpoint of the bounding-box yet created. """ return (self.min_v + self.max_v) * 0.5
@property
[docs] def size(self): r""" 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. """ return (self.max_v - self.min_v) * 0.5