"""
The polyhedron module allows creation and drawing of polyhedra.The body of the
polyhedron is composed of faces that are composed of vertices.
Control over the vertices, faces, color, and opacity of a box are provided.
However, please note that the current implementation does not ensure the
passed in vertices and faces will enclose to form a volume. This must be
determined in the subclass.
To draw any number of polyhedra, create the Polyhedron instances, add them to
a Group instance then invoke the Group's draw() method.
Copyright Schrodinger, LLC. All rights reserved.
"""
from math import sqrt
import schrodinger
from . import common
from .common import FILL
from .common import LINE
from .common import OPACITY_MAX
from .common import OPACITY_MIN
from .common import Group  # noqa: F401
maestro = schrodinger.get_maestro()
# Each polyhedron is either going to be in Maestro mode or standalone mode
MODE_MAESTRO, MODE_STANDALONE = list(range(2))
OPACITY_DEFAULT = 1.0
COLOR_DEFAULT = 'red'
PHI = (1.0 + sqrt(5.0)) / 2.0
[docs]def origin_to_point(vertices, center):
    """
    Takes a set of vertices that have been created around the origin
    and translates them to the be centered around the x, y, z coordinates
    supplied in `center`.
    :param vertices: The list of vertices around the origin
    :type  vertices: list of lists (e.g. [[x1,y1,z1],[x2,y2,z2],...]
    :param   center: The x, y, and z coordinates to center the `vertices` on
    :type    center: list of floats
    """
    for i in range(len(vertices)):
        vertices[i] = [(v + c) for v, c in zip(vertices[i], center)]
    return vertices 
[docs]def scale_vertices(vertices, scale):
    """
    Scale a set of vertices.
    :param vertices: The list of vertices around the origin
    :type  vertices: list of lists (e.g. [[x1,y1,z1],[x2,y2,z2],...]
    :param    scale: The scale to apply to the vertices
    :type     scale: float
    """
    for i in range(len(vertices)):
        vertices[i] = [(v * scale) for v in vertices[i]]
    return vertices 
