A Python Scientific Calculator

In a previous post of a Javascript Scientific Calculator I had mentioned I would be discussing other calculators. This one is written in python. The code is below:

import tkinter
from tkinter import *
from cmath import log, log10, pi, e, sin, cos, sqrt, tan, sinh, cosh, tanh
from math import pow, atan2, hypot, asinh, degrees, radians, asin, acos, atan, acosh, atanh, factorialcarry2=”general”
def get_list(event=None):
global carry
index = list1.curselection()[0]
seltext = list1.get(index) + ‘\n’
text1.delete(0, last=’end’)
text1.insert(0, seltext)
if ‘Law’ in seltext and ‘Cosines’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”side 1″)
input2.delete(0, last=’end’)
input2.insert(0,”side 2″)
input3.delete(0, last=’end’)
input3.insert(0,”angle”)
input4.delete(0, last=’end’)
carry = seltextif ‘Law’ in seltext and ‘Sines’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”side 1″)
input2.delete(0, last=’end’)
input2.insert(0,”angle 1″)
input3.delete(0, last=’end’)
input3.insert(0,”angle 2″)
input4.delete(0, last=’end’)
carry = seltextelif ‘Volume’ in seltext and ‘Sphere’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltextelif ‘Surface’ in seltext and ‘Sphere’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltextelif ‘Volume’ in seltext and ‘Cylinder’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input2.insert(0,”height”)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Surface’ in seltext and ‘Cylinder’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input2.insert(0,”height”)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Volume’ in seltext and ‘Cone’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input2.insert(0,”height”)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Surface’ in seltext and ‘Cone’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”radius”)
input2.delete(0, last=’end’)
input2.insert(0,”height”)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Hypot’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”side 1″)
input2.delete(0, last=’end’)
input2.insert(0,”side 2″)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Own’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”Enter Formula”)
input2.delete(0, last=’end’)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Compound’ in seltext and ‘Interest’ in seltext and ‘Rate’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”principle”)
input2.delete(0, last=’end’)
input2.insert(0,”final amount”)
input3.delete(0, last=’end’)
input3.insert(0,”Times/Year Calculated”)
input4.delete(0, last=’end’)
input4.insert(0,”number of years”)
carry = seltext

elif ‘Compound’ in seltext and ‘Interest’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”principle”)
input2.delete(0, last=’end’)
input2.insert(0,”annual %”)
input3.delete(0, last=’end’)
input3.insert(0,”Times/Year Calculated (use c for continuous)”)
input4.delete(0, last=’end’)
input4.insert(0,”number of years”)
carry = seltext

elif ‘Decay’ in seltext and ‘Time’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”half life”)
input2.delete(0, last=’end’)
input2.insert(0,”% remaining”)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Decay’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”initial amount”)
input2.delete(0, last=’end’)
input2.insert(0,”half life”)
input3.delete(0, last=’end’)
input3.insert(0,”time in same unit as half life”)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Annuity’ in seltext and “Sum” in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”amount added”)
input2.delete(0, last=’end’)
input2.insert(0,”interest”)
input3.delete(0, last=’end’)
input3.insert(0,”years”)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Annuity’ in seltext and “Addition” in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”total”)
input2.delete(0, last=’end’)
input2.insert(0,”interest”)
input3.delete(0, last=’end’)
input3.insert(0,”years”)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Annuity’ in seltext and “Years” in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”total”)
input2.delete(0, last=’end’)
input2.insert(0,”interest”)
input3.delete(0, last=’end’)
input3.insert(0,”addition”)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Mortgage’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”principle”)
input2.delete(0, last=’end’)
input2.insert(0,”interest”)
input3.delete(0, last=’end’)
input3.insert(0,”years”)
input4.delete(0, last=’end’)
carry = seltext

elif ‘Fibon’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”number of iterations”)
input2.delete(0, last=’end’)
input3.delete(0, last=’end’)
input4.delete(0, last=’end’)
carry = seltext
elif ‘Progress’ in seltext:
input1.delete(0, last=’end’)
input1.insert(0,”number”)
input2.delete(0, last=’end’)
input2.insert(0,”power”)
input3.delete(0, last=’end’)
input3.insert(0,”number of iterations”)
input4.delete(0, last=’end’)
carry = seltext

input1.focus()

def get_list2(event=None):
global carry2
index2 = list2.curselection()[0]
seltext2 = list2.get(index2) + ‘\n’
carry2 = seltext2

