I have high resolution scans of old navigational maps, that I have turned into map tiles with gdal2tiles. Now I want to write code for a live video stream that records a panning movement between two random points on the maps.
Initially, I had the code working by generating an image for each videoframe, that was assembled from a grid of map tiles. These are small jpg files of 256px x 256px. The next videoframe would then show the same map, but translated a certain amount in the x and y direction.
But opening each jpg with Image.open proved to be a bottleneck. So I tried to make the process faster by reusing the opened tiles until they disappeared off the frame, and only opening fresh tiles as needed. I basically first translate the whole image like so: newframe = oldframe.transform(oldframe.size, Image.AFFINE, data). Then I add a row of fresh tiles on top (or bottom, depending on direction of the panning motion), and on the side.
The problem
I seem to run into some rounding errors (I think), because the opened tiles do not always line up well with the existing, translated content. I have thin lines appearing. But I can't figure out where the rounding errors may come from. Nor how to avoid them.
Here is some code which shows the lines appearing, using colored empty images rather than the map tiles:
import time
import math
from random import randint, uniform
from PIL import Image
import numpy as np
import cv2
FRAMESIZE = (1920, 1080)
TILESIZE = 256
class MyMap:
'''A map class, to hold all its properties'''
def __init__(self) -> None:
self.maxzoom = 8
self.dimensions = (40000, 30000)
self.route, self.zoom = self.trajectory()
pass
def trajectory(self):
'''Calculate random trajectories from map dimensions'''
factor = uniform(1, 8)
extentwidth = FRAMESIZE[0] * factor
extentheight = FRAMESIZE[1] * factor
mapwidth, mapheight = (self.dimensions)
zdiff = math.log2(factor)
newzoom = math.ceil(self.maxzoom - zdiff)
a = (randint(0 + math.ceil(extentwidth / 2), mapwidth - math.floor(extentwidth / 2)),
randint(0 + math.ceil(extentheight / 2), mapheight - math.floor(extentheight / 2))) # Starting point
b = (randint(0 + math.ceil(extentwidth / 2), mapwidth - math.floor(extentwidth / 2)),
randint(0 + math.ceil(extentheight / 2), mapheight - math.floor(extentheight / 2))) # Ending point
x_distance = b[0] - a[0]
y_distance = b[1] - a[1]
distance = math.sqrt((x_distance**2)+(y_distance**2)) # Pythagoras
speed = 3 * factor # pixels per 25th of a second (video framerate)
steps = math.floor(distance / speed)
trajectory = []
for step in range(steps):
x = a[0] + step * x_distance / steps
y = a[1] + step * y_distance / steps
trajectory.append((x, y))
return trajectory, newzoom
def CreateFrame(self, point, oldframe = None):
x = round(self.route[point][0] / (2 ** (self.maxzoom - self.zoom)))
y = round(self.route[point][1] / (2 ** (self.maxzoom - self.zoom)))
if oldframe:
xtrns = x - round(self.route[point - 1][0] / (2 ** (self.maxzoom - self.zoom)))
ytrns = y - round(self.route[point - 1][1] / (2 ** (self.maxzoom - self.zoom)))
# print(x, self.route[point - 1][0] / (2 ** (self.maxzoom - self.zoom)))
west = int(x - FRAMESIZE[0] / 2)
east = int(x + FRAMESIZE[0] / 2)
north = int(y - FRAMESIZE[1] / 2)
south = int(y + FRAMESIZE[1] / 2)
xoffset = west % TILESIZE
yoffset = north % TILESIZE
xrange = range(math.floor(west / TILESIZE), math.ceil(east / TILESIZE))
yrange = range(math.floor(north / TILESIZE), math.ceil(south / TILESIZE))
if oldframe:
data = (
1, #a
0, #b
xtrns, #c +left/-right
0, #d
1, #e
ytrns #f +up/-down
)
newframe = oldframe.transform(oldframe.size, Image.AFFINE, data)
if ytrns < 0:
singlerow_ytile = yrange.start
elif ytrns > 0:
singlerow_ytile = yrange.stop - 1
if ytrns != 0:
for xtile in xrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (130,100,10))
newframe.paste(
tile,
(
(xtile - west // TILESIZE) * TILESIZE - xoffset,
(singlerow_ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
if xtrns < 0:
singlerow_xtile = xrange.start
elif xtrns > 0:
singlerow_xtile = xrange.stop - 1
if xtrns != 0:
for ytile in yrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (200, 200, 200))
newframe.paste(
tile,
(
(singlerow_xtile - west // TILESIZE) * TILESIZE - xoffset,
(ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
else:
newframe = Image.new('RGB',FRAMESIZE)
for xtile in xrange:
for ytile in yrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (100, 200, 20))
newframe.paste(
tile,
(
(xtile - west // TILESIZE) * TILESIZE - xoffset,
(ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
return newframe
def preparedisplay(img, ago):
quit = False
open_cv_image = np.array(img)
# Convert RGB to BGR
open_cv_image = open_cv_image[:, :, ::-1].copy()
# Write some Text
font = cv2.FONT_HERSHEY_TRIPLEX
bottomLeftCornerOfText = (10,1050)
fontScale = 1
fontColor = (2,2,2)
thickness = 2
lineType = 2
cv2.putText(open_cv_image,f"Press q to exit. Frame took {(time.process_time() - ago) * 100}",
bottomLeftCornerOfText,
font,
fontScale,
fontColor,
thickness,
lineType)
return open_cv_image
#===============================================================================
quit = False
while not quit:
currentmap = MyMap()
previousframe = None
step = 0
while step < len(currentmap.route):
start = time.process_time()
currentframe = currentmap.CreateFrame(step, previousframe)
previousframe = currentframe
cv2.imshow('maps', preparedisplay(currentframe, start))
timeleft = (time.process_time() - start)
# print(timeleft)
# if cv2.waitKey(40 - int(timeleft * 100)) == ord('q'):
if cv2.waitKey(1) == ord('q'):
# press q to terminate the loop
cv2.destroyAllWindows()
quit = True
break
step += 1
Related
This question already has answers here:
How do I fix wall warping in my raycaster?
(1 answer)
Problem with recognising where a ray in raycaster intersects a wall along the horizontal axis
(1 answer)
cant get raycast to work from angles 90 to 270 pygame
(1 answer)
Why my raycasting keeps going through walls?
(1 answer)
Closed 3 months ago.
I am trying to create a raycast visualizer. The lines are supposed to shoot out and stop when they collide with a wall. Currently the length is entirely random and sometimes the rays point in directions that are even behind me. I am using an scale of 47 when i draw things to the screen for tiling purposes. I have tried for 10 or so hours every scale in the raycast code and I can't see what I am missing.
import pygame
import numpy
from PygameEngine import GameEngine
import sys
import math
class RayCasting:
FOV = numpy.pi/5
HALF_FOV = FOV/2
NUM_RAYS = GameEngine.WIDTH//2
HALF_NUM_RAYS = NUM_RAYS//2
DELTA_ANGLE = FOV/NUM_RAYS
MAX_DEPTH = 20
def __init__(self, game):
self.game = game
def rayCast(self):
ox, oy = self.game.wasd.pos
x_map = int(ox)
y_map = int(oy)
ray_angle = self.game.wasd.angle - self.HALF_FOV + 0.000001
for ray in range(self.NUM_RAYS):
sin_a = math.sin(ray_angle)
cos_a = math.cos(ray_angle)
# horizontals
y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1)
depth_hor = (y_hor - oy) / sin_a
x_hor = ox + depth_hor * cos_a
delta_depth = dy / sin_a
dx = delta_depth * cos_a
print("YHor: ",y_hor, " DY:", dy, " Depth Hor: ", depth_hor, "X Hor: ", x_hor,
" Delta Depth: ", delta_depth, " DX: ", dx)
for i in range(self.MAX_DEPTH):
tile_hor = int(x_hor), int(y_hor)
if tile_hor in self.game.MAP.wallMap:
# print("INSIDE HOR")
break
x_hor += dx
y_hor += dy
depth_hor += delta_depth
# verticals
x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1)
depth_vert = (x_vert - ox) / cos_a
y_vert = oy + depth_vert * sin_a
delta_depth = dx / cos_a
dy = delta_depth * sin_a
for i in range(self.MAX_DEPTH):
tile_vert = int(x_vert), int(y_vert)
if tile_vert in self.game.MAP.wallMap:
# print("INSIDE VERT")
break
x_vert += dx
y_vert += dy
depth_vert += delta_depth
# depth, texture offset
if depth_vert < depth_hor:
depth = depth_vert
#y_vert %= 1
#offset = y_vert if cos_a > 0 else (1 - y_vert)
else:
depth = depth_hor
#x_hor %= 1
#offset = (1 - x_hor) if sin_a > 0 else x_hor
# remove fishbowl effect
#depth *= math.cos(self.game.wasd.angle - ray_angle)
# projection
#proj_height = SCREEN_DIST / (depth + 0.0001)
# ray casting result
#self.ray_casting_result.append((depth, proj_height, texture, offset))
ray_angle += self.DELTA_ANGLE
pygame.draw.line(self.game.screen, "yellow", (ox*self.game.CELLSIZE,oy*self.game.CELLSIZE), (ox*self.game.CELLSIZE+depth*cos_a, oy*self.game.CELLSIZE+depth*sin_a), 1)
def update(self):
self.rayCast()
from PygameEngine import GameEngine
from Circle import Circle
import pygame
from pygame.locals import *
import sys
import numpy
from map import Map
from RaycastFunction import RayCasting
class RaycastGame(GameEngine):
# Space bar to place this circle which will connect to the WASD with a line
planet = Circle((0,0,0))
planet.keyX = 5
planet.keyY = 5
# Grid set up
def __init__(self):
super().__init__()
self.load()
self.MAP = Map()
self.CELLSIZE = self.MAP.CELLSIZE
# Circle controllable with WASD
self.wasd = Circle((123, 255, 123))
self.raycast = RayCasting(self)
def DDA(self):
# -
# * |
# Remember the Plane is - --m-- +
# * = target |
# m = mouse +
distX = self.wasd.keyX - self.planet.pos[0]
distY = self.wasd.keyY - self.planet.pos[1]
#hypotenuse = numpy.sqrt(distX**2+distY**2)
theta = numpy.arctan((distY/(distX+.0001)))
theta += numpy.deg2rad(90)
# print(numpy.rad2deg(theta), " THETA")
collisionPos = (0,0)
def draw(self):
# Draw MAP array
self.MAP.drawMap()
self.MAP.drawGrid()
# Draw mouse character
#pygame.draw.circle(self.screen, (0, 0, 0),
#(self.plane), Circle.radius)
# Draw planet
# self.planet.draw(self.screen)
# Draw wasd character
self.wasd.draw(self.screen)
# Connect mouse and wasd characters with a line
#pygame.draw.line(self.screen, (255, 255, 255), self.planet.pos, (self.wasd.keyX, self.wasd.keyY), 5)
def update(self):
self.planet.placePlanet()
self.wasd.move()
self.DDA()
self.raycast.update()
def run(self):
# Game loop.
while True:
#This gets written over. Only for clearing screen before each draw
self.screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Update.
self.update()
# Draw
self.draw()
pygame.display.flip()
self.fpsClock.tick(self.FPS)
I do not understand why the rays are not stopping in the proper area.
So I have a pan-tilt system with an airbrush on top, the pressure is quite strong so that I can place the robot at a distance of at least 1.5 meters. I currently have normalized coordinates XY that I can visualize on my camera like this
Now I want to translate those coordinates to a real canvas and allow the pan-tilt to point towards them and eventually spray. The two servos have 0 to 180 degrees but the airbrush is positioned on top of the tilt at 90. So if we consider that the pan and tilt it's at 90 the airbrush points perpendicularly to the real canvas. I am following along with this answer https://stackoverflow.com/a/44269392/13475623
lx = (2 * canvasXpoint / canvasW - 1) * np.tan(fovX / 2)
ly = (-2 * canvasYpoint / canvasH + 1) * np.tan(fovY / 2)
lz = 100
tx = np.cos(pan) * np.cos(tilt) * lx - np.cos(tilt) * np.sin(pan) * ly - np.sin(tilt) * lz
ty = np.sin(pan) * lx + np.cos(pan) * ly
tz = np.cos(pan) * np.sin(tilt) * lx - np.sin(pan) * np.sin(tilt) * ly + np.cos(tilt) * lz
tilt = abs(np.arctan2(tz, tx) )*180 /np.pi
pan = abs(np.arcsin(ty / np.sqrt(tx*tx + ty*ty + tz*tz))) *180 /np.pi
he specifically ask to use fovx and fovy, but i have no idea how to place the, is fovx and fovy the same as the centre of the canvas plus z? which gives the robot position?
this is the entire code:
import numpy as np
import random
import cv2
rect = (0,0,0,0)
startPoint = False
endPoint = False
def on_mouse(event,x,y,flags,params):
global rect,startPoint,endPoint
# get mouse click
if event == cv2.EVENT_LBUTTONDOWN:
if startPoint == True and endPoint == True:
startPoint = False
endPoint = False
rect = (0, 0, 0, 0)
if startPoint == False:
rect = (x, y, 0, 0)
startPoint = True
elif endPoint == False:
rect = (rect[0], rect[1], x, y)
endPoint = True
cap = cv2.VideoCapture(0)
waitTime = 50
#Reading the first frame
(grabbed, frame) = cap.read()
# create a numpy array with coordinates, dtype= np.uint32
points = np.array([
[0.3791454386035252, 0.5089704263689607], [0.4983802415059109, 0.4865878212776629], [0.4191061040406586, 0.4890729258496474], [0.48898375092596835, 0.6904554156787046], [0.41117320428962, 0.6855686449973655], [0.48969027909831686, 0.8806483247709954], [0.4096722346480175, 0.8725103831012889], [0.45146556567120294, 0.216198952126905], [0.6304876750748412, 0.1994776546413951], [0.6406976694235704, 0.1861724655606558], [0.6199918357274865, 0.18561325370105788], [0.6525936779272056, 0.201758477474465], [0.6013198509477334, 0.20041966221830415], [0.6683290543094758, 0.29699362669473495], [0.5645238852104717, 0.3113999818240313], [0.6545654774178274, 0.49620430200480303], [0.5898070573107588, 0.49659117464889346], [0.6592482998457356, 0.6834740545963035], [0.5840631897032319, 0.6828527784533074], [0.6408640096147972, 0.8299668209407426], [0.5829181988101784, 0.8173392725052692], [0.6197806290284397, 0.30050890733295843], [0.8252923243905792, 0.23409826375167195], [0.835683753646597, 0.2185883280832016], [0.8131540844750428, 0.21904862499113367], [0.8506741192799976, 0.2279991219170517], [0.7959142481709739, 0.22725381616179272], [0.8733570624656342, 0.3256920048853457], [0.7652207837892534, 0.3239122878098148], [0.893097550288673, 0.44273291363944955], [0.7346131146711571, 0.4430594635999311], [0.902709244982588, 0.5343829401117663], [0.8520378940615836, 0.543215423861057], [0.7842126810888624, 0.5430821914771806], [0.8496391467917583, 0.7170072127563635], [0.7934480818135997, 0.7157067918591926], [0.8415470663986131, 0.8790693270711738], [0.7969306654944098, 0.8786970205344115], [0.8191112469834433, 0.32444646417244244], [0.4544294400182521, 0.10802826838116084], [0.4652589441860643, 0.09470838455219986], [0.44184697991125976, 0.09401847354478254], [0.4784184639521475, 0.1113126386155105], [0.42270482157448985, 0.10977393520172159], [0.5101597581790689, 0.21719483055184013], [0.39370939342390643, 0.21645334444157344], [0.3703281257159549, 0.34746637604116004]], np.float64)
while(cap.isOpened()):
(grabbed, frame) = cap.read()
cv2.namedWindow('frame')
cv2.setMouseCallback('frame', on_mouse)
panarr=[]
tiltarr=[]
#drawing rectangle
if startPoint == True:
cv2.circle(frame, (rect[0], rect[1]), 2,(255, 0, 255), 2)
if startPoint == True and endPoint == True:
cv2.rectangle(frame, (rect[0], rect[1]), (rect[2], rect[3]), (255, 0, 255), 2)
w = rect[2] - rect[0]
h = rect[3] - rect[1]
canvasW = 120
canvasH = 90
distanceZ = 100
#position machine
screenXCenter = (rect[0] + rect[2]) / 2
screenYCenter = (rect[1] + rect[3]) / 2
pan = tilt = 90
servoXcentrepoint = canvasW / 2
servoYcentrepoint = canvasH / 2
# fov
fovX = np.arctan((canvasW * canvasH )/distanceZ)
for x, y in points:
screenX = (x * w) + rect[0] #- differencesqrx
screenY = (y * h) + rect[1] #- differencesqry
cv2.circle(frame,(int(screenXCenter),int(screenYCenter)),2,(255, 255, 0),2)
cv2.circle(frame,(int(screenX),int(screenY)),2,(255, 45, 250),2)
canvasXpoint = (x * canvasW)
canvasYpoint = (y * canvasH)
# dx = canvasXpoint - servoXcentrepoint
# dy = canvasYpoint - servoYcentrepoint
# pan = abs(np.arctan((distanceZ/dx))) * 180/np.pi
# tilt = abs(np.arctan(distanceZ/dy)) * 180/np.pi
lx = (2 * canvasXpoint / canvasW - 1) * np.tan(servoXcentrepoint / 2)
ly = (-2 * canvasYpoint / canvasH + 1) * np.tan(servoYcentrepoint / 2)
lz = 10
tx = np.cos(pan) * np.cos(tilt) * lx - np.cos(tilt) * np.sin(pan) * ly - np.sin(tilt) * lz
ty = np.sin(pan) * lx + np.cos(pan) * ly
tz = np.cos(pan) * np.sin(tilt) * lx - np.sin(pan) * np.sin(tilt) * ly + np.cos(tilt) * lz
tilt = abs(np.arctan2(tz, tx) )*180 /np.pi
pan = abs(np.arcsin(ty / np.sqrt(tx*tx + ty*ty + tz*tz))) *180 /np.pi
tiltarr.append(int(tilt))
panarr.append(int(pan))
# a = [x,y]
cv2.imshow('frame',frame)
if cv2.waitKey(1)==ord('q'):
break
print(tiltarr)
print(panarr)
cap.release()
cv2.destroyAllWindows()
The ultimate goal is to determine the angle for the pan and tilt based on each point
I am currently trying to draw a Mandelbrot set in python with turtle. However, my problem has nothing to do with the Mandelbrot. I can't change the size of my turtle window. How can I do that?
I tried to initialize a screen and set the screen size with the screensize method. Nothing changes if I do this.
This is my code for drawing the set. I pasted the whole code because I don't know what I did wrong that the screen size doesn't change.
from turtle import *
height = 360
width = 360
screen = Screen()
screen.screensize(width, height)
tu = Turtle()
tu.hideturtle()
tu.speed(0)
tu.penup()
def decreasePoint(n, start1, stop1, start2, stop2):
return ((n - start1) / (stop1 - start1)) * (stop2 - start2) + start2
for x in range(width):
for y in range(height):
a = decreasePoint(x, 0, width, -2, 2)
b = decreasePoint(y, 0, height, -2, 2)
ca = a
cb = b
n = 0
z = 0
while n < 100:
aa = a * a - b * b
bb = 2 * a * b
a = aa + ca
b = bb + cb
n += 1
if abs(a + b) > 16:
break
bright = 'pink'
if (n == 100):
bright = 'black'
tu.goto(x , y)
tu.pendown()
tu.dot(4, bright)
tu.penup()
done()
Instead of:
screen.screensize(width, height)
do:
screen.setup(width, height)
The screensize() method sets the amount of area the turtle can roam, but doesn't change the screen size (despite the name), just the scrollable area. Also, to simplify your code, speed it up and produce a more detailed result, I suggest the following rework:
from turtle import Screen, Turtle
WIDTH, HEIGHT = 360, 360
screen = Screen()
screen.setup(WIDTH + 4, HEIGHT + 8) # fudge factors due to window borders & title bar
screen.setworldcoordinates(0, 0, WIDTH, HEIGHT)
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
def scalePoint(n, start1, stop1, start2, stop2):
return (n - start1) * (stop2 - start2) / (stop1 - start1) + start2
screen.tracer(False)
for x in range(WIDTH):
real = scalePoint(x, 0, WIDTH, -2, 2)
for y in range(HEIGHT):
imaginary = scalePoint(y, 0, HEIGHT, -2, 2)
c = complex(real, imaginary)
z = 0j
color = 'pink'
for _ in range(100):
if abs(z) >= 16.0:
break
z = z * z + c
else:
color = 'black'
turtle.goto(x, y)
turtle.dot(1, color)
screen.update()
screen.tracer(True)
screen.exitonclick()
I can not seem draw lines between the old pixel and the new pixel making a smooth Bezier curve. I have the Bezier curve, but it is only made up of pixels alone. Also, when I click on the canvas to update the Bezier curve I can't get the old one to delete. I have tried canvas.delete(line) and also canvas.delete(tk.ALL), but this gets rid of everything and i need to be able to keep my click_points or the where the ovals where drawn. Any help would be greatly appreciated.
import tkinter as tk
#Screen creation.
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 800
SIZE = 4
**# Creates the canvas.**
root_window = tk.Tk()
canvas = tk.Canvas(root_window, width = SCREEN_WIDTH, height = SCREEN_HEIGHT)
canvas.pack()
**#Plots each pixel**
def plot_pixel(x0, y0):
line = canvas.create_line(x0, y0, x0 + 1, y0)
**#Pre: Takes a list of points.
#Post: Recursively iterates through the list to find the
# linear interpolation (x, y)**
def draw_curve(points, t):
if len(points) == 1:
plot_pixel(points[0][0], points[0][1])
else:
newpoints = []
for i in range(0, len(points) - 1):
# old_point_x = (1 - t) * points[i - 1][0] + t * points[i][0]
# old_point_y = (1 - t) * points[i - 1][1] + t * points[i][1]
x = (1 - t) * points[i][0] + t * points[i + 1][0]
y = (1 - t) * points[i][1] + t * points[i + 1][1]
newpoints.append((x, y))
draw_curve(newpoints, t)
Recursion call to draw_curve while t <= 1.
def draw(points):
t = 0
while t <= 1:
draw_curve(points, t)
t += 0.01
#Mouse B-1 bound, for every click draw an oval and append to
#list -- click_points.
click_points = []
def click(event):
click_points.append((event.x, event.y))
oval = canvas.create_oval(event.x - SIZE,
event.y - SIZE,
event.x + SIZE,
event.y + SIZE,
fill = "red")
draw(click_points)
canvas.bind("<Button-1>", click)
root_window.mainloop()
The first problem that im getting is with my random numbers. every other time i try and run the program i get an error with a random number. The program worked and would make a sierpinski triangle every other time until i tried to add color into the equation now the display box pops up then everything freezes
import sys, pygame, random, math, array
####initializes pygame
pygame.init()
#####deffining all my functions
def verticiePos(verticies):
for i in range(2):
screen.set_at(verticies[i], (0,0,255))
def randV(verticies):
v = random.choice(verticies)
return v
def Show(delay):
pygame.display.flip()
pygame.time.delay(delay)
def randPoint(h,w):
yRand = random.randint(0,h-1)
#maxX = ((w - yRand) * 2)
xRand = random.randint(0, w-1)
return (xRand, yRand)
def mainFunc():
verticiePos(verticies)
randPoint(h,w)
def colors(point, maxRed, maxBlue, maxGreen, bv, gv):
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 255
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 255
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 255
howBlue = int(howBlue)
return (howRed, howGreen, howBlue)
#####global variables
xRand = 0
yRand = 0
howRed = 0
howBlue = 0
howGreen = 0
#####Let the user choose the size of the display and setting screne
w = input("What do you want the width of the dcreen to be: ")
w = int(w)
h = input("What do you want the height of the dcreen to be: ")
h = int(h)
size = [w,h]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Project 1, Spierpinski triangle")
######setting up my verticies and all the functions i made
verticies = [(1,h - 1), (int(w/2), 1), (w-1,h-1)]
gv = verticies[1]
bv = verticies[2]
lengthOne = w
lengthTwo = math.sqrt(((w/2)**2) + (h**2))
if lengthOne >= lengthTwo:
maxRed = lengthOne
maxBlue = lengthOne
else:
maxRed = lengthTwo
maxBlue = lengthTwo
maxGreen = lengthTwo
############################################
mainFunc()
point = [yRand,xRand]
iteration = 0
delay = 2
#######the main loop thats plots points
for i in range(10000):
v = randV(verticies)
#colors(point, maxRed, maxBlue, maxGreen, bv, gv)
point = (int((point[0] + v[0])/2), int((point[1] + v[1])/2))
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 200
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 200
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 200
howBlue = int(howBlue)
screen.set_at(point,(howRed,howGreen,howBlue))
Show(delay)
iteration = iteration + 1
#####the loop went really fast and was hard to see it coming into shape so i added this
if iteration > 2000:
delay = 0
#howRed,howGreen,howBlue
This is an updated version of the code that works i just need to clean it up now
Problem with random:
You use random.randint(yRand, maxX) in randPoint() and sometimes yRand > maxX
but random.randint(a, b) require a <= b
http://docs.python.org/2/library/random.html#random.randint
Problem with freeze ???
I have not problem with freeze but you have loop for i in range(50000): and it takes 1 minute to finish. At first run I thought that program freeze.
You have no event loop to get keyboard event and stop program with ESC.
Function color() always return (0,0,0) - it is black - so I don't see Sierpinski triangle.
#EDIT:
Sierpinski Triangle with recursion
import pygame
import math
class Sierpinski():
def __init__(self):
h = w = int(input("Triangle size: "))
level = int(input("Recursion level: "))
margin = 50 # add to size to make margin around triangle
# initializes pygame and setting screne
pygame.init()
self.screen = pygame.display.set_mode( (w + margin*2, h + margin*2) ) # self. - to make accessible in all function
pygame.display.set_caption("Sierpinski Triangle - Recursion")
# offset to move triangle to middle of window
const_height = math.sqrt(3)/2 # h = a * sqrt(3)/2 = a * const_height
invert_const_height = 1 - const_height
offset = int(h * invert_const_height / 2) # to move triange up - to middle
# main vertices A, B, C
a = (margin, h + margin - offset)
b = (w + margin, h + margin - offset)
c = (w/2 + margin, int(h * invert_const_height) + margin - offset)
self.screen.set_at(a, (255,255,255))
self.screen.set_at(b, (255,255,255))
self.screen.set_at(c, (255,255,255))
# recursion
self.drawTriangle(a, b, c, level)
# main loop (in game)
clock = pygame.time.Clock()
running = True
while running:
# keyboard & mouse event
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# move objects - nothing to do here
# draw object & redraw on screen
pygame.display.set_caption("Sierpinski Triangle - Recursion [FPS: %f]" % (clock.get_fps()))
pygame.display.update()
# frametime
clock.tick(25) # max 25 Frames Per Second
# end program
pygame.quit()
#-------------------------------------------------------
def drawTriangle(self, a, b, c, level):
if level == 0:
return
ab = self.middlePoint(a, b)
ac = self.middlePoint(a, c)
bc = self.middlePoint(b, c)
self.screen.set_at(ab, (255,255,255))
self.screen.set_at(bc, (255,255,255))
self.screen.set_at(ac, (255,255,255))
self.drawTriangle(a, ab, ac, level-1)
self.drawTriangle(b, ab, bc, level-1)
self.drawTriangle(c, bc, ac, level-1)
#-------------------------------------------------------
def middlePoint(self, a, b):
x = (a[0] + b[0])/2
y = (a[1] + b[1])/2
return (x,y)
#----------------------------------------------------------------------
if __name__ == '__main__':
Sierpinski()