spirographs/spirographs.py
A.M. Rowsell d34d6d1ba1
Working version!
Had to get the canvas object to draw_idle() in order for it
to be refreshed. Now it works great! I might tweak the step size
for the sliders, as 0.1 can end up with weird, not quite complete
plots.
2021-06-27 16:44:11 -04:00

106 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# gtk imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject, GLib
# math/plot imports
from matplotlib.backends.backend_gtk3agg import (
FigureCanvasGTK3Agg as FigureCanvas)
from matplotlib.figure import Figure
import numpy as np
import math
import sys
class spirographs:
def __init__(self):
self.bigRadius = 12
self.smallRadius = 5
self.distance = 4
self.highestTheta = (np.lcm(self.smallRadius, self.bigRadius)/self.bigRadius) * 2 * math.pi
self.stepSize = self.highestTheta / 4096
# update initial slider positions
bigRadiusAdjustment = builder.get_object('bigRadiusAdjustment')
smallRadiusAdjustment = builder.get_object('smallRadiusAdjustment')
distanceAdjustment = builder.get_object('distanceAdjustment')
bigRadiusAdjustment.set_value(self.bigRadius)
smallRadiusAdjustment.set_value(self.smallRadius)
distanceAdjustment.set_value(self.distance)
# create initial plot
self.recalcPoints()
self.showPlot()
def calcEpiX(self, theta):
return ((self.bigRadius + self.smallRadius) * math.cos(theta)) - (self.distance * math.cos(((self.bigRadius + self.smallRadius)/(self.smallRadius))*theta))
def calcEpiY(self, theta):
return ((self.bigRadius + self.smallRadius) * math.sin(theta)) - (self.distance * math.sin(((self.bigRadius + self.smallRadius)/(self.smallRadius))*theta))
def calcHypoX(self, theta):
return ((self.bigRadius - self.smallRadius) * math.cos(theta)) + (self.distance * math.cos(((self.bigRadius - self.smallRadius)/(self.smallRadius))*theta))
def calcHypoY(self, theta):
return ((self.bigRadius - self.smallRadius) * math.sin(theta)) - (self.distance * math.sin(((self.bigRadius - self.smallRadius)/(self.smallRadius))*theta))
def onDestroy(self, widget):
Gtk.main_quit()
return
def bigRadiusAdjustment_value_changed_cb(self, widget):
self.bigRadius = widget.get_value()
self.recalcPoints()
self.updatePlot()
def smallRadiusAdjustment_value_changed_cb(self, widget):
self.smallRadius = widget.get_value()
self.recalcPoints()
self.updatePlot()
def distanceAdjustment_value_changed_cb(self, widget):
self.distance = widget.get_value()
self.recalcPoints()
self.updatePlot()
def recalcPoints(self):
self.epiX = np.array([self.calcEpiX(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
self.epiY = np.array([self.calcEpiY(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
self.hypoX = np.array([self.calcHypoX(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
self.hypoY = np.array([self.calcHypoY(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
def showPlot(self):
viewport = builder.get_object('plotViewport')
self.plotFigure = Figure(figsize=(5, 4), dpi=100)
self.epiPlot, self.hypoPlot = self.plotFigure.subplots(1, 2)
self.epiPlot.set_title(f"Epichondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}")
self.epiPlot.plot(self.epiX, self.epiY)
self.hypoPlot.set_title(f"Hypochondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}")
self.hypoPlot.plot(self.hypoX, self.hypoY)
self.canvas = FigureCanvas(self.plotFigure)
self.canvas.set_size_request(800, 600)
viewport.add(self.canvas)
def updatePlot(self):
self.epiPlot.clear()
self.hypoPlot.clear()
self.epiPlot.set_title(f"Epichondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}")
self.hypoPlot.set_title(f"Hypochondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}")
self.epiPlot.plot(self.epiX, self.epiY)
self.hypoPlot.plot(self.hypoX, self.hypoY)
self.canvas.draw_idle()
builder = Gtk.Builder()
builder.add_from_file("spirographs.glade")
sp = spirographs()
builder.connect_signals(sp)
window = builder.get_object("spWindow")
window.show_all()
Gtk.main()