Exemple #1
0
class GraphingInterface(Core.Object):
    enter_function = Core.InputEvent(KEYBOARD, PRESS, ord(' '))

    def __init__(self):
        Core.Object.__init__(self)
        self.graph = StringFunctionGrapher()
        self.prompt = Prompt()
        self.flash = OnScreenMessage()

        self.flash.position = (-310, 230)
        self.flash.text_size = 25
        self.flash.delay = 5.0
        self.flash.color = (0, 0.2, 0.7)
        self.prompt.position = (-310, 230)
        self.prompt.text_size = 25
        self.prompt.color = (0, 0.2, 0.7)
        self.prompt.set_callback(self.update_function)
        self.graph.position = (-320, 0)
        self.graph.set(DRAW)

    def input(self, evt):
        if (evt == self.enter_function) and not self.prompt.active():
            self.flash.hide()
            self.prompt.ask("Function: ")

    def update_function(self, new_func, context = None):
        try:
            self.graph.set_string_function(new_func)
        except Exception as e:            
            self.flash.show("Invalid function '%s':\n%s" % (new_func, e))
        else:
            self.flash.show("Graphing\nf(x) = %s" % new_func)        
Exemple #2
0
class binaryStarSystem(Core.Object):
    e_toggle_particles = Core.InputEvent(KEYBOARD, PRESS, KEY_SPACE)
    e_toggle_centripetal = Core.InputEvent(KEYBOARD, PRESS, ord("c"))

    M2_over_M1 = 0.5
    a = 200
    primaryThreshold = -12.0
    secondaryThreshold = -12.0

    screen_width = 640.0
    screen_height = 480.0
    vertical_offset = -100

    CM = None
    r1 = None
    r2 = None

    phiIncludeCentripetalForce = False
    primaryStarParticles = None
    secondaryStarParticles = None

    screenMessage = None

    def __init__(self):
        Core.Object.__init__(self)

        # Calculate/Set the position-information
        self.CM = Vector()
        self.centerOfScreen = (0, 250, 0)
        self.calculateRs()
        self.calculateRadii()
        self.position = self.CM

        # Set up the primaryParticles variables
        self.createdPrimaryStarParticles = False
        self.primaryStarParticles = []
        self.secondaryStarParticles = []

        # Create the on-screen message
        self.screenMessage = OnScreenMessage()
        self.screenMessage.position = (-310, 230, 0)
        self.screenMessage.set(DRAW)

    def drawStars(self, primary_radius):
        glPushMatrix()
        glTranslate(self.centerOfScreen[0], self.centerOfScreen[1] + self.vertical_offset, 0)
        glColor(1.0, 0, 0)
        Draw.circle((self.r1, 0, 0), primary_radius, True)
        Draw.circle((self.r1 + self.a, 0, 0), primary_radius * self.M2_over_M1, True)
        glPopMatrix()

    def drawCM(self):
        glColor(0.0, 1.0, 0.0)
        glBegin(GL_LINES)
        glVertex(self.CM[0] + 2, self.CM[1] + self.vertical_offset + 2)
        glVertex(self.CM[0] - 2, self.CM[1] + self.vertical_offset - 2)
        glVertex(self.CM[0] + 2, self.CM[1] + self.vertical_offset - 2)
        glVertex(self.CM[0] - 2, self.CM[1] + self.vertical_offset + 2)
        glEnd()

    def draw(self):
        self.drawStars(10)
        self.drawCM()

    def render(self):
        self.plotPhiSurface()

    def input(self, evt):
        if evt == self.e_toggle_centripetal:
            self.phiIncludeCentripetalForce = not self.phiIncludeCentripetalForce
        elif evt == self.e_toggle_particles:
            if not self.createdPrimaryStarParticles:
                self.createStarParticles()
            else:
                self.destroyStarParticles()

    def step(self):
        if Keyboard.down(KEY_LEFT) and self.a > 25:
            self.updateA(self.a - 2)
            self.screenMessage.show("Seperation: %.2f R" % (self.a / self.primaryRadius))
        elif Keyboard.down(KEY_RIGHT):
            self.updateA(self.a + 2)
            self.screenMessage.show("Seperation: %.2f R" % (self.a / self.primaryRadius))
        elif Keyboard.down(KEY_DOWN) and self.M2_over_M1 > 0.14:
            self.updateM2_over_M1(self.M2_over_M1 - 0.05)
            self.screenMessage.show("M2 = %.2f M1" % (1.0 / self.M2_over_M1))
        elif Keyboard.down(KEY_UP) and self.M2_over_M1 < 0.96:
            self.updateM2_over_M1(self.M2_over_M1 + 0.05)
            self.screenMessage.show("M2 = %.2f M1" % (1.0 / self.M2_over_M1))

    def calculateRs(self):
        self.r1 = -100
        self.r2 = self.r1 + self.a
        self.CM[0] = self.centerOfScreen[0] + (self.r1 + self.M2_over_M1 * self.r2) / (1 + self.M2_over_M1)
        self.CM[1] = self.centerOfScreen[1]
        self.CM[2] = 0

    def calculateRadii(self):
        # Find the primaryRadius, the leftmost point on the graph of Phi that is equal to primaryThreshold
        self.primaryRadius = 0
        P1 = self.primaryStarPosition()
        while self.Phi(P1[0] - self.primaryRadius, P1[1]) <= self.primaryThreshold:
            self.primaryRadius += 0.1

        self.secondaryRadius = 0
        P2 = self.secondaryStarPosition()
        while self.Phi(P2[0] + self.secondaryRadius, P2[1]) <= self.secondaryThreshold:
            self.secondaryRadius += 0.1

    def updateA(self, a):
        self.a = a
        self.calculateRs()

    def updateM2_over_M1(self, M2_over_M1):
        self.M2_over_M1 = M2_over_M1
        self.calculateRs()
        self.calculateRadii()

        # This relationship is not derived from any physical laws, it just seems to work well
        self.secondaryThreshold = self.primaryThreshold - (1.0 - self.M2_over_M1) * 4.0

    def Phi(self, sx, sy):
        x = sx - self.CM[0]
        y = sy - self.CM[1]

        r1 = (self.centerOfScreen[0] - self.CM[0]) + self.r1
        r2 = self.centerOfScreen[0] + (self.r2 - self.CM[0])
        s1 = 0.1 * sqrt((x - r1) ** 2 + y ** 2)
        s2 = 0.1 * sqrt((x - r2) ** 2 + y ** 2)

        if s1 <= 0.001 or s2 <= 0.001:
            return -50
        else:
            local_a = 100
            Phi = -(local_a / s1) * (1 + self.M2_over_M1 * s1 / s2) / (1 + self.M2_over_M1)
            if Phi < -50:
                return -50
            if self.phiIncludeCentripetalForce:
                Phi -= (x ** 2 + y ** 2) / (2 * local_a * local_a)
            return Phi

    def primaryPsuedoPressurePotential(self, sx, sy):
        x = sx - self.CM[0]
        y = sy - self.CM[1]

        s1 = 0.1 * sqrt((x - self.r1) ** 2 + y ** 2)

        local_a = 100

        return local_a / s1

    def plotPhiSurface(self):
        N = 40
        phi_max = 100

        x_start = -320
        x_end = 320
        y_start = 0
        y_end = 480

        len_x = x_end - x_start
        len_y = y_end - y_start

        dx = round(len_x / N)
        dy = round(len_y / N)

        glScale(0.0125, 0.0125, 0.01)
        glTranslate(-100, 100, 0)
        glBegin(GL_QUADS)

        kx = 200 / len_x
        ky = 200 / len_y
        for x in range(0, len_x, dx):
            xnext = x + dx
            for y in range(0, len_y, dy):
                ynext = y + dy

                k = 10
                phi_x_y = k * self.Phi(x_start + x, y_start + y)
                phi_xnext_y = k * self.Phi(x_start + x + dx, y_start + y)
                phi_xnext_ynext = k * self.Phi(x_start + x + dx, y_start + y + dy)
                phi_x_ynext = k * self.Phi(x_start + x, y_start + y + dy)

                glNormal((phi_x_y - phi_xnext_y) * dy, (phi_x_y - phi_x_ynext) * dx, dx * dy)

                c = 1.0 + phi_x_y / phi_max
                glColor(0.0, c, 1.0 - c)

                glVertex(kx * x, phi_x_y, ky * y)
                glVertex(kx * xnext, phi_xnext_y, ky * y)
                glVertex(kx * xnext, phi_xnext_ynext, ky * ynext)
                glVertex(kx * x, phi_x_ynext, ky * ynext)

                glVertex(kx * x, phi_x_ynext, ky * ynext)
                glVertex(kx * xnext, phi_xnext_ynext, ky * ynext)
                glVertex(kx * xnext, phi_xnext_y, ky * y)
                glVertex(kx * x, phi_x_y, ky * y)

        glEnd()

    def primaryStarPosition(self):
        return Vector(self.centerOfScreen[0] + self.r1, self.centerOfScreen[1], 0)

    def secondaryStarPosition(self):
        return Vector(self.centerOfScreen[0] + self.r2, self.centerOfScreen[1], 0)

    def createStarParticles(self):
        num_secondary_particles = round(500 * self.M2_over_M1)
        for i in range(1000 - num_secondary_particles):
            p = starParticle(
                binarySystem, binarySystem.primaryStarPosition(), self.primaryThreshold, self.primaryRadius - 10
            )
            self.primaryStarParticles.append(p)
            p.set(DRAW | STEP)

        for i in range(num_secondary_particles):
            p = starParticle(
                binarySystem,
                binarySystem.secondaryStarPosition(),
                self.secondaryThreshold,
                self.secondaryRadius - 10,
                (1.0, 0.5, 0.0),
            )
            self.secondaryStarParticles.append(p)
            p.set(DRAW | STEP)

        self.createdPrimaryStarParticles = True

    def destroyStarParticles(self):
        for p in self.primaryStarParticles:
            p.unset(DRAW | STEP)
            del p
        for p in self.secondaryStarParticles:
            p.unset(DRAW | STEP)
            del p
        self.primaryStarParticles = []
        self.secondaryStarParticles = []
        self.createdPrimaryStarParticles = False