[docs]class MaestroPolyhedronCore(common._MaestroPrimitiveMixin, common.Primitive):
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """
        Create a polyhedron centered at `center`. Note that one of length,
        radius, or volume is needed to create the shape.
        :param center: List of 3 Angstrom values indicating the center
            coordinate of the tetrahedron.
        :type center: list(float)
        :param length: Length in Angstroms of each of the edges of the
            tetrahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
            tetrahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        :param color: One of - Color object, Color name (string), or Tuple of
            (R, G, B) (each 0.0-1.0)
        :param opacity: 0.0 (invisible) through 1.0 (opaque). Defaults to 1.0
        :type opacity: float
        :param style: LINE or FILL.  Default is FILL.
        :type style: int
        :raise RuntimeError: If a single option from `length`, `radius`, and
                             `volume` does not have a value.
        :raise ValueError:   If the size parameter (`length`, `radius`, or
                             `volume`) is not a float.
        :raise NotImplementedError: If the initiating subclass does not have
                                    a `getVertices` or `getFaces` method.
        """
        self._checkSizeArgs(length, radius, volume)
        self.length = length
        self.radius = radius
        self.volume = volume
        self.center = center
        self.vertices = self.getVertices(center,
                                         length=length,
                                         radius=radius,
                                         volume=volume)
        self.faces = self.getFaces(self.vertices)
        self._setNormals()
        self.r, self.g, self.b = common.color_arg_to_rgb(color)
        # Clamp to range of 0.0 and 1.0, inclusive
        opacity = float(opacity)
        if opacity < OPACITY_MIN:
            self.opacity = OPACITY_MIN
        elif opacity > OPACITY_MAX:
            self.opacity = OPACITY_MAX
        else:
            self.opacity = opacity
        if (style != FILL and style != LINE):
            raise ValueError("Style must be FILL or LINE")
        else:
            self.style = style
        if mode != MODE_MAESTRO and mode != MODE_STANDALONE:
            raise ValueError("mode must be MODE_MAESTRO or MODE_STANDALONE")
        else:
            self.mode = mode
        if mode == MODE_MAESTRO and maestro:
            self.polyhedron = maestro.create_polyhedron(self.vertices,
                                                        self.getIndices(),
                                                        self.normals, self.r,
                                                        self.g, self.b,
                                                        self.opacity,
                                                        self.style)
            maestro_objects = [self.polyhedron]
            common.Primitive.__init__(self, maestro_objects)
        else:
            common.Primitive.__init__(self)
        return 
    def _setNormals(self):
        """
        Private method to set the normals based on the `self.faces` value. A
        `normal is created for each face in `self.faces`. This method will
        clear all normals and re-calculate them.
        """
        self.normals = []
        for face in self.faces:
            self.normals.append(common.create_normal(face))
    def _calculateBoundingBox(self, mat):
        """
        Calculate a bounding box for the polyhedron. This is used when
        resizing the molecule in the workspace.
        Returns two lists of coordinates, each of 6 elements. The first
        three elements of the first list are the minimum values of the
        rotated object, the second three elements are the minimum values of
        the unrotated object. The second list has the corresponding maximum
        values.
        """
        i = 0
        tmp = [0.0, 0.0, 0.0] + self.vertices[0]
        tmp[0] = mat[0][0] * tmp[3] + mat[0][1] * tmp[4] + mat[0][2] * tmp[
            5] + mat[0][3]
        tmp[1] = mat[1][0] * tmp[3] + mat[1][1] * tmp[4] + mat[1][2] * tmp[
            5] + mat[1][3]
        tmp[2] = mat[2][0] * tmp[3] + mat[2][1] * tmp[4] + mat[2][2] * tmp[
            5] + mat[2][3]
        xyzmin = tmp[:]
        xyzmax = tmp[:]
        for i in range(1, len(self.vertices)):
            tmp[3:6] = self.vertices[i][0:3]
            tmp[0] = mat[0][0] * tmp[3] + mat[0][1] * tmp[4] + mat[0][2] * tmp[
                5] + mat[0][3]
            tmp[1] = mat[1][0] * tmp[3] + mat[1][1] * tmp[4] + mat[1][2] * tmp[
                5] + mat[1][3]
            tmp[2] = mat[2][0] * tmp[3] + mat[2][1] * tmp[4] + mat[2][2] * tmp[
                5] + mat[2][3]
            for k in range(6):
                if xyzmin[k] > tmp[k]:
                    xyzmin[k] = tmp[k]
                if xyzmax[k] < tmp[k]:
                    xyzmax[k] = tmp[k]
        return (xyzmin, xyzmax)
[docs]    def update(self, vertices, faces):
        """
        Update the polyhedron's shape.
        :param vertices: List of vertices. Each member of list should be
                         a list of 3 coords, [x,y,z]
        :type  vertices: list of lists
        :param faces: List of faces comprising the polyhedron. Each face
                      should be a list of at least 3 vertices.
        :type  faces: list of lists
        :see: `Tetrahedron.updateVertices` for an example of usage
        """
        self.vertices = vertices
        self.faces = faces
        self._setNormals() 
[docs]    def setStyle(self, style):
        """
        Sets the polyhedron's drawing style.
        :param style: Whether to fill the polyhedron in or to leave it as
                      lines connecting vertices.
        :type  style: Choice, FILL or LINE
        """
        if self.mode == MODE_MAESTRO and maestro:
            maestro.set_polyhedron_style(self.polyhedron, style) 
    def _checkSizeArgs(self, length, radius, volume):
        """
        A private method to make sure the size options are correctly set.
        """
        size_args = 0
        for arg in (length, radius, volume):
            if arg:
                try:
                    arg = float(arg)
                except ValueError:
                    raise ValueError('The "length", "radius" and "volume" '
                                     'keywords must be a float.')
                size_args += 1
        if size_args != 1:
            raise RuntimeError('A single size paramter must be supplied from '
                               '"length", "radius" or "volume".')