def callback():
text1.delete(0, last=’end’)
if ‘Law’ in carry and ‘Cosines’ in carry:
b = eval(input1.get()) + 0j
c = eval(input2.get()) + 0j
cosa = eval(input3.get())
cosa = cos(radians(cosa)) + 0j
a = sqrt( (b**2 + c**2) – (2*b*c*cosa))
elif ‘Law’ in carry and ‘Sines’ in carry:
sinv1 = eval(input2.get())
sinv2 = eval(input3.get())
sinv1 = sin(radians(sinv1)) + 0j
sinv2 = sin(radians(sinv2)) + 0j
v2 = eval(input1.get())
a = v2 * (sinv2/sinv1)
elif ‘Volume’ in carry and ‘Sphere’ in carry:
a = eval(input1.get())
a = (pi * a ** 3) * (4/ 3)
elif ‘Surface’ in carry and ‘Sphere’ in carry:
a = eval(input1.get())
a = 4 * pi * a**2
elif ‘Volume’ in carry and ‘Cylinder’ in carry:
a = pi * eval(input1.get())**2 * eval(input2.get())
elif ‘Surface’ in carry and ‘Cylinder’ in carry:
a = 2 * pi * eval(input1.get())**2 +  2 * pi * eval(input1.get())  * eval(input2.get())
elif ‘Volume’ in carry and ‘Cone’ in carry:
a = (pi * eval(input1.get())**2 * eval(input2.get())) / 3
elif ‘Surface’ in carry and ‘Cone’ in carry:
a = pi*eval(input1.get())*eval(input2.get())+ pi*eval(input1.get())**2
elif ‘Compound’ in carry and ‘Interest’ in carry and ‘Rate’ in carry:
p,fv,f,n = eval(input1.get()),eval(input2.get()),eval(input3.get()),eval(input4.get())
n = n * f
a = (((fv/p)**(1/n)) – 1) *f*100
elif ‘Compound’ in carry and ‘Interest’ in carry:
if input3.get() == “c”:
a = eval(input1.get()) * (e**((eval(input2.get())/100) * eval(input4.get())))
else:
p = eval(input1.get())
i = eval(input2.get())
f = eval(input3.get())
n = eval(input4.get())
a = p*((1 + (i/100) /f)**(f*n))
elif “Decay” in carry and “Time” in carry:
k,rem = (-log(2))/ eval(input1.get()),(eval(input2.get()))/100
a = (log(rem))/k
elif “Decay” in carry:
k = (-log(2))/ eval(input2.get())
a = eval(input1.get()) * (e**(k * eval(input3.get())))
elif “Hypot” in carry:
b = eval(input1.get())
c =  eval(input2.get())
a = hypot(b,c)
elif “Annuity” in carry and “Sum” in carry:
a = eval(input1.get()) * ((1 + eval(input2.get())/100) ** (eval(input3.get()) + 1)- 1) / (eval(input2.get())/100) – eval(input1.get())
elif “Annuity” in carry and “Addition” in carry:
r = eval(input2.get()) / 100
a = eval(input1.get()) / ((((1 + r) ** (eval(input3.get()) + 1) – 1) / r) – 1)
elif “Annuity” in carry and “Years” in carry:
r = (eval(input2.get()) / 100) + 0j
t = eval(input1.get()) + 0j
i = eval(input3.get()) + 0j
a =   (log((r * (t/i)) + (1 + r))) / log(1 + r)
elif “Mortgage” in carry:
r = eval(input2.get()) / 1200
t = eval(input3.get()) * 12
a = r * eval(input1.get()) / ( 1 – (1 + r) ** -t)
elif “Fibon” in carry:
lim = eval(input1.get())
y,x,z,a=0,1,0,0
b=””
while z < lim:
z = z + 1
b = ” ” + str(y)
y,x=x,x+y
text1.insert(END, b)
elif “Progress” in carry:
n,p,z,lim,a,x,c=0,0,0,0,0,0,0
b = “”
n = eval(input1.get())
c = n
x = n
p = eval(input2.get())
lim = eval(input3.get())
while z < lim:
z = z + 1
b =” ” + str(n)
text1.insert(END, b)
n = c**p + x
x = n
elif “Own” in carry:
a = eval(input1.get())
if abs(a – 0.00000000000) < .0000000001:
a = 0
if abs(a – .50000000000) < .0000000001:
a = .5
if abs(a – 1.00000000000) < .0000000001:
a = 1.0
if abs(a – 2.00000000000) < .0000000001:
a = 2.0
if abs(a – -.50000000000) < .0000000001:
a = -.5
if abs(a – 30.00000000000) < .0000000001:
a = 30.0
if abs(a – 45.00000000000) < .0000000001:
a = 45.0
if abs(a – 60.00000000000) < .0000000001:
a = 60.0
if abs(a – 90.00000000000) < .0000000001:
a = 90.0
if abs(a – 120.00000000000) < .0000000001 or abs(a – -60.00000000000) < .0000000001:
a = 120.0
if abs(a – 135.00000000000) < .0000000001:
a = 135.0
if abs(a – 150.00000000000) < .0000000001 or abs(a – -30.00000000000) < .0000000001:
a = 150.0
if abs(a – 180.00000000000) < .0000000001:
a = 180.0
if “general” in carry2:
a =  ‘{0:g}’.format(a)
elif “expon” in carry2:
a =  ‘{0:e}’.format(a)
elif “binary” in carry2:
a =  ‘{0:b}’.format(a)
elif “oct” in carry2:
a =  ‘{0:o}’.format(a)
elif “hex” in carry2:
a =  ‘{0:x}’.format(a)
elif “1 decimal” in carry2:
a = ‘{0:.1f}’.format(a)
elif “2 decimal” in carry2:
a = ‘{0:.2f}’.format(a)
elif “3 decimal” in carry2:
a = ‘{0:.3f}’.format(a)
elif “4 decimal” in carry2:
a = ‘{0:.4f}’.format(a)
elif “5 decimal” in carry2:
a = ‘{0:.5f}’.format(a)
elif “6 decimal” in carry2:
a = ‘{0:.6f}’.format(a)

