|
| 1 | +https://powcoder.com |
| 2 | +代写代考加微信 powcoder |
| 3 | +Assignment Project Exam Help |
| 4 | +Add WeChat powcoder |
| 5 | +https://powcoder.com |
| 6 | +代写代考加微信 powcoder |
| 7 | +Assignment Project Exam Help |
| 8 | +Add WeChat powcoder |
| 9 | +#general tools, to port out. |
| 10 | +#http://stackoverflow.com/questions/3204245/how-do-i-convert-a-tuple-of-tuples-to-a-one-dimensional-list-using-list-comprehe |
| 11 | +#better learn before i go teach students |
| 12 | +def flatten_once(ls): |
| 13 | + return [element for tupl in ls for element in tupl] |
| 14 | + |
| 15 | +from tkinter import * #python 3 uses lower case for tkinter |
| 16 | +import math |
| 17 | +#assumption: VIEWPORT IS UNIQUE |
| 18 | +master = Tk() |
| 19 | +master.resizable(width=FALSE, height=FALSE) |
| 20 | +visible = None |
| 21 | +viewport_size = None; |
| 22 | +image_buffer = None |
| 23 | +img_antialias = 1 #off |
| 24 | + |
| 25 | +try: |
| 26 | + from PIL import Image, ImageDraw, ImageTk # Import DNSPython |
| 27 | + PIL_available = True |
| 28 | +except ImportError: |
| 29 | + PIL_available = False |
| 30 | + print("Warning: PIL was not loaded correctly") |
| 31 | + |
| 32 | +def init(vp_size): |
| 33 | + global viewport_size |
| 34 | + viewport_size = vp_size |
| 35 | + master.geometry(str(viewport_size)+"x"+str(viewport_size)) #fixed window size |
| 36 | + return |
| 37 | +# Graphics Auxiliary |
| 38 | + |
| 39 | +class Posn: |
| 40 | + def __init__(self, x = None, y = None): |
| 41 | + if x is None: |
| 42 | + raise TypeError("Posn(x,y) - x must be a number") |
| 43 | + if y is None: |
| 44 | + raise TypeError("Posn(x,y) - y must be a number") |
| 45 | + self.x = x |
| 46 | + self.y = y |
| 47 | + def __add__(self, other): #huehuehue, operator overloading! |
| 48 | + return Posn(self.x+other.x, self.y+other.y) |
| 49 | + def __mul__(self, factor): |
| 50 | + return Posn(self.x*factor, self.y*factor) |
| 51 | +##viewport/canvas capabilities |
| 52 | + |
| 53 | +#a viewport is rendered bitmap buffer |
| 54 | +def open_viewport(name, horiz, vert): |
| 55 | + vp, image = open_pixmap(name, horiz, vert) |
| 56 | + #vp.pack() |
| 57 | + show_viewport((vp, image)) |
| 58 | + #vp.create_rectangle(0, 0, 600, 600, fill="white") |
| 59 | + return [vp, image] |
| 60 | + |
| 61 | +#a pixmap is an unrendered pixmap buffer |
| 62 | + #how to do this is simple - |
| 63 | + #everything below a certain screening layer is unrendered. |
| 64 | + #everything above is. And make sure there's only 1 thing there. |
| 65 | + |
| 66 | +def open_pixmap(name, horiz, vert): |
| 67 | + #Canvas(parent, [options...]) |
| 68 | + global viewport_size, PIL_available |
| 69 | + vp = Canvas(master, width=horiz, height=vert) |
| 70 | + image = None |
| 71 | + if PIL_available: |
| 72 | + image = Image.new("RGB", (int(horiz), int(vert)), "white") |
| 73 | + vp.create_rectangle(viewport_size/6, 0, viewport_size+viewport_size/6, viewport_size, fill="white") |
| 74 | + vp.place(x=-(viewport_size/6)) |
| 75 | + hide_viewport((vp, image)) |
| 76 | + return [vp, image] |
| 77 | + |
| 78 | +def show_viewport(vp): |
| 79 | + global visible #apparently no automatic closures. |
| 80 | + if vp == None: |
| 81 | + raise TypeError("show_viewport - vp cannot be None") |
| 82 | + if visible != None: |
| 83 | + hide_viewport(visible) |
| 84 | + visible = vp |
| 85 | + Misc.lift(vp[0], aboveThis = None) |
| 86 | + |
| 87 | +def hide_viewport(vp): |
| 88 | + global visible #apparently no automatic closures. |
| 89 | + Misc.lower(vp[0], belowThis=None) |
| 90 | + if visible == vp and visible != None: |
| 91 | + visible = None |
| 92 | + |
| 93 | +def clear_viewport(viewport): |
| 94 | + viewport[0].delete(ALL) #not nearly sure how this works. |
| 95 | + viewport[0].create_rectangle(viewport_size/6, 0, viewport_size+viewport_size/6, viewport_size, fill="white") |
| 96 | + if PIL_available: |
| 97 | + size = viewport[1].size #(width, height) |
| 98 | + viewport[1].paste("white", (0,0,size[0], size[1])) |
| 99 | + |
| 100 | +#def copy_viewport(src, dest): |
| 101 | + #removed, because i can't figure out how to implement it. |
| 102 | + #however. i have no need to. |
| 103 | +##color handling capabilities |
| 104 | + |
| 105 | + |
| 106 | +##drawing capabilities |
| 107 | + |
| 108 | +def draw_line(viewport, p1, p2, color): |
| 109 | + viewport[0].create_line(p1.x, p1.y, p2.x, p2.y, fill=color.hexcode()) |
| 110 | + if PIL_available: |
| 111 | + draw = ImageDraw.Draw(viewport[1]) |
| 112 | + draw.line(p1.x, p1.y, p2.x, p2.y, fill=color.hexcode()) |
| 113 | + |
| 114 | +#poly = canvas.create_polygon(x0, y0, x1, y1, ..., option, ...) |
| 115 | +#points is a list of point objects, need to map and unpack interior twice. |
| 116 | +def draw_solid_polygon(viewport, points, offset, color): |
| 117 | + points = flatten_once(map(lambda q: (q.x+offset.x, q.y+offset.y), points)) |
| 118 | + #print(*points) |
| 119 | + viewport[0].create_polygon(*points, fill=color.hexcode()) |
| 120 | + if PIL_available: |
| 121 | + draw = ImageDraw.Draw(viewport[1]) |
| 122 | + draw.polygon(points, fill=color.hexcode()) |
| 123 | + |
| 124 | + |
| 125 | +#draw_pixels is removed, wasn't used in the JS code. |
| 126 | + #probably because it was used only in the 3d rendering code, and that was rewritten. |
| 127 | + |
| 128 | +class Rgb: |
| 129 | + def __init__(self, r,g,b): |
| 130 | + self.r = round(r*255) |
| 131 | + self.g = round(g*255) |
| 132 | + self.b = round(b*255) |
| 133 | + def hexcode(self): |
| 134 | + return '#%02x%02x%02x' % (self.r, self.g, self.b) |
| 135 | + |
| 136 | +#Import/export capabilities |
| 137 | + |
| 138 | +#TODO: make higher quality |
| 139 | +#Basically draws whatever is drawn to screen in parallel. |
| 140 | + #However, not pixel perfect. |
| 141 | +import datetime |
| 142 | +def saveImage(vp, filename=None): |
| 143 | + if PIL_available: |
| 144 | + if(filename == None): |
| 145 | + filename = datetime.datetime.now().strftime("%y%m%d-%H%M%S") |
| 146 | + vp[1].save(filename+".png", "PNG") |
| 147 | + else: |
| 148 | + print("PIL does not appear to be available") |
| 149 | + |
| 150 | +def get_pixels(vp): |
| 151 | + if PIL_available: |
| 152 | + return vp[1].load() |
| 153 | + else: |
| 154 | + raise("PIL does not appear to be available") |
| 155 | + |
| 156 | +def pixels_to_canvas(vp): |
| 157 | + if len(vp) == 2: #why? because PIL doesn't keep a copy of the image, so the moment the function goes out of scope, the image DISAPPEARS. |
| 158 | + vp.append(ImageTk.PhotoImage(vp[1])) |
| 159 | + else: |
| 160 | + vp[2] = ImageTk.PhotoImage(vp[1]) |
| 161 | + vp[0].create_image(0,0,image = vp[2], anchor="nw") #else it forget, and diessss |
| 162 | + |
| 163 | +def get_image(vp): |
| 164 | + return vp[1] |
| 165 | + |
| 166 | +def square(x): |
| 167 | + return x*x |
| 168 | + |
| 169 | +def distance(p1, p2): |
| 170 | + return math.sqrt(square(p1.x-p2.x)+square(p1.y-p2.y)) |
| 171 | + |
| 172 | +def blit_pixels(viewport, inv_transform, pixels, viewport_size, image_size, mono, zmin = 0, zmax = 1): |
| 173 | + MAX_X = viewport_size[0] |
| 174 | + MAX_Y = viewport_size[1] |
| 175 | + IMAX_X = image_size[0] |
| 176 | + IMAX_Y = image_size[1] |
| 177 | + viewport_pix = get_pixels(viewport) |
| 178 | + for y in range(MAX_Y): |
| 179 | + for x in range(MAX_X): |
| 180 | + src = inv_transform(Posn(x,y)) #this is the posn on the pixels |
| 181 | + srcx = src.x |
| 182 | + srcy = src.y |
| 183 | + #simple 2x2 weighted sampling. |
| 184 | + #weight is inversely proportional to distance. |
| 185 | + #don't try to use this code for your homework on other modules, |
| 186 | + #i haven't taken graphics and i wrote this off the top off my head. |
| 187 | + rsrcx = round(srcx) |
| 188 | + rsrcy = round(srcy) |
| 189 | + if(rsrcx>=0 and rsrcx<IMAX_X and rsrcy>=0 and rsrcy<IMAX_Y): #if the closest pixel is to be rendered |
| 190 | + #used for weighing |
| 191 | + dsrcx = srcx - rsrcx #+ve => right |
| 192 | + dsrcy = srcy - rsrcy #+ve => up |
| 193 | + #used to figure out which pixel we are actually weighing against. |
| 194 | + if(dsrcx>=0): |
| 195 | + esrcx = 1 |
| 196 | + else: |
| 197 | + esrcx = -1 |
| 198 | + if(dsrcy>=0): |
| 199 | + esrcy = 1 |
| 200 | + else: |
| 201 | + esrcy = -1 |
| 202 | + original = Posn(srcx, srcy) |
| 203 | + dtgt = 1/(distance(Posn(rsrcx, rsrcy),original)+0.01) |
| 204 | + dtgtdx = 1/(distance(Posn(rsrcx+esrcx, rsrcy),original)+0.01) |
| 205 | + dtgtdy = 1/(distance(Posn(rsrcx, rsrcy+esrcy),original)+0.01) |
| 206 | + dtgtdxdy = 1/(distance(Posn(rsrcx+esrcx, rsrcy+esrcy),original)+0.01) |
| 207 | + tgt = pixels[rsrcx, rsrcy] |
| 208 | + #try to get pixel colour values if possible |
| 209 | + #if not possible, disable the weight |
| 210 | + if(rsrcx+esrcx>= 0 and rsrcx+esrcx<IMAX_X): |
| 211 | + tgtdx = pixels[rsrcx+esrcx, rsrcy] |
| 212 | + else: |
| 213 | + dtgtdx = 0 |
| 214 | + dtgtdxdy = 0 |
| 215 | + tgtdx = (0,0,0) |
| 216 | + if(rsrcy+esrcy>= 0 and rsrcy+esrcy<IMAX_Y): |
| 217 | + tgtdy = pixels[rsrcx, rsrcy+esrcy] |
| 218 | + else: |
| 219 | + dtgtdy = 0 |
| 220 | + dtgtdxdy = 0 |
| 221 | + tgtdy = (0,0,0) |
| 222 | + if(dtgtdxdy!=0): |
| 223 | + tgtdxdy = pixels[rsrcx+esrcx, rsrcy+esrcy] |
| 224 | + else: |
| 225 | + tgtdxdy = (0,0,0) |
| 226 | + divisor = (dtgt + dtgtdx + dtgtdy + dtgtdxdy) |
| 227 | + tcolor = (round((dtgt*tgt[0]+dtgtdx*tgtdx[0]+dtgtdy*tgtdy[0]+dtgtdxdy*tgtdxdy[0])/divisor),\ |
| 228 | + round((dtgt*tgt[1]+dtgtdx*tgtdx[1]+dtgtdy*tgtdy[1]+dtgtdxdy*tgtdxdy[1])/divisor), \ |
| 229 | + round((dtgt*tgt[2]+dtgtdx*tgtdx[2]+dtgtdy*tgtdy[2]+dtgtdxdy*tgtdxdy[2])/divisor)) |
| 230 | + def rescale(color): |
| 231 | + if color>=254: |
| 232 | + return 255 |
| 233 | + else: |
| 234 | + return round(zmin*255 + (zmax-zmin)*color) |
| 235 | + tcolor = (rescale(tcolor[0]), rescale(tcolor[1]), rescale(tcolor[2])) |
| 236 | + viewport_pix[x,y] = (min(tcolor[0], viewport_pix[x,y][0]), min(tcolor[1], viewport_pix[x,y][1]), min(tcolor[2], viewport_pix[x,y][2])) |
| 237 | + pixels_to_canvas(viewport) |
| 238 | + |
| 239 | +#TODO: test how it renders out of range pixels |
| 240 | + #no one should up-sample with this algorithm -.- |
| 241 | +# def blit_pixels(viewport, transform, pixels, viewport_size, image_size, mono): |
| 242 | + # global img_antialias |
| 243 | + # MAX_X = image_size[0] |
| 244 | + # MAX_Y = image_size[1] |
| 245 | + # tviewport = open_pixmap("temp", viewport_size[0]*img_antialias, viewport_size[1]*img_antialias) |
| 246 | + # bound_x = img_antialias*viewport_size[0] |
| 247 | + # bound_y = img_antialias*viewport_size[1] |
| 248 | + # target_pix = get_pixels(tviewport) |
| 249 | + # for y in range(MAX_Y): |
| 250 | + # for x in range(MAX_X): |
| 251 | + # p = Posn(x,y) |
| 252 | + # transposn = transform(p) |
| 253 | + # t_x = transposn.x |
| 254 | + # t_y = transposn.y |
| 255 | + # if(t_x>=0 and t_x<=bound_x and t_y>=0 and t_y<=bound_y): |
| 256 | + # if mono: |
| 257 | + # colour = pixels[x,y] |
| 258 | + # avg = round(colour[0]+colour[1]+colour[2]/3) |
| 259 | + # target_pix[t_x, t_y] = (avg, avg, avg) |
| 260 | + # else: |
| 261 | + # target_pix[t_x, t_y] = pixels[x,y] |
| 262 | + # vp_size = get_image_size(viewport) |
| 263 | + # MAX_X = vp_size[0] |
| 264 | + # MAX_Y = vp_size[1] |
| 265 | + ##will leave some dots at the edge. |
| 266 | + ##but MUAHAHAHAHAHHAHAHAHAHAHAHAHAHAHAHAH |
| 267 | + ##DOES NOT CARE |
| 268 | + # white = (255,255,255) |
| 269 | + # for y in range(1,MAX_Y-1): |
| 270 | + # for x in range(1,MAX_X-1): |
| 271 | + # if(target_pix[x,y]== white): |
| 272 | + # up = target_pix[x,y-1] |
| 273 | + # down = target_pix[x,y+1] |
| 274 | + # left = target_pix[x-1, y] |
| 275 | + # right = target_pix[x+1, y] |
| 276 | + # ul = target_pix[x-1, y+1] |
| 277 | + # ur = target_pix[x+1, y+1] |
| 278 | + # dl = target_pix[x-1, y-1] |
| 279 | + # dr = target_pix[x-1, y-1] |
| 280 | + # if(up == white and down == white and left == white and right == white): |
| 281 | + # colour_r = (ul[0]+ur[0]+dl[0]+dr[0])/4 |
| 282 | + # colour_g = (ul[1]+ur[1]+dl[1]+dr[1])/4 |
| 283 | + # colour_b = (ul[2]+ur[2]+dl[2]+dr[2])/4 |
| 284 | + # target_pix[x,y] = (round(colour_r), round(colour_g), round(colour_b)) |
| 285 | + # else: |
| 286 | + # colour_r = (ul[0]+ur[0]+dl[0]+dr[0]+up[0]+down[0]+left[0]+right[0])/8 |
| 287 | + # colour_g = (ul[1]+ur[1]+dl[1]+dr[1]+up[1]+down[1]+left[1]+right[1])/8 |
| 288 | + # colour_b = (ul[2]+ur[2]+dl[2]+dr[2]+up[2]+down[2]+left[2]+right[2])/8 |
| 289 | + # target_pix[x,y] = (round(colour_r), round(colour_g), round(colour_b)) |
| 290 | + ##TODO: enhancement, averaging for points which have been missed out |
| 291 | + # viewport[1] = tviewport[1].resize((viewport_size[0], viewport_size[1]), Image.ANTIALIAS) |
| 292 | + # pixels_to_canvas(viewport) |
| 293 | + |
| 294 | +def get_image_size(img): |
| 295 | + return img[1].size |
| 296 | +def load_image(filename): #returns a vp |
| 297 | + global img_antialias |
| 298 | + if PIL_available: |
| 299 | + img = Image.open(filename) |
| 300 | + img = img.convert('RGB') |
| 301 | + width, height = img.size |
| 302 | + img = img.resize((img_antialias*width, img_antialias*height), Image.BICUBIC) |
| 303 | + tkcanvas, pilcanvas = open_pixmap(filename, img_antialias*width, img_antialias*height) |
| 304 | + return (tkcanvas, img) |
| 305 | + else: |
| 306 | + raise("load_img requires that PIL be available") |
0 commit comments