Ellipsoid: Difference between revisions

From PyMOLWiki
Jump to navigation Jump to search
mNo edit summary
No edit summary
Line 1: Line 1:
This script provides a class called "SimpleEllipsoid" that can be created and [[load]]ed into pymol as a [[callback object]]. It uses code that is ported from [http://www.gamedev.net/reference/articles/article1172.asp this c++ code] and seems to be correct! In theory, this could be extended to make toroidal objects, as well as cylinders, spheres, and 'pillows'. Probably not very useful, though.
This script provides methods that create [[cgo]]s as triangles. It uses code that is ported from [http://www.gamedev.net/reference/articles/article1172.asp this c++ code] and seems to be correct!  


Here is the script. The last four lines show this in use, by making two ellipses and loading them into pymol.
Here is the script. The last four lines show this in use, by making an ellipse and a toroid and loading them into pymol. This is done most easily by something like "cmd.load_cgo(makeEllipsoid(1, 1, 1, 2, 3, 4), 'ellipsoid')" which makes an ellipsoid at x, y, z = 1, 1, 1 and dimensions 2, 3, 4 and called 'ellipsoid'.


<source lang="python">
<source lang="python">
from pymol.opengl.gl import *
from pymol.cgo import BEGIN, COLOR, TRIANGLES, VERTEX, NORMAL, END
from pymol.callback import Callback
from pymol import cmd
from pymol import cmd


Line 22: Line 21:
         return signOfFloat(math.sin(v)) * math.pow(math.fabs(math.sin(v)), n)
         return signOfFloat(math.sin(v)) * math.pow(math.fabs(math.sin(v)), n)


def sqEllipsoid(a1, a2, a3, u, v, n, e):
def sqEllipsoid(x, y, z, a1, a2, a3, u, v, n, e):
         x = a1 * sqC(u, n) * sqC(v, e)
         x = a1 * sqC(u, n) * sqC(v, e) + x
         y = a2 * sqC(u, n) * sqS(v, e)
         y = a2 * sqC(u, n) * sqS(v, e) + y
         z = a3 * sqS(u, n)
         z = a3 * sqS(u, n) + z
         nx = sqC(u, 2 - n) * sqC(v, 2 - e) / a1
         nx = sqC(u, 2 - n) * sqC(v, 2 - e) / a1
         ny = sqC(u, 2 - n) * sqS(v, 2 - e) / a2
         ny = sqC(u, 2 - n) * sqS(v, 2 - e) / a2
Line 31: Line 30:
         return x, y, z, nx, ny, nz
         return x, y, z, nx, ny, nz


def sqToroid(a1, a2, a3, u, v, n, e, alpha):
def sqToroid(x, y, z, a1, a2, a3, u, v, n, e, alpha):
         a1prime = 1 / (a1 + alpha)
         a1prime = 1.0 / (a1 + alpha)
         a2prime = 1 / (a2 + alpha)
         a2prime = 1.0 / (a2 + alpha)
         a3prime = 1 / (a3 + alpha)
         a3prime = 1.0 / (a3 + alpha)
         x = a1prime * sqCT(u, e, alpha) * sqC(v, n)
         x = a1prime * sqCT(u, e, alpha) * sqC(v, n)
         y = a2prime * sqCT(u, e, alpha) * sqS(v, n)
         y = a2prime * sqCT(u, e, alpha) * sqS(v, n)
Line 43: Line 42:
         return x, y, z, nx, ny, nz
         return x, y, z, nx, ny, nz


class SuperQuadricEllipsoid(Callback):
def makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, n, e, u1, u2, v1, v2, u_segs, v_segs, color=[0.5, 0.5, 0.5]):


         def __init__(self, x, y, z, a1, a2, a3, n, e, u1, u2, v1, v2, u_segs, v_segs, alpha=0):
         r, g, b = color


                # Calculate delta variables
        # Calculate delta variables */
                dU = (u2 - u1) / u_segs
        dU = (u2 - u1) / u_segs
                dV = (v2 - v1) / v_segs
        dV = (v2 - v1) / v_segs


                # Setup storage for data
        o = [ BEGIN, TRIANGLES ]
                self.points = []
                self.normals = []


                 # Store the position
        U = u1
                 self.x, self.y, self.z = x, y, z
        for Y in range(0, u_segs):
                 # Initialize variables for loop */
                V = v1
                 for X in range(0, v_segs):
                        # VERTEX #1 */
                        x1, y1, z1, n1x, n1y, n1z = sqEllipsoid(x, y, z, a1, a2, a3, U, V, n, e)
                        x2, y2, z2, n2x, n2y, n2z = sqEllipsoid(x, y, z, a1, a2, a3, U + dU, V, n, e)
                        x3, y3, z3, n3x, n3y, n3z = sqEllipsoid(x, y, z, a1, a2, a3, U + dU, V + dV, n, e)
                        x4, y4, z4, n4x, n4y, n4z = sqEllipsoid(x, y, z, a1, a2, a3, U, V + dV, n, e)


                # Initialize variables for loop
                        o.extend([COLOR, r, g, b, NORMAL, n1x, n1y, n1z, VERTEX, x1, y1, z1])
                U = u1
                         o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                for Y in range(0, u_segs):
                         o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])
                         # Initialize variables for loop
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                         V = v1
                        o.extend([COLOR, r, g, b, NORMAL, n3x, n3y, n3z, VERTEX, x3, y3, z3])
                        for X in range(0, v_segs):
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])
                                # VERTEX #1 */
                                x, y, z, nx, ny, nz = sqEllipsoid(a1, a2, a3, U, V, n, e)
                                self.points.append((x, y, z))
                                self.normals.append((nx, ny, nz))


                                # VERTEX #2 */    
                        # Update variables for next loop */
                                x, y, z, nx, ny, nz = sqEllipsoid(a1, a2, a3, U + dU, V, n, e)
                        V += dV
                                self.points.append((x, y, z))
                # Update variables for next loop */
                                self.normals.append((nx, ny, nz))
                U += dU
        o.append(END)
        return o
 
