Difference between revisions of "Ellipsoid"

From PyMOLWiki
Jump to: navigation, search
m
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 22: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')