[docs]    def getVertices(self):
        """Abstract method, defined by convention only"""
        raise NotImplementedError("%s must implement an upload method." %
                                  self.__class__.__name__) 
[docs]    def getIndices(self):
        """Abstract method, defined by convention only"""
        raise NotImplementedError("%s must implement a getIndices() method." %
                                  self.__class__.__name__) 
[docs]    def getFaces(self, vertices):
        """
        :param vertices: List of vertices. Each member of list should be
                         a list of 3 coords, [x,y,z]
        :type  vertices: list of lists
        """
        faces = []
        indices = self.getIndices()
        for index in indices:
            face = []
            for i in index:
                face.append(vertices[i])
            faces.append(face)
        return faces 
[docs]    def updateVertices(self, center, length=None, radius=None, volume=None):
        """
        Update the vertices given a new `center` and size parameter. The
        changes will be seen the next time the object is drawn.
        :param center: List of 3 Angstrom values indicating the center
                       coordinate of the tetrahedron.
        :type center: list(float, float, float)
        :param length: Length in Angstroms of each of the edges of the
                       tetrahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       tetrahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        :type radius: float
        :raise RuntimeError: If a single option from `length`, `radius`, and
                             `volume` does not have a value.
        :raise ValueError: If the size parameter (`length`, `radius`, or
                           `volume`) is not a float.
        See `Polyhedron.update`
        """
        self._checkSizeArgs(length, radius, volume)
        self.vertices = self.getVertices(center,
                                         length=length,
                                         radius=radius,
                                         volume=volume)
        self.faces = self.getFaces(self.vertices)
        self.update(self.vertices, self.faces)  
[docs]class MaestroCube(MaestroPolyhedronCore):
    """
    Class to draw a 3D cube in Maestro's Workspace.
    Cubes should be added to a graphics3d.common.Group, or CubeGroup, and
    drawing done via the Group. See the `graphics3d.common.Group`
    documentation.
    API Example::
        import schrodinger.maestro.maestro as maestro
        import schrodinger.graphics3d.polyhedron as polyhedron
        cube_group = polyhedron.Group()
        st = maestro.workspace_get() # Here, st is methane.
        for atom in st.atom:
            if atom.element == 'C':
                center = atom.xyz
        cube = polyhedron.Cube(
            center  = center,
            mode = polyhedron.MODE_MAESTRO,
            length  = 1.828, # length between Hs
            color   = 'goldenrod',
            opacity = 1.0,
            style   = polyhedron.LINE
        )
        # Add the primative to the container.
        cube_group.add(cube)
        # Show the markers
        cube.show()
        cube_group.show()
        # Hide the markers.
        cube_group.hide()
        # Remove the markers and the callback.
        cube_group.clear()
    """
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """ :see: `MaestroPolyhedronCore.__init__` """
        MaestroPolyhedronCore.__init__(self,
                                       center,
                                       mode,
                                       length=length,
                                       radius=radius,
                                       volume=volume,
                                       color=color,
                                       opacity=opacity,
                                       style=style) 
[docs]    def getVertices(self, center, length=None, radius=None, volume=None):
        """
        Get a list of vertices. If the center coordinates are considered
        the origin the vertices will have a base on the y-plane, a vertex
        on the x-axis and a vertex directly in the +z-axis from the `center`.
        :param center: List of 3 Angstrom values indicating the center
                       coordinate of the tetrahedron.
        :type center: list(float,  float, float)
        :param length: Length in Angstroms of each of the sides of the
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        """
        if length is not None:
            edge_length = float(length)
        elif radius is not None:
            edge_length = 2.0 * sqrt(float(radius)) / 3.0
        elif volume is not None:
            edge_length = float(volume)**(1.0 / 3.0)
        # We need to scale the edge length. The base_vertices below produce
        # a cube with an edge length of 2
        edge_length /= 2.0
        # Define a cube about the origin
        base_vertices = [[1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], [-1.0, -1.0, 1.0],
                         [1.0, -1.0, 1.0], [1.0, 1.0, -1.0], [-1.0, 1.0, -1.0],
                         [-1.0, -1.0, -1.0], [1.0, -1.0, -1.0]]
        vertices = scale_vertices(base_vertices, edge_length)
        return origin_to_point(vertices, center) 