text1.insert(0, str(a))

window = tkinter.Tk()
window.title(“GUI Calculator”)
window.geometry(“1200×480″)
text1 = tkinter.Entry(window, width=200)
input1 = tkinter.Entry(window, width=200)
input2 = tkinter.Entry(window, width=200)
input3 = tkinter.Entry(window, width=200)
input4 = tkinter.Entry(window, width=200)
list1 = tkinter.Listbox(window, height=’22’, width=”100″)
list2 = tkinter.Listbox(window, height=’22’, width=”100″)
b = Button(text=”Calculate”, width=’20’,command=callback)

text1.grid(row=0, columnspan=2)
input1.grid(row=1, columnspan=2)
input2.grid(row=2, columnspan=2)
input3.grid(row=3, columnspan=2)
input4.grid(row=4, columnspan=2)
list1.grid(row=5)
list2.grid(row=5, column=1)
b.grid(row=6, columnspan=2)
text1.insert(0,”Calculation Result”)
list1.insert(END, “Law of Cosines”)
for item in [“Law of Sines”, “Hypotenuse”, “Volume of Sphere”, “Surface of Sphere”, “Volume of Cylinder”, “Surface of Cylinder”, “Volume of Cone”, “Surface of Cone”, “Compound Interest”, “Compound Interest Rate”, “Decay”, “Decay Time”, “Annuity Sum”, “Annuity Addition”, “Annuity Years”, “Mortgage”, “Fibonacci Sequence”, “Sum of Progression”, “Own Formula”]:
list1.insert(END, item)
list1.bind(‘<ButtonRelease-1>’, get_list)
list2.insert(END, “general”)
for item in [“exponential”, “binary”, “octal”, “hex”, “1 decimal place”,”2 decimal places”,”3 decimal places”,”4 decimal places”,”5 decimal places”,”6 decimal places”]:
list2.insert(END, item)
list2.bind(‘<ButtonRelease-1>’, get_list2)
window.mainloop()

 

You can copy the code and save it as a py file (keeping in mind that the indentations have been removed in this code listing) or you can download the code as mentioned in this previous post:

Files For Download

Here is how the GUI appears:

Click image for larger view

CalcGUI

This is set up by the last section of code:

window = tkinter.Tk()
window.title(“GUI Calculator”)
window.geometry(“1200×480″)
text1 = tkinter.Entry(window, width=200)
input1 = tkinter.Entry(window, width=200)
input2 = tkinter.Entry(window, width=200)
input3 = tkinter.Entry(window, width=200)
input4 = tkinter.Entry(window, width=200)
list1 = tkinter.Listbox(window, height=’22’, width=”100″)
list2 = tkinter.Listbox(window, height=’22’, width=”100″)
b = Button(text=”Calculate”, width=’20’,command=callback)text1.grid(row=0, columnspan=2)
input1.grid(row=1, columnspan=2)
input2.grid(row=2, columnspan=2)
input3.grid(row=3, columnspan=2)
input4.grid(row=4, columnspan=2)
list1.grid(row=5)
list2.grid(row=5, column=1)
b.grid(row=6, columnspan=2)
text1.insert(0,”Calculation Result”)
list1.insert(END, “Law of Cosines”)
for item in [“Law of Sines”, “Hypotenuse”, “Volume of Sphere”, “Surface of Sphere”, “Volume of Cylinder”, “Surface of Cylinder”, “Volume of Cone”, “Surface of Cone”, “Compound Interest”, “Compound Interest Rate”, “Decay”, “Decay Time”, “Annuity Sum”, “Annuity Addition”, “Annuity Years”, “Mortgage”, “Fibonacci Sequence”, “Sum of Progression”, “Own Formula”]:
list1.insert(END, item)
list1.bind(‘<ButtonRelease-1>’, get_list)
list2.insert(END, “general”)
for item in [“exponential”, “binary”, “octal”, “hex”, “1 decimal place”,”2 decimal places”,”3 decimal places”,”4 decimal places”,”5 decimal places”,”6 decimal places”]:
list2.insert(END, item)
list2.bind(‘<ButtonRelease-1>’, get_list2)
window.mainloop()

 