def makeSuperQuadricToroid(x, y, z, a1, a2, a3, alpha, n, e, u1, u2, v1, v2, u_segs, v_segs, color=[0.5, 0.5, 0.5]):
 
        r, g, b = color
 
        # Calculate delta variables */
        dU = (u2 - u1) / u_segs
        dV = (v2 - v1) / v_segs
 
        o = [ BEGIN, TRIANGLES ]


                                # VERTEX #3 */
        U = u1
                                x, y, z, nx, ny, nz = sqEllipsoid(a1, a2, a3, U + dU, V + dV, n, e)
        for Y in range(0, u_segs):
                                self.points.append((x, y, z))
                # Initialize variables for loop */
                                self.normals.append((nx, ny, nz))
                V = v1
                for X in range(0, v_segs):
                        # VERTEX #1 */
                        x1, y1, z1, n1x, n1y, n1z = sqToroid(x, y, z, a1, a2, a3, U, V, n, e, alpha)
                        x2, y2, z2, n2x, n2y, n2z = sqToroid(x, y, z, a1, a2, a3, U + dU, V, n, e, alpha)
                        x3, y3, z3, n3x, n3y, n3z = sqToroid(x, y, z, a1, a2, a3, U + dU, V + dV, n, e, alpha)
                        x4, y4, z4, n4x, n4y, n4z = sqToroid(x, y, z, a1, a2, a3, U, V + dV, n, e, alpha)


                                # VERTEX #4 */
                        o.extend([COLOR, r, g, b, NORMAL, n1x, n1y, n1z, VERTEX, x1, y1, z1])
                                x, y, z, nx, ny, nz = sqEllipsoid(a1, a2, a3, U, V + dV, n, e)
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                                self.points.append((x, y, z))
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])
                                self.normals.append((nx, ny, nz))
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                        o.extend([COLOR, r, g, b, NORMAL, n3x, n3y, n3z, VERTEX, x3, y3, z3])
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])


                                # Update variables for next loop */
                                V += dV
                         # Update variables for next loop */
                         # Update variables for next loop */
                         U += dU
                         V += dV
                # Update variables for next loop */
                U += dU
        o.append(END)
        return o
 
def makeEllipsoid(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 1.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)
 
def makeCylinder(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 0.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)
 
def makeSpindle(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 2.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)


        def get_extent(self):
def makeDoublePyramid(x, y, z, a1, a2, a3):
                 return [[-10.0, -10.0, -10.0], [10.0, 10.0, 10.0]]
                 return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 2.0, 2.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)


        def __call__(self):