[docs]    def getIndices(self):
        """
        :return The indices of the faces
        """
        indices = [[0, 1, 2, 3], [4, 7, 6, 5], [0, 4, 5, 1], [1, 5, 6, 2],
                   [2, 6, 7, 3], [3, 7, 4, 0]]
        return indices  
# **************************************************************************
[docs]class MaestroTetrahedron(MaestroPolyhedronCore):
    """
    Class to draw a 3D tetrahedron in Maestro's Workspace.
    Tetrahedrons should be added to a graphics3d.common.Group, or
    TetrahedronGroup, and drawing done via the Group. See the
    `graphics3d.common.Group` documentation.
    API Example::
        import schrodinger.maestro.maestro as maestro
        import schrodinger.graphics3d.polyhedron as polyhedron
        tetrahedron_grp = polyhedron.Group()
        st = maestro.workspace_get() # Here, st is methane.
        for atom in st.atom:
            if atom.element == 'C':
                center = atoms.xyz
        tetra = polyhedron.Tetrahedron(
            center  = center,
            length  = 1.828, # length between Hs
            color   = 'goldenrod',
            opacity = 1.0,
            style   = tetrahedron.LINE
        )
        # Add the primative to the container.
        tetrahedron_grp.add(tetra)
        # Hide the markers.
        tetrahedron_grp.hide()
        # Remove the markers
        tetrahedron_grp.clear()
    """
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """ :see: `MaestroPolyhedronCore.__init__` """
        MaestroPolyhedronCore.__init__(self,
                                       center,
                                       mode,
                                       length=length,
                                       radius=radius,
                                       volume=volume,
                                       color=color,
                                       opacity=opacity,
                                       style=style) 
[docs]    def getVertices(self, center, length=None, radius=None, volume=None):
        """
        Get a list of vertices. If the center coordinates are considered
        the origin the vertices will have a base on the y-plane, a vertex
        on the x-axis and a vertex directly in the +z-axis from the `center`.
        :param center: List of 3 Angstrom values indicating the center
                       coordinate of the tetrahedron.
        :type center: list(float, float, float)
        :param length: Length in Angstroms of each of the sides of the
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        """
        if length is not None:
            edge_length = float(length)
        elif radius is not None:
            edge_length = radius / sqrt(3.0 / 8.0)
        elif volume is not None:
            edge_length = (12.0 / sqrt(2.0) * float(volume))**(1.0 / 3.0)
        # We need to scale the edge length. The base_vertices below produce
        # a tetrahedron with an edge length of 2*sqrt(2)
        edge_length /= 2.0 * sqrt(2.0)
        # Define a tetrahedron about the origin
        base_vertices = [[1.0, 1.0, 1.0], [-1.0, -1.0, 1.0], [-1.0, 1.0, -1.0],
                         [1.0, -1.0, -1.0]]
        vertices = scale_vertices(base_vertices, edge_length)
        return origin_to_point(vertices, center) 
[docs]    def getIndices(self):
        """
        :return The indices of the faces
        """
        indices = [[2, 1, 0], [1, 3, 0], [3, 2, 0], [2, 3, 1]]
        return indices  
[docs]class MaestroOctahedron(MaestroPolyhedronCore):
    """
    Class to draw a 3D octahedron in Maestro's Workspace.
    See `Tetrahedron` doc string for more details.
    """
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """ :see: `MaestroPolyhedronCore.__init__` """
        MaestroPolyhedronCore.__init__(self,
                                       center,
                                       mode,
                                       length=length,
                                       radius=radius,
                                       volume=volume,
                                       color=color,
                                       opacity=opacity,
                                       style=style) 
