diff --git a/BoSLOO.pyproj b/BoSLOO.pyproj
index 42b1fa4..4b7c2e8 100644
--- a/BoSLOO.pyproj
+++ b/BoSLOO.pyproj
@@ -23,6 +23,9 @@
+
+ Code
+
diff --git a/OrbitSim.py b/OrbitSim.py
index cf39a07..f72af42 100644
--- a/OrbitSim.py
+++ b/OrbitSim.py
@@ -1,4 +1,6 @@
-import os, json, numpy, pygame
+import os, json, numpy, pygame, time
+from renderer import *
+from copy import deepcopy
groundControlPath = "GroundControlFiles"
configPath = os.path.join("ConfigFiles", "OrbitSim")
@@ -13,10 +15,8 @@ def config():
if not os.path.exists(configFilename):
#generate default
config_dic = {
- "g": 6674,
- "gExp": -14, #G = g * 10^gExp
- "earthMass": 5972,
- "earthMassExp": 21, #Me = earthMass * 10^earthMassExp; in kg
+ "G": 6.674e-11,
+ "earthMass": 5.972e24, #in kg
"earthRadius": 6378000, #meters
"timeScale": 1 #higher number go faster wheeeeee
}
@@ -27,61 +27,56 @@ def config():
with open(configFilename) as file:
return json.load(file)
-class Point:
- """Numpy 3-vec"""
- def __init__(self, x, y, z):
- self.vector = numpy.array([x, y, z])
-
- def magnitude(self):
- return numpy.linalg.norm(self.vector)
-
- def distanceFrom(self, otherPoint:"Point"):
- return numpy.linalg.norm(self.vector - otherPoint.vector)
-
-Point.zero = Point(0, 0, 0)
-
-class Camera:
- """Object which will be used to paint pixels on screen."""
- def __init__(self, location:Point, target:Point = Point.zero, FOV = 75):
- self.location = location
- self.target = target
- self.FOV = FOV
-
- def isInside(self, planet:"Planet"):
- """returns True if camera is inside the planet."""
- return numpy.linalg.norm(self.location.magnitude) < planet.radius
-
class OrbitingBody:
"""a zero-mass point object parented to a planet"""
def __init__(self, location:Point, velocity:Point, name, displaySize, parentPlanet):
self.location = location
self.velocity = velocity
self.name = name
- self.displaySize = displaySize #the size of the object on camera, for visibility reasons
+ self.displaySize = displaySize #the size of the object on camera in pixels, for visibility reasons
self.parentPlanet = parentPlanet
class Planet:
"""A massive body at 0,0,0 and a given radius."""
- def __init__(self, name, mass, radius, rotationPeriod):
+ def __init__(self, name, mass, radius, rotationPeriod, location:Point = deepcopy(Point.zero)):
"""Rotation period given in seconds."""
+ self.location = location
self.name = name
self.mass = mass
self.radius = radius
- self.rotationPercentage = 0
+ self.rotationPercentage = 0.00
self.rotationPeriod = rotationPeriod
-Planet.Earth = Planet("Earth", (config()["earthMass"] * 10**config()["earthMassExp"]), config()["earthRadius"], 86400)
+ def rotate(self, timeDelta:"Seconds"):
+ self.rotationPercentage += timeDelta/self.rotationPeriod
+ if self.rotationPercentage >= 100.0:
+ self.rotationPercentage -= 100.0
+
+Planet.Earth = Planet("Earth", config()["earthMass"], config()["earthRadius"], 86400)
+
+def physicsUpdate(objects, deltaTime):
+ """updates the positions of all orbiting objects in [objects] with timestep deltaTime"""
+ for obj in objects:
+ if type(obj).__name__ == "OrbitingBody":
+ accel = Point.scalarMult(Point.subtract(obj.location, obj.parentPlanet.location).normalize(),-(config()["G"] * obj.parentPlanet.mass)/(Point.subtract(obj.location, obj.parentPlanet.location).magnitude() ** 2))
+ obj.velocity = Point.add(obj.velocity, Point.scalarMult(accel, deltaTime))
+ obj.location = Point.add(obj.location, Point.scalarMult(obj.velocity, deltaTime))
if __name__=="__main__":
pygame.init()
pygame.display.set_caption("Spinny")
- window = pygame.display.set_mode((400, 400))
+ window = pygame.display.set_mode((600, 600))
resolutionDownscaling = 2
pygame.display.flip()
+ frameTime = 1/30 #framerate
+
running = True
display = False
+ thisEarth = deepcopy(Planet.Earth)
+ sat = OrbitingBody(Point(config()["earthRadius"] * 1.1, 0, 0), Point(0,1000,-6500), "BoSLOO", 3, thisEarth)
+ renderObjects = [thisEarth, sat]
while running:
for event in pygame.event.get():
@@ -90,7 +85,21 @@ if __name__=="__main__":
elif event.type == pygame.MOUSEBUTTONDOWN:
if not display:
display = True
- camera = Camera(Point(0, 0, 6378000*4))
+ camera = Camera(window, Point(0, 0, 3 * config()["earthRadius"]), thisEarth, renderObjects)
+ pygame.draw.circle(window, (255,255,255), pygame.mouse.get_pos(), 100)
+ camera.renderFrame()
+ pygame.display.flip()
+ else:
+ display = False
+ window.fill((0,0,0))
+ pygame.display.flip()
+ if display:
+ deltaTime = frameTime * config()["timeScale"]
+ physicsUpdate(renderObjects, deltaTime)
+ camera.renderFrame()
+ pygame.display.flip()
+ time.sleep(frameTime)
+
pygame.quit()
print("Bye!")
\ No newline at end of file
diff --git a/renderer.py b/renderer.py
new file mode 100644
index 0000000..87efc06
--- /dev/null
+++ b/renderer.py
@@ -0,0 +1,106 @@
+import numpy, pygame
+
+class Point:
+ """Numpy 3-vec"""
+ def __init__(self, x, y, z):
+ self.vector = numpy.array([x, y, z])
+
+ def magnitude(self):
+ return numpy.linalg.norm(self.vector)
+
+ def normalize(self):
+ self.vector = self.vector/self.magnitude()
+ return self
+
+ def distanceFrom(self, otherPoint:"Point"):
+ return numpy.linalg.norm(self.vector - otherPoint.vector)
+
+ def add(p1, p2):
+ sum = numpy.add(p1.vector, p2.vector)
+ return Point(sum[0], sum[1], sum[2])
+
+ def subtract(p1, p2):
+ diff = numpy.subtract(p1.vector, p2.vector)
+ return Point(diff[0], diff[1], diff[2])
+
+ def dot(p1, p2):
+ return numpy.dot(p1.vector, p2.vector)
+
+ def scalarMult(p1, scalar):
+ mult = p1.vector * scalar
+ return Point(mult[0], mult[1], mult[2])
+
+
+Point.zero = Point(0, 0, 0)
+
+class Ray:
+ def __init__(self, origin:Point, direction:Point):
+ self.origin = origin
+ self.direction = direction
+
+class Line:
+ def __init__(self, p1:Point, p2:Point):
+ self.p1 = p1
+ self.p2 = p2
+
+ def intersectWithPlane(self, plane):
+ lineVec = Point.subtract(self.p2, self.p1)
+ dot = Point.dot(plane.normal, lineVec)
+
+ if abs(dot) > 1e-6:
+ w = Point.subtract(self.p1, plane.point)
+ fac = -Point.dot(plane.normal, w) / dot
+ u = Point.scalarMult(lineVec, fac)
+ return Point.add(self.p1, u)
+ else:
+ return None
+
+class Plane:
+ def __init__(self, point:Point, normal:Point):
+ self.point = point
+ self.normal = normal
+
+class Camera:
+ """Object which will be used to paint pixels on screen."""
+ def __init__(self, surface:pygame.Surface, location:Point, target:"Planet", objects, hFOV = 55, vFOV = 55):
+ self.surface = surface
+ self.objects = objects
+ self.location = location
+ self.target = target
+ self.hFOV = hFOV
+ self.vFOV = vFOV
+
+ def isInside(self, planet:"Planet"):
+ """returns True if camera is inside the planet."""
+ return numpy.linalg.norm(self.location.magnitude) < planet.radius
+
+ def renderFrame(self):
+ """generates a frame and draws it to the surface. Does not update screen; use pygame.display.flip()"""
+ winWidth, winHeight = self.surface.get_size()
+ winDistance = winWidth * numpy.cos(numpy.radians(self.hFOV)/2) / 2 #distance for a virtual screen to exist in-space to give the correct FOV
+ vecToCenter = Point.subtract(self.target.location, self.location)
+ vecToCenter.normalize()
+ screenPlane = Plane(Point.add(self.location, Point.scalarMult(vecToCenter, winDistance)), vecToCenter)
+ screenSurface = pygame.Surface((winWidth, winHeight))
+ #pygame uses 0,0 as the top left corner
+ for obj in self.objects:
+ if type(obj).__name__ == "OrbitingBody":
+ lineToCamera = Line(obj.location, self.location)
+ intersectPoint = lineToCamera.intersectWithPlane(screenPlane)
+ if intersectPoint is not None:
+ intersectPoint = Point.add(intersectPoint, Point(int(winWidth/2), int(winHeight/2), 0))
+ pygame.draw.circle(screenSurface, (255,255,150), (int(intersectPoint.vector[0]), int(intersectPoint.vector[1])), obj.displaySize)
+ elif type(obj).__name__ == "Planet":
+ lineToCamera = Line(obj.location, self.location)
+ intersectPoint = lineToCamera.intersectWithPlane(screenPlane)
+ if intersectPoint is not None:
+ intersectPoint = Point.add(intersectPoint, Point(int(winWidth/2), int(winHeight/2), 0))
+ pygame.draw.circle(screenSurface, (255,255,150), (int(intersectPoint.vector[0]), int(intersectPoint.vector[1])), 15)
+
+ screenSurface = pygame.transform.flip(screenSurface, False, True)
+ self.surface.blit(screenSurface, (0,0))
+
+
+ #for row in range(int(-winHeight/2), int(winHeight/2)):
+ # for column in range(int(-winWidth/2), int(winWidth/2)):
+ # line = Line(self.location, Point(self.location.x + column))
\ No newline at end of file