is shown in Listing 16-9.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Line, Ellipse, Color
from kivy.clock import Clock
from kivy.core.image import Image as CoreImage
from PIL import Image, ImageDraw, ImageFont
import io
import os
import numpy as np
from kivy.lang import Builder
Builder.load_file(
os.path.join(os.path.dirname(os.path.abspath(
__file__)), 'File.kv')
);
#Avoid Form1 of being resizable
from kivy.config import Config
Config.set("graphics","resizable", False);
Config.set('graphics', 'width', '480');
Config.set('graphics', 'height', '680');
D=600;
VX1=-15; VY1=0; VZ1=0;
VX2=15; VY2=0; VZ2=0;
P=0.0; #Place the function at z=D/2
N=40; #Number of pixels to represent the function
y1A=np.zeros( (N+1,N+1) );
y1B=np.zeros( (N+1,N+1) );
x1A=np.zeros( (N+1,N+1) );
x1B=np.zeros( (N+1,N+1) );
z1A=np.zeros( (N+1,N+1) ); #Mesh
z1B=np.zeros( (N+1,N+1) ); #Mesh
XG0=0; ZG0=P*D;
a=10; b=9; c=9;
Pi=np.pi;
Theta0=Pi/180*(40);
Phi=np.zeros(N+1);
ThetaA=np.zeros(N+1); rA=np.zeros( (N+1,N+1) );
ThetaB=np.zeros(N+1); rB=np.zeros( (N+1,N+1) );
for n in range(0,N+1):
ThetaA[n]=n/N*Theta0; #from 0 to Theta0
ThetaB[n]=n/N*Theta0 +Pi; #from Pi to(Pi+Theta0)
Phi0=Pi/180*360
for n in range(0,N+1):
Phi[n]=(n-N/2)/N*Phi0;
for n in range(0,N+1):
for m in range(0,N+1):
rA[n][m]=1/np.sqrt( (np.cos(ThetaA[n])/a)**2
-(np.sin(ThetaA[n])*np.sin(Phi[m])/b)**2
-(np.sin(ThetaA[n])*np.cos(Phi[m])/c)**2 );
rB[n][m]=1/np.sqrt( (np.cos(ThetaB[n])/a)**2
-(np.sin(ThetaB[n])*np.sin(Phi[m])/b)**2
-(np.sin(ThetaB[n])*np.cos(Phi[m])/c)**2 );
L=5;
for n in range (0,N+1):
for m in range(0,N+1):#Filling MeshA
x1A[n][m]=L*rA[n][m]*np.sin(ThetaA[n])*
np.cos(Phi[m]);
z1A[n][m]=L*rA[n][m]*np.sin(ThetaA[n])*
np.sin(Phi[m])+ZG0;
y1A[n][m]=L*rA[n][m]*np.cos(ThetaA[n]);
for n in range (0,N+1):
for m in range(0,N+1):#Filling MeshB
x1B[n][m]=L*rB[n][m]*np.sin(ThetaB[n])
*np.cos(Phi[m]);
z1B[n][m]=L*rB[n][m]*np.sin(ThetaB[n])
*np.sin(Phi[m])+ZG0;
y1B[n][m]=L*rB[n][m]*np.cos(ThetaB[n]);
PointList=np.zeros( (N+1,2) );
def GraphFunction(VX,VY,VZ,Which):
if (Which==0):
r,g,b = 200, 0, 0; #red Image
Draw=Draw1
else:
r,g,b= 0, 200, 200; #cyan image
Draw=Draw2
#Drawing surface A
for n in range (0,N+1): #Horizontal Lines A
for m in range (0,N+1):
Factor=(D-VZ)/(D-z1A[n][m]-VZ);
xA=XC+Factor*(x1A[n][m]-VX)+VX;
yA=YC-Factor*(y1A[n][m]-VY)-VY;
PointList[m]=xA,yA;
List=tuple( map(tuple,PointList) );
Draw.line( List, fill=(r,g,b), width=2 );
for n in range (0,N+1): #Vertical Lines A
for m in range (0,N+1):
Factor=(D-VZ)/(D-z1A[m][n]-VZ);
xA=XC+Factor*(x1A[m][n]-VX)+VX;
yA=YC-Factor*(y1A[m][n]-VY)-VY;
PointList[m]=xA,yA;
List=tuple( map(tuple,PointList) );
Draw.line( List, fill=(r,g,b), width=2 );
#Drawing surface B
for n in range (0,N+1): #Horizontal Lines B
for m in range (0,N+1):
Factor=(D-VZ)/(D-z1B[n][m]-VZ);
xA=XC+Factor*(x1B[n][m]-VX)+VX;
yA=YC-Factor*(y1B[n][m]-VY)-VY;
PointList[m]=xA,yA;
List=tuple( map(tuple,PointList) );
Draw.line( List, fill=(r,g,b), width=2 );
for n in range (0,N+1): #Vertical Lines B
for m in range (0,N+1):
Factor=(D-VZ)/(D-z1B[m][n]-VZ);
xA=XC+Factor*(x1B[m][n]-VX)+VX;
yA=YC-Factor*(y1B[m][n]-VY)-VY;
PointList[m]=xA,yA;
List=tuple( map(tuple,PointList) );
Draw.line( List, fill=(r,g,b), width=2 );
Font = ImageFont.truetype('Gargi.ttf', 40);
Draw1.text( (10,10), "3D", fill =
(255,0,0,1),font=Font);
Draw2.text( (30,10), "3D", fill =
(0,255,255,1), font=Font);
def ShowScene(B):
Array1=np.array(PilImage1);
Array2=np.array(PilImage2);
Array3=Array1 | Array2;
PilImage3=Image.fromarray(Array3);
Memory=io.BytesIO();
PilImage3.save(Memory, format="png");
Memory.seek(0);
ImagePNG=CoreImage(Memory, ext="png");
B.ids.Screen1.texture=ImagePNG.texture;
ImagePNG.remove_from_cache()
Memory.close();
PilImage3.close();
Array1=None;
Array2=None;
Array3=None;
def ClearObjects():
Draw1.rectangle( (0, 0, W-10, H-10), fill=
(60, 70, 30, 1) );
Draw2.rectangle( (0, 0, W-10, H-10), fill=
(60, 70, 30, 1) );
def RotateFunction(B, Sense):
global XG0, ZG0
if Sense==-1:
Teta=np.pi/180*(-4.0);
else:
Teta=np.pi/180*(4.0);
Cos_Teta=np.cos(Teta)
Sin_Teta=np.sin(Teta);
X0=XG0; Y0=0; Z0=ZG0 # Center of rotation
for n in range(0,N+1):
for m in range(0,N+1):
if (B.ids.Button3.state=="down" or
B.ids.Button4.state=="down"):
yP=(y1A[n][m]-Y0)*Cos_Teta
+ (x1A[n][m]-X0)*Sin_Teta + Y0;
xP=-(y1A[n][m]-Y0)*Sin_Teta
+(x1A[n][m]-X0)*Cos_Teta + X0;
y1A[n][m]=yP;
x1A[n][m]=xP;
yP=(y1B[n][m]-Y0)*Cos_Teta
+ (x1B[n][m]-X0)*Sin_Teta + Y0;
xP=-(y1B[n][m]-Y0)*Sin_Teta
+(x1B[n][m]-X0)*Cos_Teta + X0;
y1B[n][m]=yP;
x1B[n][m]=xP;
if (B.ids.Button5.state=="down" or
B.ids.Button6.state=="down"):
yP=(y1A[n][m]-Y0)*Cos_Teta
+ (z1A[n][m]-Z0)*Sin_Teta + Y0;
zP=-(y1A[n][m]-Y0)*Sin_Teta
+(z1A[n][m]-Z0)*Cos_Teta + Z0;
y1A[n][m]=yP;
z1A[n][m]=zP;
yP=(y1B[n][m]-Y0)*Cos_Teta
+ (z1B[n][m]-Z0)*Sin_Teta + Y0;
zP=-(y1B[n][m]-Y0)*Sin_Teta
+(z1B[n][m]-Z0)*Cos_Teta + Z0;
y1B[n][m]=yP;
z1B[n][m]=zP;
if (B.ids.Button7.state=="down" or
B.ids.Button8.state=="down"):
xP=(x1A[n][m]-X0)*Cos_Teta
+ (z1A[n][m]-Z0)*Sin_Teta + X0;
zP=-(x1A[n][m]-X0)*Sin_Teta
+(z1A[n][m]-Z0)*Cos_Teta + Z0;
x1A[n][m]=xP;
z1A[n][m]=zP;
xP=(x1B[n][m]-X0)*Cos_Teta
+ (z1B[n][m]-Z0)*Sin_Teta + X0;
zP=-(x1B[n][m]-X0)*Sin_Teta
+(z1B[n][m]-Z0)*Cos_Teta + Z0;
x1B[n][m]=xP;
z1B[n][m]=zP;
class Form1(FloatLayout):
def __init__(Handle, **kwargs):
super(Form1, Handle).__init__(**kwargs);
Event1=Clock.schedule_once(Handle.Initialize);
def Initialize(B, *args):
global W,H, XC,YC;
global PilImage1,PilImage2, Draw1,Draw2;
# P= Percentage of the D distance
global P, Amplitude;
W,H=B.ids.Screen1.size;
XC=int (W/2)+P/(1-P)*VX1+0;
YC=int(H/2)-P/(1-P)*VY1+10;
PilImage1= Image.new('RGB', (W-10, H-10),
(60, 70, 30));
Draw1 = ImageDraw.Draw(PilImage1);
PilImage2= Image.new('RGB', (W-10, H-10),
(60, 70, 30));
Draw2 = ImageDraw.Draw(PilImage2);
Font = ImageFont.truetype('Gargi.ttf', 70)
Draw1.text( (30,200), "3D Images", fill =
(255,0,0,1), font=Font);
Draw2.text( (50,200), "3D Images", fill =
(0,255,255,1), font=Font);
ShowScene(B);
def Button1_Click(B):
global Draw1, Draw2;
ClearObjects(); # Clearing Draw1 and Draw2
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button2_Click(B):
ClearObjects(); # Clearing Draw1 and Draw2
Font = ImageFont.truetype('Gargi.ttf', 70)
Draw1.text( (30,200), "3D Images", fill =
(255,0,0,1), font=Font);
Draw2.text( (50,200), "3D Images", fill =
(0,255,255,1), font=Font);
ShowScene(B);
def Button3_Click(B):
RotateFunction(B,1);
ClearObjects(); # Clearing Draw1 and Draw2
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button4_Click(B):
RotateFunction(B,-1),
ClearObjects();
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button5_Click(B):
RotateFunction(B,-1),
ClearObjects();
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button6_Click(B):
RotateFunction(B,1),
ClearObjects();
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button7_Click(B):
RotateFunction(B,-1),
ClearObjects();
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
def Button8_Click(B):
RotateFunction(B,1),
ClearObjects();
GraphFunction(VX1,VY1,VZ1,0);
GraphFunction(VX2,VY2,VZ2,1);
ShowScene(B);
# This is the Start Up code.
class StartUp (App):
def build (BU):
BU.title="Form1"
return Form1();
if __name__ =="__main__":
StartUp().run();
Listing 16-9main.py (for the Hyperboloid)