From fb222b6dea0ecc83a7aafea250d3877ef9b4eead Mon Sep 17 00:00:00 2001 From: Sakimori Date: Sat, 26 Jun 2021 22:19:44 -0400 Subject: [PATCH] added renderImage to camera, to save a representative image of system at any point to disk takes a long time oops --- OrbitSim.py | 13 +++++++++---- renderer.py | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/OrbitSim.py b/OrbitSim.py index eade6ff..a978ce6 100644 --- a/OrbitSim.py +++ b/OrbitSim.py @@ -1,4 +1,4 @@ -import os, json, numpy, pygame, time +import os, json, numpy, pygame, time, threading from renderer import * from copy import deepcopy @@ -97,9 +97,11 @@ if __name__=="__main__": running = True display = False thisEarth = deepcopy(Planet.Earth) - sat = OrbitingBody(Point(config()["earthRadius"] * 1.1, 0, 0), Point(0,6000,-6500), "BoSLOO", 3, thisEarth) + sat = OrbitingBody(Point(config()["earthRadius"] * 1.1, 0, 0), Point(0,1000,-8500), "BoSLOO", 3, thisEarth) orbitlines = [] renderObjects = [thisEarth, sat, orbitlines] + imageThread = threading.Thread() + while running: for event in pygame.event.get(): @@ -108,16 +110,19 @@ if __name__=="__main__": elif event.type == pygame.MOUSEBUTTONDOWN: if not display: display = True - camera = Camera(window, Point(0, 0, 3 * config()["earthRadius"]), thisEarth, renderObjects) + camera = Camera(window, Point(0, 0, 8 * config()["earthRadius"]), thisEarth, renderObjects) pygame.draw.circle(window, (255,255,255), pygame.mouse.get_pos(), 100) camera.renderFrame() pygame.display.flip() else: + if not imageThread.is_alive(): + imageThread = threading.Thread(target=camera.renderImage, args=(sat,)) + imageThread.start() display = False window.fill((0,0,0)) pygame.display.flip() if display: - deltaTime = frameTime * config()["timeScale"] + deltaTime = frameTime * config()["timeScale"] physicsUpdate(renderObjects, orbitlines, deltaTime) camera.renderFrame() pygame.display.flip() diff --git a/renderer.py b/renderer.py index 1b3b1fc..ae9b750 100644 --- a/renderer.py +++ b/renderer.py @@ -12,9 +12,12 @@ class Point: self.vector = self.vector/self.magnitude() return self - def distanceFrom(self, otherPoint:"Point"): + def distanceFromPoint(self, otherPoint:"Point"): return numpy.linalg.norm(self.vector - otherPoint.vector) + def distanceFromLine(self, line:"Line"): + return numpy.linalg.norm(numpy.cross(line.p2.vector - line.p1.vector, self.vector - line.p1.vector)/numpy.linalg.norm(line.p2.vector - line.p1.vector)) + def add(p1, p2): sum = numpy.add(p1.vector, p2.vector) return Point(sum[0], sum[1], sum[2]) @@ -108,6 +111,43 @@ class Camera: screenSurface = pygame.transform.flip(screenSurface, False, True) self.surface.blit(screenSurface, (0,0)) + + def renderImage(self, sat:"OrbitingBody"): + """generates a single image and saves it to disk""" + frozenSat = sat.location + 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) + screenPlaneOrigin = Point.subtract(screenPlane.point, Point(int(winWidth/2), int(winHeight/2), 0)) + screenSurface = pygame.Surface((winWidth, winHeight)) + #pygame uses 0,0 as the top left corner + + satDistance = -1 + for column in range(0, winWidth): + for row in range(0, winHeight): + #get line in world going through this pixel + worldLine = Line(self.location, Point.add(screenPlaneOrigin, Point(column, row, 0))) + #compare distance from center of planet to radius of planet to determine intersection + if self.target.location.distanceFromLine(worldLine) < self.target.radius: + screenSurface.set_at((column, row), (100,255,100)) + + dist = frozenSat.distanceFromLine(worldLine) + if satDistance < 0 or dist < satDistance: + satDistance = dist + satPixel = (column, row) + + if screenSurface.get_at(satPixel) == (0,0,0): + circleBorder = 0 + else: + if self.location.distanceFromPoint(frozenSat) > self.location.distanceFromPoint(self.target.location): + circleBorder = 2 + else: + circleBorder = 0 + pygame.draw.circle(screenSurface, (230, 227, 64), satPixel, 4, width = circleBorder) + screenSurface = pygame.transform.flip(screenSurface, False, True) + pygame.image.save(screenSurface, "test.png") #for row in range(int(-winHeight/2), int(winHeight/2)):