[docs]    def getVertices(self, center, length=None, radius=None, volume=None):
        """
        Get a list of vertices. If the center coordinates are considered the
        origin the vertices will have a base on the y-plane, a vertex on the
        x-axis and a vertex directly in the +z-axis from the `center`.
        :param center: List of 3 Angstrom values indicating the center
                       coordinate of the tetrahedron.
        :type center: list(float, float, float)
        :param length: Length in Angstroms of each of the sides of the
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       tetrahedron. Note: `length` or `radius` must be
                       specified to create tetrahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        """
        if length is not None:
            edge_length = float(length)
        elif radius is not None:
            edge_length = float(radius) * 2.0 / sqrt(2.0)
        elif volume is not None:
            edge_length = (3.0 * float(volume) / sqrt(2.0))**(1.0 / 3.0)
        # We need to scale the edge length. The base_vertices below produce
        # an octahedron with an edge length of sqrt(2)
        edge_length /= sqrt(2.0)
        # Define the octahedron about the origin
        base_vertices = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0],
                         [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, -1.0]]
        vertices = scale_vertices(base_vertices, edge_length)
        return origin_to_point(vertices, center) 
[docs]    def getIndices(self):
        """
        :return The indices of the faces
        """
        indices = [[0, 1, 2], [0, 2, 4], [0, 4, 5], [0, 5, 1], [3, 1, 5],
                   [3, 5, 4], [3, 4, 2], [3, 2, 1]]
        return indices  
[docs]class MaestroDodecahedron(MaestroPolyhedronCore):
    """
    Class to draw a 3D dodecahedron in Maestro's Workspace.
    See `Tetrahedron` doc string for more details.
    """
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """ :see: `MaestroPolyhedronCore.__init__` """
        MaestroPolyhedronCore.__init__(self,
                                       center,
                                       mode,
                                       length=length,
                                       radius=radius,
                                       volume=volume,
                                       color=color,
                                       opacity=opacity,
                                       style=style) 
[docs]    def getVertices(self, center, length=None, radius=None, volume=None):
        """
        Get a list of vertices. If the center coordinates are considered the
        origin the vertices will have a base on the y-plane, a vertex on the
        x-axis and a vertex directly in the +z-axis from the `center`.
        :param center: List of 3 Angstrom values indicating the center
                       coordinate of the dodecahedron.
        :type center: list(float, float, float)
        :param length: Length in Angstroms of each of the sides of the
                       dodecahedron. Note: `length` or `radius` must be
                       specified to create dodecahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       dodecahedron. Note: `length` or `radius` must be
                       specified to create dodecahedron.
        :type radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type volume: float
        """
        if length is not None:
            edge_length = float(length)
        elif radius is not None:
            edge_length = radius / sqrt(3.0 / 8.0)
        elif volume is not None:
            edge_length = (4.0 * float(volume) /
                           (15 + (7.0 * sqrt(15.0))))**(1.0 / 3.0)
        # We need to scale the edge length. The base_vertices below produce
        # a dodecahedron with an edge length of 2/phi
        edge_length /= (2.0 / PHI)
        # Initial dodecahedron placed at origin
        iPHI = 1.0 / PHI
        base_vertices = [
            [1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1, -1],
            [-1, 1, 1], [-1, 1, -1], [-1, -1, 1], [-1, -1, -1],
            [0, iPHI, PHI], [ 0, iPHI, -PHI ], [0, -iPHI, PHI], [0, -iPHI, -PHI],
            [ iPHI, PHI, 0 ], [iPHI, -PHI, 0], [-iPHI, PHI, 0], [-iPHI, -PHI, 0],
            [PHI, 0, iPHI], [PHI, 0, -iPHI], [-PHI, 0, iPHI], [-PHI, 0, -iPHI]
        ]  # yapf:disable
        # Scale the vertices by length
        vertices = scale_vertices(base_vertices, edge_length)
        return origin_to_point(vertices, center) 