def makePillow(x, y, z, a1, a2, a3):
                 glPushMatrix()
                 return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 1.0, 0.0, -math.pi, math.pi, -math.pi, math.pi, 10, 10)
                glTranslatef(self.x, self.y, self.z)
                glBegin(GL_QUADS)
                glColor3f(1.0, 1.0, 0.0)
                for i in range(0, u_segs * v_segs * 4):
                        x, y, z = self.points[i]
                        nx, ny, nz = self.normals[i]
                        glNormal3f(nx, ny, nz)
                        glVertex3f(x, y, z)
                glEnd()
                glPopMatrix()


class SimpleEllipsoid(SuperQuadricEllipsoid):
def makeRoundCube(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 0.2, 0.2, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)


        def __init__(self, x, y, z, a1, a2, a3):
def makeToroid(x, y, z, a1, a2, a3, alpha):
                 SuperQuadricEllipsoid.__init__(self, x, y, z, a1, a2, a3, 1.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)
                 return makeSuperQuadricToroid(x, y, z, a1, a2, a3, alpha, 1.0, 1.0, -math.pi, math.pi, -math.pi, math.pi, 10, 10)


x, y, z = 1, 1, 1
x, y, z, rx, ry, rz = 1, 1, 1, 1, 2, 3
rx, ry, rz = 1, 2, 3
cmd.load_cgo(makeEllipsoid(x, y, z, rx, ry, rz), 'ellipsoid-cgo')
cmd.load_callback(SimpleEllipsoid(x, y, z, rx, ry, rz), 'ellipsoid1')
x, y, z, rx, ry, rz = 1, 1, 1, 8, 2, 2
x, y, z = 2, 2, 2
cmd.load_cgo(makeToroid(x, y, z, rx, ry, rz, 3), 'toroid-cgo')
rx, ry, rz = 2, 1, 3
cmd.load_callback(SimpleEllipsoid(x, y, z, rx, ry, rz), 'ellipsoid2')
</source>
</source>

Revision as of 21:28, 19 July 2005

This script provides methods that create cgos as triangles. It uses code that is ported from this c++ code and seems to be correct!

Here is the script. The last four lines show this in use, by making an ellipse and a toroid and loading them into pymol. This is done most easily by something like "cmd.load_cgo(makeEllipsoid(1, 1, 1, 2, 3, 4), 'ellipsoid')" which makes an ellipsoid at x, y, z = 1, 1, 1 and dimensions 2, 3, 4 and called 'ellipsoid'.

from pymol.cgo import BEGIN, COLOR, TRIANGLES, VERTEX, NORMAL, END
from pymol import cmd

def signOfFloat(f):
        if f < 0: return -1
        if f > 0: return 1
        return 0

def sqC(v, n):
        return signOfFloat(math.cos(v)) *  math.pow(math.fabs(math.cos(v)), n)

def sqCT(v, n, alpha):
        return alpha + sqC(v, n)

def sqS(v, n):
        return signOfFloat(math.sin(v)) * math.pow(math.fabs(math.sin(v)), n)

def sqEllipsoid(x, y, z, a1, a2, a3, u, v, n, e):
        x = a1 * sqC(u, n) * sqC(v, e) + x
        y = a2 * sqC(u, n) * sqS(v, e) + y
        z = a3 * sqS(u, n) + z
        nx = sqC(u, 2 - n) * sqC(v, 2 - e) / a1
        ny = sqC(u, 2 - n) * sqS(v, 2 - e) / a2
        nz = sqS(u, 2 - n) / a3
        return x, y, z, nx, ny, nz

def sqToroid(x, y, z, a1, a2, a3, u, v, n, e, alpha):
        a1prime = 1.0 / (a1 + alpha)
        a2prime = 1.0 / (a2 + alpha)
        a3prime = 1.0 / (a3 + alpha)
        x = a1prime * sqCT(u, e, alpha) * sqC(v, n)
        y = a2prime * sqCT(u, e, alpha) * sqS(v, n)
        z = a3prime * sqS(u, e)
        nx = sqC(u, 2 - e) * sqC(v, 2 - n) / a1prime
        ny = sqC(u, 2 - e) * sqS(v, 2 - n) / a2prime
        nz = sqS(u, 2 - e) / a3prime
        return x, y, z, nx, ny, nz

def makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, n, e, u1, u2, v1, v2, u_segs, v_segs, color=[0.5, 0.5, 0.5]):

        r, g, b = color

        # Calculate delta variables */
        dU = (u2 - u1) / u_segs
        dV = (v2 - v1) / v_segs

        o = [ BEGIN, TRIANGLES ]

        U = u1
        for Y in range(0, u_segs):
                # Initialize variables for loop */
                V = v1
                for X in range(0, v_segs):
                        # VERTEX #1 */
                        x1, y1, z1, n1x, n1y, n1z = sqEllipsoid(x, y, z, a1, a2, a3, U, V, n, e)
                        x2, y2, z2, n2x, n2y, n2z = sqEllipsoid(x, y, z, a1, a2, a3, U + dU, V, n, e)
                        x3, y3, z3, n3x, n3y, n3z = sqEllipsoid(x, y, z, a1, a2, a3, U + dU, V + dV, n, e)
                        x4, y4, z4, n4x, n4y, n4z = sqEllipsoid(x, y, z, a1, a2, a3, U, V + dV, n, e)

                        o.extend([COLOR, r, g, b, NORMAL, n1x, n1y, n1z, VERTEX, x1, y1, z1])
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                        o.extend([COLOR, r, g, b, NORMAL, n3x, n3y, n3z, VERTEX, x3, y3, z3])
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])

                        # Update variables for next loop */
                        V += dV
                # Update variables for next loop */
                U += dU
        o.append(END)
        return o

def makeSuperQuadricToroid(x, y, z, a1, a2, a3, alpha, n, e, u1, u2, v1, v2, u_segs, v_segs, color=[0.5, 0.5, 0.5]):

        r, g, b = color

        # Calculate delta variables */
        dU = (u2 - u1) / u_segs
        dV = (v2 - v1) / v_segs

        o = [ BEGIN, TRIANGLES ]

        U = u1
        for Y in range(0, u_segs):
                # Initialize variables for loop */
                V = v1
                for X in range(0, v_segs):
                        # VERTEX #1 */
                        x1, y1, z1, n1x, n1y, n1z = sqToroid(x, y, z, a1, a2, a3, U, V, n, e, alpha)
                        x2, y2, z2, n2x, n2y, n2z = sqToroid(x, y, z, a1, a2, a3, U + dU, V, n, e, alpha)
                        x3, y3, z3, n3x, n3y, n3z = sqToroid(x, y, z, a1, a2, a3, U + dU, V + dV, n, e, alpha)
                        x4, y4, z4, n4x, n4y, n4z = sqToroid(x, y, z, a1, a2, a3, U, V + dV, n, e, alpha)

                        o.extend([COLOR, r, g, b, NORMAL, n1x, n1y, n1z, VERTEX, x1, y1, z1])
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])
                        o.extend([COLOR, r, g, b, NORMAL, n2x, n2y, n2z, VERTEX, x2, y2, z2])
                        o.extend([COLOR, r, g, b, NORMAL, n3x, n3y, n3z, VERTEX, x3, y3, z3])
                        o.extend([COLOR, r, g, b, NORMAL, n4x, n4y, n4z, VERTEX, x4, y4, z4])

                        # Update variables for next loop */
                        V += dV
                # Update variables for next loop */
                U += dU
        o.append(END)
        return o

def makeEllipsoid(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 1.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)

def makeCylinder(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 0.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)

def makeSpindle(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 2.0, 1.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)

def makeDoublePyramid(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 2.0, 2.0, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)

def makePillow(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 1.0, 0.0, -math.pi, math.pi, -math.pi, math.pi, 10, 10)

def makeRoundCube(x, y, z, a1, a2, a3):
                return makeSuperQuadricEllipsoid(x, y, z, a1, a2, a3, 0.2, 0.2, -math.pi / 2, math.pi / 2, -math.pi, math.pi, 10, 10)

def makeToroid(x, y, z, a1, a2, a3, alpha):
                return makeSuperQuadricToroid(x, y, z, a1, a2, a3, alpha, 1.0, 1.0, -math.pi, math.pi, -math.pi, math.pi, 10, 10)

x, y, z, rx, ry, rz = 1, 1, 1, 1, 2, 3
cmd.load_cgo(makeEllipsoid(x, y, z, rx, ry, rz), 'ellipsoid-cgo')
x, y, z, rx, ry, rz = 1, 1, 1, 8, 2, 2
cmd.load_cgo(makeToroid(x, y, z, rx, ry, rz, 3), 'toroid-cgo')