<div dir="ltr">"""<br>A Visual Python animation showing a "triangular page" going back and<br>forth between triangular book covers laid flat against the XY plane.<br>The page tip traces a semi-circle (not displayed but certainly computed).<br>
As a result of two triangular "flaps" (cover and page) at some dihedral<br>angle, a tetrahedron is defined, actually two, one with each cover as<br>base, tip as opposite vertex.  Their volumes will always be the same.<br>
The video pauses in two places (time.sleep()).  The Tetrahedron class<br>(imported) is designed to natively return volume in "tetravolumes"<br>but you can flip that switch easily to use xyz_volume instead.<br><br>
Dependencies:<br>Python 3.x (<a href="http://python.org">python.org</a>)<br>Visual Python (<a href="http://vpython.org">vpython.org</a>)<br><br>stickworks.py (3.x version)<br><a href="https://mail.python.org/pipermail/edu-sig/2013-September/010896.html">https://mail.python.org/pipermail/edu-sig/2013-September/010896.html</a><br>
<br>tetravolumes.py<br><a href="https://mail.python.org/pipermail/edu-sig/2013-August/010872.html">https://mail.python.org/pipermail/edu-sig/2013-August/010872.html</a><br>(watch for / repair word-wrapping in this code -- too wide for<br>
mailman defaults)<br><br>Videos and more explanation:<br><a href="http://controlroom.blogspot.com/2013/09/polyhedrons-at-play.html">http://controlroom.blogspot.com/2013/09/polyhedrons-at-play.html</a><br><br>"""<br>
<br>from tetravolumes import Tetrahedron<br>from stickworks import Vector, Edge<br>import math<br>import time<br>from visual import *<br><br><br># This module runs as "__main__" so the visual stuff kicks it off<br>
<br>scene2 = display(title = "Book Covers", width=500, height=500, background=(0,0,0), center=(0,0,0))<br>scene2.forward = (0,1,-.3)<br>scene2.autocenter = False<br>scene2.range = (2,2,4)<br>scene2.select()<br><br>
<br># In this namespace, a rod with its tail at the origin is a Vector while some line<br># segment floating in space with neither end at the origin is an Edge.<br><br># So rods like C0--S1 and even the spine and axis themselves are modeled<br>
# as Edges, not Vectors.  Edges are *defined* using two Vectors however,<br># one pointing to each end.<br><br># S0 --- S1 is the spine, two XYZ Vectors (defined in a different module named<br># stickworks.  I use the Y axis, with Z considered vertical.<br>
<br>S0 = Vector((0,0.5,0))<br>S1 = -S0<br>spine = Edge(S0, S1) # spine of a book (equilateral triangular book covers)<br><br># C0 -- C1 would be the book cover axis from cover to cover, nailed down and<br># fixed.  Again, these are modeled as Vectors.  X axis is used.<br>
<br>C0 = Vector((math.sqrt(3)/2,0,0))<br>C1 = -C0<br>axis = Edge(C0, C1)  # another fixed Edge<br><br># spine to C0<br>S0C0 = Edge(S0,C0)<br>S1C0 = Edge(S1,C0)<br><br># spine to C1<br>S0C1 = Edge(S0,C1)<br>S1C1 = Edge(S1,C1)<br>
<br>class Page:<br>    """<br>    triangular page modeled by its tip oscillating<br>    between pages.<br>    """<br><br>    def __init__(self, angle=0):<br>        self.angle = angle  # degrees<br>
        self.tip = self._getVector()<br><br>    def delta_angle(self, degrees):<br>        self.angle += degrees<br>        self.tip = self._getVector()<br><br>    def _getVector(self):<br>        #The page tip's job is to make an arc using sine and cosine of the dihedral<br>
        # angle the page is making with the flap, starting with tip at C0.<br>        z = math.sin(math.radians(self.angle)) * axis.length/2<br>        x = math.cos(math.radians(self.angle)) * axis.length/2<br>        y = 0<br>
        return Vector((x,y,z))<br><br>def complementary(page):<br>    a = Edge(page.tip, S0).length<br>    b = Edge(page.tip, C0).length<br>    c = Edge(page.tip, S1).length<br>    d = S0C0.length<br>    e = S1C0.length<br>
    f = spine.length<br>    t0 = Tetrahedron(a,b,c,d,e,f)<br><br>    a = Edge(page.tip, S0).length<br>    b = Edge(page.tip, C1).length<br>    c = Edge(page.tip, S1).length<br>    d = S0C1.length<br>    e = S1C1.length<br>
    f = spine.length<br>    t1 = Tetrahedron(a,b,c,d,e,f)<br><br>    return t0, t1<br><br><br>def inadvertent(page):<br>    # stub function marking a 3rd tetrahedron of opposite<br>    # edges green and blue, other edges red, as a fall-out,<br>
    # like another consequence of the setting for t. Per<br>    # Koski's studies.<br>    t2 = Tetrahedron( )<br>    return t2<br><br><br>spine.draw()<br>S0C0.draw()<br>S1C0.draw()<br>S0C1.draw()<br>S1C1.draw()<br>lamp = local_light(pos=(0,-3,0), color=color.yellow)<br>
page = Page()<br><br>def drawit(page):<br>    s=Edge(page.tip, S0, color=(1,0,0))<br>    t=Edge(page.tip, C1, color=(0,0,1))<br>    u=Edge(page.tip, S1, color=(1,0,0))<br>    v=Edge(page.tip, C0, color=(0,1,0))<br>    s.draw()<br>
    t.draw()<br>    u.draw()<br>    v.draw()<br>    rate(30)<br>    return s,t,u,v<br><br>def eraseit(*seq):<br>    for obj in seq:<br>        obj.erase()<br><br># a loop drives the page back and forth by upping and lowering<br>
# the degrees, of the dihedral angle.  So you'll spot where, when I'm<br># close to "regular tetrahedron" (71 degree) I swap in a dihedral angle<br># computed with trig -- you could say it's a still snap shot of the ideal,<br>
# whereas the animation skips such "irrational" dihedrals.<br><br>for i in range(4):<br>    for t in range(180):<br>        page.delta_angle(1)<br>        a,b,c,d = drawit(page)<br>        if i == 2 and t == 71:<br>
            page = Page(math.degrees(math.asin( 1/sqrt(3))) * 2)<br>            T1, T2 = complementary(page)<br>            # choose T1.ivm_volume OR T1.xyz_volume<br>            tx =text(text="Vol = {:>6.3f}".format(T1.ivm_volume()), pos=(-1, 0, -1),<br>
                     height=0.4, depth=-0.1, up=(0,0,1), color = color.orange)<br>            time.sleep(10)<br>            tx.visible = False<br>        eraseit(a,b,c,d)<br><br>    # The two stops to display volumes are programmed in.  It's not like<br>
    # I can stop it arbitrarily and have the volume displayed, although the<br>    # 2nd video may give that illusion.<br><br>    for t in range(180):<br>        page.delta_angle(-1)<br>        a,b,c,d = drawit(page)<br>        if i == 0 and t == 90:<br>
            T1, T2 = complementary(page)<br>            # choose T1.ivm_volume OR T1.xyz_volume<br>            tx =text(text="Vol = {:>6.3f}".format(T1.ivm_volume()), pos=(-1, 0, -1),<br>                     height=0.4, depth=-0.1, up=(0,0,1), color = color.orange)<br>
            time.sleep(10)<br>            tx.visible = False<br>        eraseit(a,b,c,d)<br><br><br></div>