I am struggling to numerically solve Newton's equation for gravity using scipy.integrate.solve_ivp. I can get the coding working when one of the bodies is assumed stationary. However as shown in the picture when I use the code below where I am trying to account for the force of the sun on Jupiter and that of Jupiter on the sun, the suns orbit is not correct. It doesn't seem to wobble but instead just heads off away from the COM.
G = 6.67408e-11
msun = 1988500e24
m_jupiter = 1898.13e24
x_pos_j = 2.939022030646856E+00*au
y_pos_j = -4.169544536356319E+00*au
z_pos_j = -4.843813063988785E-02*au
x_vel_j = 6.083727195546033E-03*v_factor
y_vel_j = 4.708328571996785E-03*v_factor
z_vel_j = -1.556609498459863E-04*v_factor
def f_grav(t, y):
x1, x2, x3, v1, v2, v3 = y
# x1_star, x2_star, x3_star = x_other
dydt = [v1,
v2,
v3,
-(x1-x1_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2),
-(x2-x2_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2),
-(x3-x3_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2)]
return dydt
x_jupiter = np.array([x_pos_j, y_pos_j, z_pos_j])
x_sun = np.array([0, 0, 0])
v_sun = np.array([0, 0, 0])
tStart = 0e0
t_End = 20*year
dt = t_End/3000
# minstep = dt/100
domain = (tStart, dt)
temp_end = dt
x1_star, x2_star, x3_star = [0, 0, 0]
init_j = [x_pos_j, y_pos_j, z_pos_j, x_vel_j, y_vel_j, z_vel_j]
init_sun = [20, -20, 20, 15, -15, 0]
while tStart < t_End:
m=msun
ans_j = solve_ivp(fun=f_grav, t_span=domain, y0=init_j)
x1_star, x2_star, x3_star = ans_j['y'][0:3, -1]
v1_star, v2_star, v3_star = ans_j['y'][3:6, -1]
x_jupiter = np.vstack((x_jupiter, (ans_j['y'][0:3, -1])))
init_j = [x1_star, x2_star, x3_star, v1_star, v2_star, v3_star]
# print(init_j[0:3])
m=m_jupiter
ans_sun = solve_ivp(fun=f_grav, t_span=domain, y0=init_sun)
x1_star, x2_star, x3_star = ans_sun['y'][0:3, -1]
v1_star, v2_star, v3_star = ans_sun['y'][3:6, -1]
v_sun = np.vstack((v_sun, (ans_sun['y'][3:6, -1])))
x_sun = np.vstack((x_sun, (ans_sun['y'][0:3, -1])))
init_sun = [x1_star, x2_star, x3_star, v1_star, v2_star, v3_star]
tStart += dt
temp_end = tStart + dt
domain = (tStart,temp_end)
plt.plot(x_jupiter[:,0], x_jupiter[:,1])
plt.plot(x_sun[:,0], x_sun[:,1])
plt.show()
In the code at any given moment to solve the equation I assume that the other star is stationary but only for dt, which I don't think should effect the results. Is this why my plots are wrong and if so how can I better solve the equation when both bodies are moving. The orbit of Jupiter (blue on right image) looks more less correct but not that of the sun (on both images and is orange).
Related
Can I somehow pass variables from dictionaries into the functions inside of solve_ivp,
such that I can call them directly, i.e. offFSH instead of para_dict["offFSH"] ?
I think that this would be better for readability, but please let me know if my current/another version would be preferable.
Please don't pay attention to the model/equations itself, I took it from a much larger model I want to simulate, hence my desire to organize variables with dictionaries.
Thanks!
from scipy.integrate import solve_ivp
def simulate_model(simu_dict, para_dict):
tspan = [0, simu_dict["simulationLength"]]
InitialValues = [simu_dict["FSHR_init"], simu_dict["FSHR_complex_init"], simu_dict["LHR_init"], simu_dict["LHR_complex_init"]]
result = solve_ivp(fun = lambda t, y: func(t,y, para_dict), t_span = tspan, y0 = InitialValues, method = "RK45", dense_output = True)
return result
def func(t, y, para_dict):
FSHR = 0
FSHR_complex = 1
LHR = 2
LHR_complex = 3
dFSHR = para_dict["offFSH"] * y[FSHR_complex] - para_dict["onFSH"] * y[FSHR_complex]
dFSHR_complex = para_dict["onFSH"] * y[FSHR] - para_dict["offFSH"] * y[FSHR_complex]
dLHR = para_dict["offLH"] * y[LHR_complex] - para_dict["onLH"] * y[LHR]
dLHR_complex = para_dict["onLH"] - para_dict["offLH"] * y[LHR_complex]
dy = [dFSHR,dFSHR_complex,dLHR, dLHR_complex]
return dy
###########################################################################################
simu_dict = {
"FSHR_init": 0.7,
"FSHR_complex_init": 0.9,
"LHR_init": 1.8,
"LHR_complex_init": 6.2,
"simulationLength": 2
}
para_dict = {
"onFSH": 1,
"offFSH": 5,
"onLH": 1,
"offLH": 1,
}
test = simulate_model(simu_dict, para_dict)
I pretty much deleted the last code and started new. I added a new class called Object which is the replacement for the lists called body_1 and body_2. Also all the calculations are now done from within the Object class. Most previous existing issues were resolved through this process but there is still one that presists. I believe its inside the StartVelocity() function which creates the v1/2 needed to start the Leapfrog algorithm. This should give me a geostationary Orbit but as clearly visible the Satelite escapes very quickly after zooming through earth.
Codes are:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from object import Object
import numpy as np
class Simulation:
def __init__(self):
# Index: 0 Name, 1 Position, 2 Velocity, 3 Mass
body_1 = Object("Earth", "g", "r",
np.array([[0.0], [0.0], [0.0]]),
np.array([[0.0], [0.0], [0.0]]),
5.9722 * 10**24)
body_2 = Object("Satelite", "b", "r",
np.array([[42164.0], [0.0], [0.0]]),
np.array([[0.0], [3075.4], [0.0]]),
5000.0)
self.bodies = [body_1, body_2]
def ComputePath(self, time_limit, time_step):
time_range = np.arange(0, time_limit, time_step)
for body in self.bodies:
body.StartVelocity(self.bodies, time_step)
for T in time_range:
for body in self.bodies:
body.Leapfrog(self.bodies, time_step)
def PlotObrit(self):
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for body in self.bodies:
body.ReshapePath()
X, Y, Z = [], [], []
for position in body.path:
X.append(position[0])
Y.append(position[1])
Z.append(position[2])
ax.plot(X, Y, Z, f"{body.linecolor}--")
for body in self.bodies:
last_pos = body.path[-1]
ax.plot(last_pos[0], last_pos[1], last_pos[2], f"{body.bodycolor}o", label=body.name)
ax.set_xlabel("x-Axis")
ax.set_ylabel("y-Axis")
ax.set_zlabel("z-Axis")
ax.legend()
fig.savefig("Leapfrog.png")
if __name__ == "__main__":
sim = Simulation()
sim.ComputePath(0.5, 0.01)
sim.PlotObrit()
import numpy as np
class Object:
def __init__(self, name, bodycolor, linecolor, pos_0, vel_0, mass):
self.name = name
self.bodycolor = bodycolor
self.linecolor = linecolor
self.position = pos_0
self.velocity = vel_0
self.mass = mass
self.path = []
def StartVelocity(self, other_bodies, time_step):
force = self.GetForce(other_bodies)
self.velocity += (force / self.mass) * time_step * 0.5
def Leapfrog(self, other_bodies, time_step):
self.position += self.velocity * time_step
self.velocity += (self.GetForce(other_bodies) / self.mass) * time_step
self.path.append(self.position.copy())
def GetForce(self, other_bodies):
force = 0
for other_body in other_bodies:
if other_body != self:
force += self.Force(other_body)
return force
def Force(self, other_body):
G = 6.673 * 10**-11
dis_vec = other_body.position - self.position
dis_mag = np.linalg.norm(dis_vec)
dir_vec = dis_vec / dis_mag
for_mag = G * (self.mass * other_body.mass) / dis_mag**2
for_vec = for_mag * dir_vec
return for_vec
def ReshapePath(self):
for index, position in enumerate(self.path):
self.path[index] = position.reshape(3).tolist()
Im aware that Body 2's position has to be multiplied by 1000 to get meters but it would just fly in a straight line if i would do that and there would be no signs of gravitational forces what so ever.
The constant G is in kg-m-sec units. The radius of the satellite orbit however only makes sense in km, else the orbit would be inside the Earth core. Then the speed in m/sec gives a near circular orbit with negligible eccentricity. (Code from a math.SE question on Kepler law quantities)
import math as m
G = 6.673e-11*1e-9 # km^3 s^-2 kg^-1
M_E = 5.9722e24 # kg
R_E = 6378.137 # km
R_sat = 42164.0 # km from Earth center
V_sat = 3075.4/1000 # km/s
theta = 0
r0 = R_sat
dotr0 = V_sat*m.sin(theta)
dotphi0 = -V_sat/r0*m.cos(theta)
R = (r0*V_sat*m.cos(theta))**2/(G*M_E)
wx = R/r0-1; wy = -dotr0*(R/(G*M_E))**0.5
E = (wx*wx+wy*wy)**0.5; psi = m.atan2(wy,wx)
T = m.pi/(G*M_E)**0.5*(R/(1-E*E))**1.5
print(f"orbit constants R={R} km, E={E}, psi={psi} rad")
print(f"above ground: min={R/(1+E)-R_E} km, max={R/(1-E)-R_E} km")
print(f"T={2*T} sec, {T/1800} h")
with output
orbit constants R=42192.12133271948 km, E=0.0006669512550867562, psi=-0.0 rad
above ground: min=35785.863 km, max=35842.14320159004 km
T=86258.0162673565 sec, 23.960560074265697 h
for r(phi)=R/(1+E*cos(phi-psi))
Implementing these changes in your code and calling with
sim.ComputePath(86e+3, 600.0)
gives a nice circular orbit
I want to be able to lock the angle of the wheels relative to the car's chassis. In between the wheels, there are springs, that should allow the car to suspend, but right now, the angle is not locked. I am using pymunk's function "RotaryLimitJoint"
A behavior like this is the goal (gif)
Right now it looks like this:
My code:
car_pos = Vec2d(100,500)
mass = 30
radius = 10
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel1_b = pymunk.Body(mass, moment)
wheel1_s = pymunk.Circle(wheel1_b, radius)
wheel1_s.friction = 1.5
wheel1_s.color = wheel_color
space.add(wheel1_b, wheel1_s)
mass = 30
radius = 10
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel2_b = pymunk.Body(mass, moment)
wheel2_s = pymunk.Circle(wheel2_b, radius)
wheel2_s.friction = 1.5
wheel2_s.color = wheel_color
space.add(wheel2_b, wheel2_s)
mass = 100
size = (80,25)
moment = pymunk.moment_for_box(mass, size)
chassi_b = pymunk.Body(mass, moment)
chassi_s = pymunk.Poly.create_box(chassi_b, size)
chassi_s.color = chassi_color
space.add(chassi_b, chassi_s)
#Positions
chassi_b.position = car_pos + (0,-15)
wheel1_b.position = car_pos + (-25,0)
wheel2_b.position = car_pos + (25,0)
#Joints
spring1 = pymunk.DampedSpring(chassi_b, wheel1_b, (-25,0), (0,0), 20, 100000, 1)
spring1.collide_bodies = False
spring2 = pymunk.DampedSpring(chassi_b, wheel2_b, (25,0), (0,0), 20, 100000, 1)
spring2.collide_bodies = False
wheelAngle1 = pymunk.RotaryLimitJoint(wheel1_b, chassi_b, 0, 0)
wheelAngle1.collide_bodies = False
wheelAngle2 = pymunk.RotaryLimitJoint(chassi_b, wheel2_b, 0, 0)
wheelAngle2.collide_bodies = False
space.add(
spring1,
spring2,
wheelAngle1,
wheelAngle2
)
speed = 20
space.add(
pymunk.SimpleMotor(wheel1_b, chassi_b, speed),
pymunk.SimpleMotor(wheel2_b, chassi_b, speed)
)
First off credits to #viblo.
What makes the following code work, is that the GrooveJoint (see docs) is created perpendicular to the car's chassis. The GrooveJoint is defining a line, where a body is free to slide on. Defining the GrooveJoint it is attached to the car's chassis and to the wheel (for both the front and back wheel).
It looks like this now:
I converted the code (from #viblo) to python and here it is:
def car(space, speed, add_car):
car_pos = Vec2d(100,500)
#bodies
wheel_color = 0,0,0
chassi_color = 255,0,0
wheelCon_color = 0,255,255
#Wheel 1
mass = 25
radius = 10
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel1_b = pymunk.Body(mass, moment)
wheel1_s = pymunk.Circle(wheel1_b, radius)
wheel1_s.friction = 1.5
wheel1_s.color = wheel_color
#Wheel 2
mass = 25
radius = 10
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel2_b = pymunk.Body(mass, moment)
wheel2_s = pymunk.Circle(wheel2_b, radius)
wheel2_s.friction = 1.5
wheel2_s.color = wheel_color
#Chassi
mass = 30
size = (80,25)
moment = pymunk.moment_for_box(mass, size)
chassi_b = pymunk.Body(mass, moment)
chassi_s = pymunk.Poly.create_box(chassi_b, size)
chassi_s.color = chassi_color
#Positions
chassi_b.position = car_pos + (0,-15)
wheel1_b.position = car_pos + (-25,0)
wheel2_b.position = car_pos + (25,0)
#Joints
spring1 = pymunk.constraint.DampedSpring(chassi_b, wheel1_b, (-25,0), (0,0), 15, 5000, 250)
spring1.collide_bodies = False
spring2 = pymunk.constraint.DampedSpring(chassi_b, wheel2_b, (25,0), (0,0), 15, 5000, 250)
spring2.collide_bodies = False
groove1 = pymunk.constraint.GrooveJoint(chassi_b, wheel1_b, (-25,0), (-25,25), (0, 0))
groove1.collide_bodies = False
groove2 = pymunk.constraint.GrooveJoint(chassi_b, wheel2_b, (25,0), (25,25), (0,0))
groove2.collide_bodies = False
if add_car:
motor1 = pymunk.SimpleMotor(wheel1_b, chassi_b, speed)
motor2 = pymunk.SimpleMotor(wheel2_b, chassi_b, speed)
space.add(
spring1,
spring2,
groove1,
groove2,
motor1,
motor2,
chassi_b,
chassi_s,
wheel2_b,
wheel2_s,
wheel1_b,
wheel1_s
)
The RotaryLimitJoint is not what you need. It will constrain the angle between the wheel and chassis, but the wheel needs to rotate so it wont work.
What you can try with instead is a GrooveJoint.
This is how the code looks like in c code, it should be fairly easy to convert it to python:
Full source: https://github.com/slembcke/Chipmunk2D/blob/master/demo/Joints.c#L263
The relevant part:
boxOffset = cpv(0, 0);
cpBody *wheel1 = addWheel(space, posA, boxOffset);
cpBody *wheel2 = addWheel(space, posB, boxOffset);
cpBody *chassis = addChassis(space, cpv(80, 100), boxOffset);
cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel1, cpv(-30, -10), cpv(-30, -40), cpvzero));
cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel2, cpv( 30, -10), cpv( 30, -40), cpvzero));
cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel1, cpv(-30, 0), cpvzero, 50.0f, 20.0f, 10.0f));
cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel2, cpv( 30, 0), cpvzero, 50.0f, 20.0f, 10.0f));
If you cant figure it out I can try to convert it to python, but unfortunately Im not on a computer with Python & Pymunk setup for that now.
I have a fairly complex Python based OpenGL code that runs fine on Windows and Mac, but fails with weird banded-spheres on Linux. Views from two angles:
Here is what the same code plots on a Mac:
The problem is not only with spheres, but this is the easiest thing to show. Does this problem suggest anything to anyone with more experience with OpenGL than I?
Thanks for any hints or suggestions.
Here is some sample code that shows this problem
'''Draws a sphere and axis triplet with openGL; rotates with mouse drag.
This works fine on Windows and Mac, but sphere displays strangely on Linux
'''
import sys
import math
import numpy as np
import numpy.linalg as nl
import wx
import wx.glcanvas
import OpenGL.GL as GL
import OpenGL.GLU as GLU
drawingData = {
'oldxy' : [0, 0],
'Quaternion' : np.array([ 0.11783419, 0.87355958, 0.09141639, 0.4633053 ]),
'linecolors': [(np.array([[0, 0, 0], [1, 0, 0]]), [255, 0, 0]),
(np.array([[0, 0, 0], [0, 1, 0]]), [ 0, 255, 0]),
(np.array([[0, 0, 0], [0, 0, 1]]), [ 0, 0, 255])],
}
def Q2Mat(Q):
''' make rotation matrix from quaternion
'''
QN = Q/np.sqrt(np.sum(np.array(Q)**2))
aa = QN[0]**2
ab = QN[0]*QN[1]
ac = QN[0]*QN[2]
ad = QN[0]*QN[3]
bb = QN[1]**2
bc = QN[1]*QN[2]
bd = QN[1]*QN[3]
cc = QN[2]**2
cd = QN[2]*QN[3]
dd = QN[3]**2
M = [[aa+bb-cc-dd, 2.*(bc-ad), 2.*(ac+bd)],
[2*(ad+bc), aa-bb+cc-dd, 2.*(cd-ab)],
[2*(bd-ac), 2.*(ab+cd), aa-bb-cc+dd]]
return np.array(M)
def prodQVQ(Q,V):
"""compute the quaternion vector rotation qvq-1 = v'
"""
T2 = Q[0]*Q[1]
T3 = Q[0]*Q[2]
T4 = Q[0]*Q[3]
T5 = -Q[1]*Q[1]
T6 = Q[1]*Q[2]
T7 = Q[1]*Q[3]
T8 = -Q[2]*Q[2]
T9 = Q[2]*Q[3]
T10 = -Q[3]*Q[3]
M = np.array([[T8+T10,T6-T4,T3+T7],[T4+T6,T5+T10,T9-T2],[T7-T3,T2+T9,T5+T8]])
VP = 2.*np.inner(V,M)
return VP+V
def invQ(Q):
'''get inverse of quaternion q=r+ai+bj+ck; q* = r-ai-bj-ck
'''
return Q*np.array([1,-1,-1,-1])
def AVdeg2Q(A,V):
''' convert angle (degrees) & vector to quaternion
q=r+ai+bj+ck
'''
sind = lambda x: math.sin(x*math.pi/180.)
cosd = lambda x: math.cos(x*math.pi/180.)
Q = np.zeros(4)
d = nl.norm(np.array(V))
if not A: #== 0.!
A = 360.
if d:
V = V/d
p = A/2.
Q[0] = cosd(p)
Q[1:4] = V*sind(p)
else:
Q[3] = 1.
return Q
def prodQQ(QA,QB):
''' Grassman quaternion product, QA,QB quaternions; q=r+ai+bj+ck
'''
D = np.zeros(4)
D[0] = QA[0]*QB[0]-QA[1]*QB[1]-QA[2]*QB[2]-QA[3]*QB[3]
D[1] = QA[0]*QB[1]+QA[1]*QB[0]+QA[2]*QB[3]-QA[3]*QB[2]
D[2] = QA[0]*QB[2]-QA[1]*QB[3]+QA[2]*QB[0]+QA[3]*QB[1]
D[3] = QA[0]*QB[3]+QA[1]*QB[2]-QA[2]*QB[1]+QA[3]*QB[0]
return D
def RenderUnitVectors(x,y,z):
'Show the axes'
GL.glEnable(GL.GL_COLOR_MATERIAL)
GL.glLineWidth(2)
GL.glEnable(GL.GL_BLEND)
GL.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA)
GL.glEnable(GL.GL_LINE_SMOOTH)
GL.glPushMatrix()
GL.glTranslate(x,y,z)
GL.glScalef(1,1,1)
GL.glBegin(GL.GL_LINES)
for line,color in drawingData['linecolors']:
GL.glColor3ubv(color)
GL.glVertex3fv(-line[1]/2.)
GL.glVertex3fv(line[1]/2.)
GL.glEnd()
GL.glPopMatrix()
GL.glColor4ubv([0,0,0,0])
GL.glDisable(GL.GL_LINE_SMOOTH)
GL.glDisable(GL.GL_BLEND)
GL.glDisable(GL.GL_COLOR_MATERIAL)
def RenderSphere(x,y,z,radius,color):
'show a sphere'
GL.glMaterialfv(GL.GL_FRONT_AND_BACK,GL.GL_DIFFUSE,color)
GL.glPushMatrix()
GL.glTranslate(x,y,z)
GL.glMultMatrixf(np.eye(4).T)
GLU.gluSphere(GLU.gluNewQuadric(),radius,20,10)
GL.glPopMatrix()
class myGLCanvas(wx.Panel):
def __init__(self, parent, id=-1,dpi=None,**kwargs):
wx.Panel.__init__(self,parent,id=id,**kwargs)
if 'win' in sys.platform: # for Windows (& darwin==Mac) -- already double buffered
attribs = None
else: # Linux
attribs = [wx.glcanvas.WX_GL_DOUBLEBUFFER,]
self.canvas = wx.glcanvas.GLCanvas(self,-1,attribList=attribs,**kwargs)
self.context = wx.glcanvas.GLContext(self.canvas)
self.canvas.SetCurrent(self.context)
sizer=wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas,1,wx.EXPAND)
self.SetSizer(sizer)
self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.Draw()
self.Draw()
return
def OnMouseMove(self,event):
if not event.Dragging():
drawingData['oldxy'] = list(event.GetPosition())
return
# Perform a rotation in x-y space
oldxy = drawingData['oldxy']
if not len(oldxy): oldxy = list(event.GetPosition())
dxy = event.GetPosition()-oldxy
drawingData['oldxy'] = list(event.GetPosition())
V = np.array([dxy[1],dxy[0],0.])
A = 0.25*np.sqrt(dxy[0]**2+dxy[1]**2)
if not A: return
# next transform vector back to xtal coordinates via inverse quaternion & make new quaternion
Q = drawingData['Quaternion']
V = prodQVQ(invQ(Q),np.inner(np.eye(3),V))
Q = prodQQ(Q,AVdeg2Q(A,V))
drawingData['Quaternion'] = Q
self.Draw()
def Draw(self):
GL.glClearColor(0.,0.,0.,0.)
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glInitNames()
GL.glPushName(0)
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GL.glViewport(0,0,*self.canvas.GetSize())
GLU.gluPerspective(20.,self.canvas.GetSize()[0]*1./self.canvas.GetSize()[1],7.5,12.5)
GLU.gluLookAt(0,0,10,0,0,0,0,1,0)
# Set Lighting
GL.glEnable(GL.GL_DEPTH_TEST)
GL.glEnable(GL.GL_LIGHTING)
GL.glEnable(GL.GL_LIGHT0)
GL.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE,0)
GL.glLightfv(GL.GL_LIGHT0,GL.GL_AMBIENT,[1,1,1,1])
GL.glLightfv(GL.GL_LIGHT0,GL.GL_DIFFUSE,[1,1,1,1])
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
matRot = Q2Mat(drawingData['Quaternion'])
matRot = np.concatenate((np.concatenate((matRot,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
GL.glMultMatrixf(matRot.T)
GL.glMultMatrixf(np.eye(4).T)
Tx,Ty,Tz = (0.20045985394544949, 0.44135342324377724, 0.40844172594191536)
GL.glTranslate(-Tx,-Ty,-Tz)
RenderUnitVectors(Tx,Ty,Tz)
RenderSphere(0, 0, 0, 0.804, [1., 1., 1.])
self.canvas.SetCurrent(self.context)
self.canvas.SwapBuffers()
class GUI(wx.App):
def OnInit(self):
frame = wx.Frame(None,-1,'ball rendering',wx.DefaultPosition,wx.Size(400,400))
frame.Show()
wx.CallAfter(myGLCanvas,frame,size=wx.Size(400,400)) # wait for frame to be displayed
self.MainLoop()
return True
if __name__ == '__main__':
GUI()
You have to specify the number of the bits for the depth buffer, according to the conditions of your hardware, by setting WX_GL_DEPTH_SIZE. The size of the depth buffer should be 16, 24 or 32.
attribs = [
wx.glcanvas.WX_GL_RGBA,
wx.glcanvas.WX_GL_DOUBLEBUFFER,
wx.glcanvas.WX_GL_DEPTH_SIZE, 16]
See also:
How can I determine the max allowable WX_GL_DEPTH_SIZE for a wx GLCanvas?
OpenGL depth buffer deosn't seem to work in wx.glcanvas?
wx.glcanvas.WX_GL_DEPTH_SIZE
wxGLCanvas
I'm trying to achieve the pattern below.
Got as far as doing the first line, then I have no clue how to code the rest of the pattern.
Here's what I've done so far:
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Example",100,100)
x = 7
y = 7
radius = 5
while x<=30 :
centre = Point(x,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
while x>=35 and x<=65 :
centre = Point(x+5,y)
circle2 = Circle(centre,radius)
circle2.setFill("red")
circle2.draw(win)
x = x+10
print(x)
while x>=67:
centre = Point(x+10,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
main()
I got it guys, thanks
Heres the solution
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Patch2" ,100,100)
for x in (5, 15, 25, 40,50,60,75,85,95):
for y in (5, 15, 25, 40,50,60,75,85,95):
c = Circle(Point(x+2,y), 5)
d = Circle(Point(x+2,y), 5)
c.draw(win)
d.draw(win)
c.setFill("Red")
d.setFill("Red")
if x==15 or x==50 or x== 85:
if y==15 or y==50 or y== 85:
c2 = Circle(Point(x+2,y),5)
c2.draw(win)
c2.setFill("White")
main()
While there is nothing wrong with your solution, this is a bit more performant
from graphics import *
def main():
win = GraphWin("Patch2" ,100,100)
coords = [5, 15, 25, 40, 50, 60, 75, 85, 95]
centers = set([coords[i] for i in range(1, len(coords), 3)])
for i in xrange(len(coords)):
for j in xrange(i+1):
x, y = (coords[i], coords[j])
c1 = Circle(Point(x+2,y), 5)
c2 = Circle(Point(y+2,x), 5)
c1.draw(win)
c2.draw(win)
if x in centers and y in centers:
c1.setFill("White")
c2.setFill("White")
else:
c1.setFill("Red")
c2.setFill("Red")
main()
Update: "Better" version
And since I got bored and I liked this problem (yes, I program when I'm bored) I made a fully parameter-ized version which you can do some fun stuff with, like.
Probably over your head :) But maybe you learn something from it, so I'm posting it.
from graphics import *
def drawPattern(scale):
# Inner method: Draw a square of circles given the top-left point
def drawSquare(win, xCoord, yCoord, squareSize=30, numCircles=3, scale=1, scaleCircles=False, outer_color="Red", inner_color="White"):
# Overwrite the default scaling
if scale > 1:
squareSize *= scale
if scaleCircles:
numCircles *= scale
radius = squareSize/(numCircles*2) # Divide by 2 since it's the radius
from math import sqrt, floor
centerDiff = (2*radius) * floor(sqrt(numCircles)) # Used for drawing off-color circles
# xrange uses an exclusive stop value, so go one value past to make inclusive
for x in xrange(radius, squareSize+radius, radius*2):
for y in xrange(squareSize-radius, x-radius, -radius*2):
c1 = Circle(Point(x+xCoord+2,y+yCoord), radius)
c2 = Circle(Point(y+yCoord+2,x+xCoord), radius)
c1.draw(win)
c2.draw(win)
if (centerDiff < x < squareSize - centerDiff) and (centerDiff < y < squareSize - centerDiff):
c1.setFill(inner_color)
c2.setFill(inner_color)
else:
c1.setFill(outer_color)
c2.setFill(outer_color)
win = GraphWin("Patch2 (x{})".format(scale), 100*scale,100*scale)
coords = [0, 35, 70]
for x in coords:
for y in coords:
drawSquare(win, x*scale, y*scale, scale=scale) # normal (boring) version
# drawSquare(win, x*scale, y*scale, scale=scale, scaleCircles=True, outer_color="Blue") # Picture version
def main():
drawPattern(3)
main()