When the type of calculation is selected, the parameters to be inputted are inserted, as in the following image:

Click image for larger view

GUI2

This is set up by carry.

Finally, when the parameters are inserted and the Calculate button is clicked, the calculation is performed and the result displayed in the top Entry control;

Click image for larger view

GUI3

The code for doing the calculations is:

def callback():
text1.delete(0, last=’end’)
if ‘Law’ in carry and ‘Cosines’ in carry:
b = eval(input1.get()) + 0j
c = eval(input2.get()) + 0j
cosa = eval(input3.get())
cosa = cos(radians(cosa)) + 0j
a = sqrt( (b**2 + c**2) – (2*b*c*cosa))
elif ‘Law’ in carry and ‘Sines’ in carry:
sinv1 = eval(input2.get())
sinv2 = eval(input3.get())
sinv1 = sin(radians(sinv1)) + 0j
sinv2 = sin(radians(sinv2)) + 0j
v2 = eval(input1.get())
a = v2 * (sinv2/sinv1)
elif ‘Volume’ in carry and ‘Sphere’ in carry:
a = eval(input1.get())
a = (pi * a ** 3) * (4/ 3)
elif ‘Surface’ in carry and ‘Sphere’ in carry:
a = eval(input1.get())
a = 4 * pi * a**2
elif ‘Volume’ in carry and ‘Cylinder’ in carry:
a = pi * eval(input1.get())**2 * eval(input2.get())
elif ‘Surface’ in carry and ‘Cylinder’ in carry:
a = 2 * pi * eval(input1.get())**2 +  2 * pi * eval(input1.get())  * eval(input2.get())
elif ‘Volume’ in carry and ‘Cone’ in carry:
a = (pi * eval(input1.get())**2 * eval(input2.get())) / 3
elif ‘Surface’ in carry and ‘Cone’ in carry:
a = pi*eval(input1.get())*eval(input2.get())+ pi*eval(input1.get())**2
elif ‘Compound’ in carry and ‘Interest’ in carry and ‘Rate’ in carry:
p,fv,f,n = eval(input1.get()),eval(input2.get()),eval(input3.get()),eval(input4.get())
n = n * f
a = (((fv/p)**(1/n)) – 1) *f*100
elif ‘Compound’ in carry and ‘Interest’ in carry:
if input3.get() == “c”:
a = eval(input1.get()) * (e**((eval(input2.get())/100) * eval(input4.get())))
else:
p = eval(input1.get())
i = eval(input2.get())
f = eval(input3.get())
n = eval(input4.get())
a = p*((1 + (i/100) /f)**(f*n))
elif “Decay” in carry and “Time” in carry:
k,rem = (-log(2))/ eval(input1.get()),(eval(input2.get()))/100
a = (log(rem))/k
elif “Decay” in carry:
k = (-log(2))/ eval(input2.get())
a = eval(input1.get()) * (e**(k * eval(input3.get())))
elif “Hypot” in carry:
b = eval(input1.get())
c =  eval(input2.get())
a = hypot(b,c)
elif “Annuity” in carry and “Sum” in carry:
a = eval(input1.get()) * ((1 + eval(input2.get())/100) ** (eval(input3.get()) + 1)- 1) / (eval(input2.get())/100) – eval(input1.get())
elif “Annuity” in carry and “Addition” in carry:
r = eval(input2.get()) / 100
a = eval(input1.get()) / ((((1 + r) ** (eval(input3.get()) + 1) – 1) / r) – 1)
elif “Annuity” in carry and “Years” in carry:
r = (eval(input2.get()) / 100) + 0j
t = eval(input1.get()) + 0j
i = eval(input3.get()) + 0j
a =   (log((r * (t/i)) + (1 + r))) / log(1 + r)
elif “Mortgage” in carry:
r = eval(input2.get()) / 1200
t = eval(input3.get()) * 12
a = r * eval(input1.get()) / ( 1 – (1 + r) ** -t)
elif “Fibon” in carry:
lim = eval(input1.get())
y,x,z,a=0,1,0,0
b=””
while z < lim:
z = z + 1
b = ” ” + str(y)
y,x=x,x+y
text1.insert(END, b)
elif “Progress” in carry:
n,p,z,lim,a,x,c=0,0,0,0,0,0,0
b = “”
n = eval(input1.get())
c = n
x = n
p = eval(input2.get())
lim = eval(input3.get())
while z < lim:
z = z + 1
b =” ” + str(n)
text1.insert(END, b)
n = c**p + x
x = n
elif “Own” in carry:
a = eval(input1.get())
if abs(a – 0.00000000000) < .0000000001:
a = 0
if abs(a – .50000000000) < .0000000001:
a = .5
if abs(a – 1.00000000000) < .0000000001:
a = 1.0
if abs(a – 2.00000000000) < .0000000001:
a = 2.0
if abs(a – -.50000000000) < .0000000001:
a = -.5
if abs(a – 30.00000000000) < .0000000001:
a = 30.0
if abs(a – 45.00000000000) < .0000000001:
a = 45.0
if abs(a – 60.00000000000) < .0000000001:
a = 60.0
if abs(a – 90.00000000000) < .0000000001:
a = 90.0
if abs(a – 120.00000000000) < .0000000001 or abs(a – -60.00000000000) < .0000000001:
a = 120.0
if abs(a – 135.00000000000) < .0000000001:
a = 135.0
if abs(a – 150.00000000000) < .0000000001 or abs(a – -30.00000000000) < .0000000001:
a = 150.0
if abs(a – 180.00000000000) < .0000000001:
a = 180.0
if “general” in carry2:
a =  ‘{0:g}’.format(a)
elif “expon” in carry2:
a =  ‘{0:e}’.format(a)
elif “binary” in carry2:
a =  ‘{0:b}’.format(a)
elif “oct” in carry2:
a =  ‘{0:o}’.format(a)
elif “hex” in carry2:
a =  ‘{0:x}’.format(a)
elif “1 decimal” in carry2:
a = ‘{0:.1f}’.format(a)
elif “2 decimal” in carry2:
a = ‘{0:.2f}’.format(a)
elif “3 decimal” in carry2:
a = ‘{0:.3f}’.format(a)
elif “4 decimal” in carry2:
a = ‘{0:.4f}’.format(a)
elif “5 decimal” in carry2:
a = ‘{0:.5f}’.format(a)
elif “6 decimal” in carry2:
a = ‘{0:.6f}’.format(a)

 