[docs]    def getIndices(self):
        """
        :return The indices of the faces
        """
        indices = [
            [0, 16, 17, 1, 12],
            [16, 2, 13, 3, 17],
            [3, 13, 15, 7, 11],
            [15, 6, 18, 19, 7],
            [9, 5, 14, 12, 1],
            [1, 17, 3, 11, 9],
            [16, 0, 8, 10, 2],
            [12, 14, 4, 8, 0],
            [5, 19, 18, 4, 14],
            [7, 19, 5, 9, 11],
            [15, 13, 2, 10, 6],
            [4, 18, 6, 10, 8],
        ]
        return indices  
# **************************************************************************
[docs]class MaestroIcosahedron(MaestroPolyhedronCore):
    """
    Class to draw a 3D icosahedron in Maestro's Workspace.
    See `Tetrahedron` doc string for more details.
    """
[docs]    def __init__(self,
                 center,
                 mode,
                 length=None,
                 radius=None,
                 volume=None,
                 color=COLOR_DEFAULT,
                 opacity=OPACITY_DEFAULT,
                 style=FILL):
        """ :see: `MaestroPolyhedronCore.__init__` """
        MaestroPolyhedronCore.__init__(self,
                                       center,
                                       mode,
                                       length=length,
                                       radius=radius,
                                       volume=volume,
                                       color=color,
                                       opacity=opacity,
                                       style=style) 
[docs]    def getVertices(self, center, length=None, radius=None, volume=None):
        """
        Get a list of vertices. If the center coordinates are considered the
        origin the vertices will have a base on the y-plane, a vertex on the
        x-axis and a vertex directly in the +z-axis from the `center`.
        :param center: List of 3 Angstrom values indicating the center
                        coordinate of the icosahedron.
        :type center: list(float, float, float)
        :param length: Length in Angstroms of each of the sides of the
                       icosahedron. Note: `length` or `radius` must be
                       specified to create icosahedron.
        :type length: float
        :param radius: Circumsphere radius in Angstroms from center of
                       icosahedron. Note: `length` or `radius` must be
                       specified to create icosahedron.
        :type  radius: float
        :param volume: Volume in cubed Angstroms of the object.
        :type  volume: float
        """
        if length is not None:
            edge_length = float(length)
        elif radius is not None:
            edge_length = 2.0 * float(radius) / (sqrt(1 + PHI * PHI))
        elif volume is not None:
            edge_length = (6.0 * float(volume) / (5.0 * PHI * PHI))**(1.0 / 3.0)
        PHI2 = PHI * PHI
        PHI3 = PHI2 * PHI
        # We need to scale the edge length. The base_vertices below produce
        # a dodecahedron with an edge length of 2*phi^2
        edge_length /= (2.0 * PHI2)
        # Initial dodecahedron placed at origin
        base_vertices = [[PHI2, 0, PHI3], [-PHI2, 0, PHI3], [0, PHI3, PHI2],
                         [0, -PHI3, PHI2], [PHI3, PHI2, 0], [-PHI3, PHI2, 0],
                         [-PHI3, -PHI2, 0], [PHI3, -PHI2, 0], [0, PHI3, -PHI2],
                         [0, -PHI3, -PHI2], [PHI2, 0, -PHI3], [-PHI2, 0, -PHI3]]
        # Scale the vertices by length
        vertices = scale_vertices(base_vertices, edge_length)
        return origin_to_point(vertices, center) 
[docs]    def getIndices(self):
        """
        :return The indices of the faces
        """
        indices = [[0, 1, 3], [0, 2, 1], [0, 3, 7], [0, 7, 4], [0, 4, 2],
                   [7, 10, 4], [4, 10, 8], [4, 8, 2], [2, 8, 5], [2, 5, 1],
                   [1, 5, 6], [1, 6, 3], [3, 6, 9], [3, 9, 7], [7, 9, 10],
                   [11, 10, 9], [11, 8, 10], [11, 5, 8], [11, 6, 5], [11, 9, 6]]
        return indices