Source code for soma.wip.aimsalgo.samplables.superquadricsamplable

#  This software and supporting documentation are distributed by
#      Institut Federatif de Recherche 49
#      CEA/NeuroSpin, Batiment 145,
#      91191 Gif-sur-Yvette cedex
#      France
#
# This software is governed by the CeCILL-B license under
# French law and abiding by the rules of distribution of free software.
# You can  use, modify and/or redistribute the software under the 
# terms of the CeCILL-B license as circulated by CEA, CNRS
# and INRIA at the following URL "http://www.cecill.info". 
# 
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or 
# data to be ensured and,  more generally, to use and operate it in the 
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL-B license and that you accept its terms.

#########################################################################
#
# Project : Pyaimsalgo
# Module : aimsalgo.samplables
# Create date : 2007-07-13
#
# Description :
# 	This file contains SuperQuadricSamplable class
#
#########################################################################
from __future__ import absolute_import
import sys
import math
import types

import numpy
from soma import aimsalgo, aims

from soma.aimsalgo import Samplable_FLOAT_3
from soma.wip.aimsalgo.transform import BendingTransform
from soma.wip.aimsalgo.transform import TaperingTransform
from six.moves import range


[docs]class SuperQuadricSamplable( Samplable_FLOAT_3 ) : """ Constructor of the class. @type coefficients: list @param checkActivated: list of the 10 deformable superquadric coefficients. - e1 : first shape parameter - e2 : second shape parameter - a1 : x axis ray - a2 : y axis ray - a3 : z axis ray - k1 : first tapering parameter - k2 : second tapering parameter - k3 : third tapering parameter - alpha : angle of bending plan - kapa : curvature radius for the bending transform """ def __init__( self, coefficients, bending = True, tapering = True, checkActivated = True, maxBoundingBoxVolume = 10 ** 7) : Samplable_FLOAT_3.__init__( self ) self._checking = dict() self._coefficients = coefficients self._bending = bending self._bendingTransform = BendingTransform(coefficients[8:10]) self._tapering = tapering self._taperingTransform = TaperingTransform(coefficients[4:8]) self._maxBoundingBoxVolume = maxBoundingBoxVolume self._offset = self.getBoundingBoxStart( ) self._checked = self.check( checkActivated ) """ Check that the deformable superquadric parameters are consistents. @type checkActivated: bool @param checkActivated: Specify if the check is activated. """ def check( self, checkActivated ) : e1 = self._coefficients[0] e2 = self._coefficients[1] a1 = self._coefficients[2] a2 = self._coefficients[3] a3 = self._coefficients[4] k1 = self._coefficients[5] k2 = self._coefficients[6] k3 = self._coefficients[7] alpha = self._coefficients[8] kapa = self._coefficients[9] if (checkActivated) : # Check that parameters verify constraints # Check for a3 parameter checked = ( a3 != 0 ) self._checking['a3'] = checked result = checked # Check for e1 parameter checked = ( e1 != 0 ) self._checking['e1'] = checked result &= checked # Check for e1 parameter checked = ( e2 != 0 ) self._checking['e2'] = checked result &= checked if (self._tapering) : # Check for k1 parameter if (result) : checked = ( ( ( -1 * k3 * ( a3 ** -1 ) ) - 1 ) <= k1 ) checked &= ( k1 <= ( ( k3 * ( a3 ** -1 ) ) + 1 ) ) self._checking['k1'] = checked result = checked # Check for k2 parameter if (result) : checked = ( ( ( -1 * k3 * ( a3 ** -1 ) ) - 1 ) <= k2 ) checked &= ( k2 <= ( ( k3 * ( a3 ** -1 ) ) + 1 ) ) self._checking['k2'] = checked result &= checked if (self._bending) : # Check for kappa parameter if ( kapa != 0 ) : kapaInversed = kapa ** -1 checked = ( ( a3 / math.pi ) < math.fabs( kapaInversed ) ) checked &= ( ( math.sqrt ( a1**2 * ( ( math.cos(alpha) ** 2) ** e2 ) + a2**2 * ( ( math.sin(alpha) ** 2) ** e2 ) ) ) < math.fabs( kapaInversed ) ) else : checked = True self._checking['kapa'] = checked result &= checked sizes = self.getBoundingBoxSizes( ) if ( self._maxBoundingBoxVolume is not None ) : # Check for bounding box volume volume = sizes[0] * sizes[1] * sizes[2] checked = (volume <= self._maxBoundingBoxVolume) self._checking['boundingboxvolume'] = checked result &= checked # Check that no overflow occurs try : self._checked = checked self.contains( sizes ) except : checked = False self._checking['overflow'] = checked result &= checked return result else : return True """ Check that a point is contained in the current deformable superquadric. This method is called by samplers during sampling to check that the point is contained by the object. @type point: bool @param point: The point to check. """ def isChecked( self ) : return self._checked """ Check that a point is contained in the current deformable superquadric. This method is called by samplers during sampling to check that the point is contained by the object. @type point: aims.Point3df @param point: The point to check. """ def contains( self, point ) : if ( self._checked ) : # The superquadric has always its bounding box start point in (0, 0, 0) # this allow to always sample BucketMap point += self._offset e1 = self._coefficients[0] e2 = self._coefficients[1] a1 = self._coefficients[2] a2 = self._coefficients[3] a3 = self._coefficients[4] if ( self._bending ) : # Apply inverse of the bending transformation transformed = self._bendingTransform.inverseTransform( point ) else : transformed = point if (self._tapering) : transformed = self._taperingTransform.inverseTransform( transformed ) x = transformed[0] y = transformed[1] z = transformed[2] # Check that point belongs to superquadric object result = ( (math.fabs(x/a1)**(2/e2) ) + (math.fabs(y/a2)**(2/e2) ) )**(e2/e1) + (math.fabs(z/a3)**(2/e1) ) return (result <= 1) else : return False """ Get bounding box start for the current superquadric. @rtype: aims.Point3df @return: start of the bounding box for the superquadric. """ def getBoundingBoxStart( self ): a1 = self._coefficients[2] a2 = self._coefficients[3] a3 = self._coefficients[4] alpha = self._coefficients[8] kapa = self._coefficients[9] sizes = aims.Point3df( a1, a2, a3 ) if (self._tapering) : # Apply the tapering transformation sizes = self._taperingTransform.transform( sizes ) if ( self._bending and ( kapa != 0 ) ) : results = self.getBendingMinMax( sizes ) start = results[0] start[2] = - self.getZMax() else : start = sizes * -1 return start """ Get bounding box sizes for the current superquadric. @rtype: aims.Point3df @return: sizes of the bounding box for the superquadric. """ def getBoundingBoxSizes( self ): e1 = self._coefficients[0] e2 = self._coefficients[1] a1 = self._coefficients[2] a2 = self._coefficients[3] a3 = self._coefficients[4] alpha = self._coefficients[8] kapa = self._coefficients[9] sizes = aims.Point3df( a1, a2, a3 ) if (self._tapering) : # Apply the tapering transformation sizes = self._taperingTransform.transform( sizes ) if ( self._bending and ( kapa != 0 ) ) : results = self.getBendingMinMax( sizes ) minimum = results[0] maximum = results[1] sizes[0] = (maximum[0] - minimum[0]) sizes[1] = (maximum[1] - minimum[1]) sizes[2] = 2 * self.getZMax() else : sizes *= 2 return sizes """ Get maximum z value for the deformable superquadric after transformation. @rtype: float @return: maximum z value for the superquadric. """ def getZMax( self ): e1 = self._coefficients[0] e2 = self._coefficients[1] a1 = self._coefficients[2] a2 = self._coefficients[3] a3 = self._coefficients[4] alpha = self._coefficients[8] kapa = self._coefficients[9] sizes = aims.Point3df( a1, a2, a3 ) if (self._tapering) : # Apply the tapering transformation to coefficients sizes = self._taperingTransform.transform( sizes ) a1 = sizes[0] a2 = sizes[1] a3 = sizes[2] if (kapa != 0): boundingRay = math.sqrt ( a1**2 * ( math.cos(alpha) ** 2 ) ** e2 + a2**2 * ( math.sin(alpha) ** 2 ) ** e2 ) / 2 zmax = ( boundingRay + 1 / kapa ) else: zmax = a3 return zmax """ Get minimum and maximum values for points. @type sizes: aims.Point3df @param sizes: list that contains 8 points of bounding box to get the bounding box after bending transform. @rtype: list @return: minimum and maximum points after bending transformation applied. """ def getBendingMinMax(self, sizes): # Get the 4 points of the bounding box in the plan z=0 point1 = aims.Point3df( sizes[0], sizes[1], 0) point2 = aims.Point3df( sizes[0], -sizes[1], 0) point3 = aims.Point3df( -sizes[0], -sizes[1], 0) point4 = aims.Point3df( -sizes[0], sizes[1], 0) # Get the 4 top points of the bounding box plan z=sizes[2] point5 = aims.Point3df( sizes[0], sizes[1], sizes[2]) point6 = aims.Point3df( sizes[0], -sizes[1], sizes[2]) point7 = aims.Point3df( -sizes[0], -sizes[1], sizes[2]) point8 = aims.Point3df( -sizes[0], sizes[1], sizes[2]) # Apply the bending transformation to the 4 top points # of the bounding box point5 = self._bendingTransform.transform( point5 ) point6 = self._bendingTransform.transform( point6 ) point7 = self._bendingTransform.transform( point7 ) point8 = self._bendingTransform.transform( point8 ) # Get the maximum and minimum values for x, y, z points = [point1, point2, point3, point4, point5, point6, point7, point8] result = self.getMinMax( points ) return result """ Get minimum and maximum values for points. @type points: list @param points: The list of points to get minimum and maximum. @rtype: list @return: minimum and maximum points. """ def getMinMax(self, points): if points is not None : minimum = aims.Point3df(points[0]) maximum = aims.Point3df(points[0]) for point in points : for index in range(len(point)) : if point[index] < minimum[index] : minimum[index] = point[index] if point[index] > maximum[index] : maximum[index] = point[index] result = [minimum, maximum] else : result = None return result