The output can be in several different bases and can be selected from the choices in the right column.

There is an update of this post

Files For Download

From time to time I have mentioned applications I have written that I have not been able to host on this site. I now have a site for hosting them and they are free to download.

the URL is:

http://sdsolemates.com

Some of the posts for which files can be downloaded are:

JavaScript scientific Calculator
Opening .pages files on a PC
A Simple Online HTML Editor
Create a Container to Place Your Open Windows in Tabs
A Small Archiving Application
Python and Java IDE
Send Bulk HTML EMails through Multiple GMail Accounts
Instantly Create an Online Book Album and Slide Show
Something Different – An Application to View 2D Videos in 3D

These include files written in c, python, android and html.

Go to sdsolemates.com, Click Downloads on the menu at the top, check the box at the bottom of the page and download  files. Some will need the installation of other files, but everything is available free of cost.

In the future I will be discussing other applications I have written and will be making them available for download.

ClipPaths – Interesting Slide Show Transitions Without Flash

clipPaths are SVG shapes that can be used as masks so that only the part of the screen that falls within the clipPath outline is visible.  With javascript they can be made dynamic, with interesting slide show transitions as a result.

First an example;  The video is a low fps animated gif that I made from a screen capture of the actual web page (the transition is smoother in the actual web page).

Click image for larger view

clip

Here is the code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>Enter Title Here</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal normal 12px Arial; white-space: pre-wrap}
a{ text-decoration: }
:link { color: rgb(0, 0, 255) }
:visited {color :rgb(100, 0,100) }
:hover { }
:active { }
svg{position: absolute; width: 100%; height: 100%; top: 0;left: 0}
</style>
<script type=’text/javascript’>
var si; var cnt = 0; var i = 0; var ang = 0; var px = new Array(); var py = new Array();  var px0 = 210; var py0 = 160; var pts = “”;
function direct() {si = setInterval(‘effect()’, 100); }
function effect() {
var el =document.getElementById(“ell”);
var polygon = document.getElementById(“ply”);
var im =document.getElementById(“im1”);
i += .005;
if (cnt % 2 == 0) {
im.setAttribute(“style”, “clip-path: url(#circularPath)”);
im.setAttribute(“xlink:href”, “Am1.jpg”);
el.setAttribute(“rx”, 4 * i );
el.setAttribute(“ry”, 3 * i );
} else {ang = parseInt(180/12);for (var j = 1;j <=12; j ++) {
var dx = px0 + 1200*i * (Math.sin( (j * 360/12 + ang) * (Math.PI/180)));
var dy = py0 + 900*i*  (Math.cos( (j * 360/12 + ang) * (Math.PI/180)));

if (j > 0) {
px[j] =parseInt(dx);
py[j] = parseInt(dy);
}

pts = pts +  px[j] + “,” + py[j] + ” ” ;
}
im.setAttribute(“style”, “clip-path: url(#polyPath)”);
im.setAttribute(“xlink:href”, “attachment3.jpg”);
polygon.setAttribute(“points”,pts);
}

if (i > .3) {
cnt ++;
i = 0;
}
pts = “”;
}
</script>
</head>
<body onload=’direct();’>
<svg xmlns=”http://www.w3.org/2000/svg&#8221; version=”1.1″ width=”” height= “”>

<defs>
<clipPath id=”polyPath” clipPathUnits=”userSpaceOnUse” >
<polygon id=”ply” points=” ” />
</clipPath>
<clipPath id=”circularPath” clipPathUnits=”objectBoundingBox” >
<ellipse id = “ell” cx=”0.5″ cy=”0.5″ rx=”” ry=”” />
</clipPath>
</defs>

<image id = “im1″  x=”20″ y=”20″ width=”400″ height=”300″ xlink:href=”” style=”” />
</svg>
</body></html>

 

An  SVG object is created and one or more clipPaths are defined.

<defs>
<clipPath id=”polyPath” clipPathUnits=”userSpaceOnUse” >
<polygon id=”ply” points=” ” />
</clipPath>
<clipPath id=”circularPath” clipPathUnits=”objectBoundingBox” >
<ellipse id = “ell” cx=”0.5″ cy=”0.5″ rx=”” ry=”” />
</clipPath>
</defs>

In this case I defined two, an ellipse and a dodecagon.

A javascript timer is started to perform the transition

<body onload=’direct();’>
function direct() {si = setInterval(‘effect()’, 100); }

SetAttribute is used to set the clipPath, image and the size of the  clipPath outline.  In this case the ellipse.

im.setAttribute(“style”, “clip-path: url(#circularPath)”);
im.setAttribute(“xlink:href”, “Am1.jpg”);
el.setAttribute(“rx”, 4 * i );
el.setAttribute(“ry”, 3 * i );

For the dodecagon, it is the following:

else {ang = parseInt(180/12);

for (var j = 1;j <=12; j ++) {
var dx = px0 + 1200*i * (Math.sin( (j * 360/12 + ang) * (Math.PI/180)));
var dy = py0 + 900*i*  (Math.cos( (j * 360/12 + ang) * (Math.PI/180)));

if (j > 0) {
px[j] =parseInt(dx);
py[j] = parseInt(dy);
}

pts = pts +  px[j] + “,” + py[j] + ” ” ;
}
im.setAttribute(“style”, “clip-path: url(#polyPath)”);
im.setAttribute(“xlink:href”, “attachment3.jpg”);
polygon.setAttribute(“points”,pts);

Counters are incremented to determine which set of masks and images to use and to size the masks.

i += .005;

if (i > .3) {
cnt ++;
i = 0;
}

In this case I reset the counter after two and used the modulus to alternate between the two clipped images, but  any number of clipPaths and images can be used, to make a complete slide show with varying transitions.

Single Image, No Glasses, 3D Videos

In the previous post I discussed a single image, no glasses, 3d image viewer. The same technique can be used to produce 3d videos.

Below are a couple of examples:

tennis

city

The following is the code for a viewer:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>Enter Title Here</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal 800 18px Arial; background: black; color: white}
a{ text-decoration: none}
:link { color: rgb(255, 255, 255) }
:visited {color :rgb(255, 255,255) }
:hover { }
:active { }
img{ border: 1px solid black; height: 100%;}
#layer1 {position: absolute; top: 30%;  height: 40%; width: 100%;  padding: 0; text-align: center }
#up {position: absolute; top: 1%;  width: 2%; left: 92%; padding: 0; text-align: center}
#down {position: absolute; top: 1%;  width: 2%; left: 94%; padding: 0; text-align: center}
</style>
</head>
<body onLoad=’direct1();’>
<div id=”layer1″></div>
<div id=”up”><a href=”#2″ onclick=”bigger();”>+</div>
<div id=”down”><a href=”#2″ onclick=”smaller();”>-</div>
<script type=’text/javascript’>
document.onkeyup=resize;
pic = new Array; var cntr = 0; var tot =24;pic[1] =”left1.jpg”;
pic[2] =”right1.jpg”;
pic[3] =”left2.jpg”;
pic[4] =”right2.jpg”;
pic[5] =”left3.jpg”;
pic[6] =”right3.jpg”;
pic[7] =”left4.jpg”;
pic[8] =”right4.jpg”;
pic[9] =”left5.jpg”;
pic[10] =”right5.jpg”;
pic[11] =”left6.jpg”;
pic[12] =”right6.jpg”;
pic[13] =”left7.jpg”;
pic[14] =”right7.jpg”;
pic[15] =”left8.jpg”;
pic[16] =”right8.jpg”;
pic[17] =”left9.jpg”;
pic[18] =”right9.jpg”;
pic[19] =”left10.jpg”;
pic[20] =”right10.jpg”
pic[21] =”left11.jpg”;
pic[22] =”right11.jpg”;
pic[23] =”left12.jpg”;
pic[24] =”right12.jpg”;
pic[25] =”left13.jpg”;
pic[26] =”right13.jpg”
pic[27] =”left14.jpg”;
pic[28] =”right14.jpg”document.getElementById(‘layer1’).style.height = “40%”;
document.getElementById(‘layer1’).style.top = “30%”;
var ht =document.getElementById(‘layer1’).style.height;
var tp =document.getElementById(‘layer1’).style.top;
function direct1() {setInterval(“showslides1()”, 100); }
function showslides1 () {
cntr += 1; document.getElementById(‘layer1′).innerHTML='<Img SRC=’ + pic[cntr] + ‘ alt=” ” />’;
if (cntr == tot) {cntr = 0;}}
function resize(e) {
ht = parseInt(ht);
tp = parseInt(tp);if (e.keyCode == 40) {
ht  = (ht – 2).toString() + “%”;
tp  = (tp + 1).toString() + “%”;
} else if (e.keyCode == 38) {
ht = (ht + 2).toString() + “%”;
tp  = (tp – 1).toString() + “%”;
}
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
function bigger() {
ht = parseInt(ht);
tp = parseInt(tp);
ht = (ht + 2).toString() + “%”;
tp  = (tp – 1).toString() + “%”;
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
function smaller() {
ht = parseInt(ht);
tp = parseInt(tp);
ht = (ht – 2).toString() + “%”;
tp  = (tp + 1).toString() + “%”;
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
</script>
</body></html>

 

It is similar to the previous viewer, but only one cycling number is used, the total number of frames. The video size can be adjusted either with the up and down arrows or the + and – icons. The size of the picture can be adjusted to maximize the effect.

Since, I can not upload html pages to this site, the examples above are animated gifs created from the frames.

To see the viewer in practice go to this site and choose “3D Single Image Videos” from “Show Menus”.

It is also possible to make the frames into a standard video format, to be played by a multimedia player.

The 3d conversion was done with GIMP as described in the link above. It must be done frame by frame and as such, is labor intensive, making it better for generating clips to be shown on a website than for entire movies. In reality, it is no more labor intensive than producing an animated movie. The procedure is not amenable to automaton, as the depthmap for each frame must be custom made.

There might be a way to automate the effect generation.  One way would be to shoot the video in 3d with an extremely small separation between the two lenses and convert the right and left views to alternate frames. The other method would be to shoot the the video in 2d at a very high frame rate, or to shoot a panorama at a very low can rate. The frames would than be assembled 2;1, 4;3, 6:5. etc. This would be the only way to eliminate excessive jerkiness in the video. A script could possibly be written to automate the frame assembly from either of the two filming methods described.

I think a method for displaying 3d videos without the need for glasses, a special screen or to strain to fuse side by side views is a significant advance.

Animated JPEG – A Viewer for 3D Animation

Animated GIF files can be used for simulating 3D in a procedure known as wiggle of wobble 3D. However, GIF has the limitation of being restricted to a maximum of 256 colors. Sometimes this is not bad, as it gives a sort of illustrated appearance, but often you want more realism. There is also a thing called Animated PNG, which is very nice, but is supported only by Firefox, Opera and related browsers. This post describes a viewer for JPG Animation.

Let me start by saying there is no such thing as an Animated JPG file. The animation is simulated by alternately showing the left and right images, by means of javascript. I have written the code for a simple viewer. Below is the code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>Enter Title Here</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal 800 18px Arial; background: black; color: white}
a{ text-decoration: none}
:link { color: rgb(255, 255, 255) }
:visited {color :rgb(255, 255,255) }
:hover { }
:active { }
img{ border: 1px solid black; height: 100%;}
#layer1 {position: absolute; top: 5%;  height: 90%; width: 100%;  padding: 0; text-align: center }
#next {position: absolute; top: 1%;  width: 2%;  left: 98%; padding: 0; text-align: center}
#back {position: absolute; top: 1%;  width: 2%; left: 96%; padding: 0; text-align: center}
#up {position: absolute; top: 1%;  width: 2%; left: 92%; padding: 0; text-align: center}
#down {position: absolute; top: 1%;  width: 2%; left: 94%; padding: 0; text-align: center}
</style>
</head>
<body onLoad=’direct1();’>
<div id=”layer1″></div>
<div id=”next”><a href=”#2″ onclick=”toNext();”>></div>
<div id=”back”><a href=”#2″ onclick=”goBack();”><</div>
<div id=”up”><a href=”#2″ onclick=”bigger();”>+</div>
<div id=”down”><a href=”#2″ onclick=”smaller();”>-</div>
<script type=’text/javascript’>
document.onkeyup=resize;
pic = new Array; var cntr = 0; var tot =1;tot += 1;pic[1] =”left.jpg”;
pic[2] =”right.jpg”;
pic[3] =”left2.jpg”;
pic[4] =”right2.jpg”;
pic[5] =”left3.jpg”;
pic[6] =”right3.jpg”;
pic[7] =”left4.jpg”;
pic[8] =”right4.jpg”;
pic[9] =”left5.jpg”;
pic[10] =”right5.jpg”;
var total = 10;
document.getElementById(‘layer1’).style.height = “90%”;
document.getElementById(‘layer1’).style.top = “5%”;
var ht =document.getElementById(‘layer1’).style.height;
var tp =document.getElementById(‘layer1’).style.top;
function direct1() {setInterval(“showslides1()”, 30); }
function showslides1 () {
cntr += 1; document.getElementById(‘layer1′).innerHTML='<Img SRC=’ + pic[cntr] + ‘ alt=” ” />’;
if (cntr == tot) {cntr -=2;}}
function resize(e) {
ht = parseInt(ht);
tp = parseInt(tp);if (e.keyCode == 39) {
cntr += 2;
tot += 2;
if (tot > total) {
cntr = 0;
tot = 2;
}
} else if (e.keyCode == 37) {
cntr -= 2;
tot -= 2;
if (cntr < 0) {
cntr = total – 2;
tot = total;
}
}if (e.keyCode == 40) {
ht  = (ht – 2).toString() + “%”;
tp  = (tp + 1).toString() + “%”;
} else if (e.keyCode == 38) {
ht = (ht + 2).toString() + “%”;
tp  = (tp – 1).toString() + “%”;
}
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
function toNext() {
cntr += 2;
tot += 2;
if (tot > total) {
cntr = 0;
tot = 2;
}
}
function goBack() {
cntr -= 2;
tot -= 2;
if (cntr < 0) {
cntr = total – 2;
tot = total;
}
}
function bigger() {
ht = parseInt(ht);
tp = parseInt(tp);
ht = (ht + 2).toString() + “%”;
tp  = (tp – 1).toString() + “%”;
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
function smaller() {
ht = parseInt(ht);
tp = parseInt(tp);
ht = (ht – 2).toString() + “%”;
tp  = (tp + 1).toString() + “%”;
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}
</script>
</body></html>

 

An array of left and right views is created:
pic[1] =”left.jpg”;
pic[2] =”right.jpg”;
pic[3] =”left2.jpg”;
pic[4] =”right2.jpg”;
pic[5] =”left3.jpg”;
pic[6] =”right3.jpg”;
pic[7] =”left4.jpg”;
pic[8] =”right4.jpg”;
pic[9] =”left5.jpg”;
pic[10] =”right5.jpg”;
and a variable, total is created with the number of the highest array index:
var total = 10;

A function  direct1() calls another function  showslides1 () at 30 millisecond intervals.

function direct1() {setInterval(“showslides1()”, 30); }

The contents of a division are dynamically replaced with the images:

document.getElementById(‘layer1′).innerHTML='<Img SRC=’ + pic[cntr] + ‘ alt=” ” />’;

cntr is an incremented variable which determines the index of the image array to be displayed. Another variable, tot  sets that one right and left pair of images at a time is shown:

if (cntr == tot) {cntr -=2;}

The picture displayed can be cycled with the right and left keys:

document.onkeyup=resize;

if (e.keyCode == 39) {
cntr += 2;
tot += 2;
if (tot > total) {
cntr = 0;
tot = 2;
}
} else if (e.keyCode == 37) {
cntr -= 2;
tot -= 2;
if (cntr < 0) {
cntr = total – 2;
tot = total;
}
}

If you go past the last set of images, the images are recycled, either up or down.

For mobile devices without a keyboard, a control panel in the upper right corner has right and left arrows to do the same thing.

The up and down keys enlarge or reduce the image:

if (e.keyCode == 40) {
ht  = (ht – 2).toString() + “%”;
tp  = (tp + 1).toString() + “%”;
} else if (e.keyCode == 38) {
ht = (ht + 2).toString() + “%”;
tp  = (tp – 1).toString() + “%”;
}
document.getElementById(‘layer1’).style.height = ht;
document.getElementById(‘layer1’).style.top = tp;
}

This is reproduced in mobile devices with the + and – symbols.

If you want to see it in action, go to this link , click on “Show Menus” and choose “3D Animated JPEG”.

If want to try it, copy the code, create a html file and include the following stereo pairs in the same folder. It will be necessary to rename the downloaded files:

Click images for larger view and save to add to viewer

left right

left3 right3

left7

right7

left8

right8

left9

right9

These stereo pairs are simulated with the procedure described in an earlier post link . I find this works better than using an actual photographed stereo pair. Using GIMP, I created a depth map and used the displace filter with settings of 0 Y displacement, -1 X displacement and Smear.