-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finished the UI. There will likely be minor tweaks (Like supporting portrait orientations) in the upcoming days/weeks
- Loading branch information
1 parent
3780335
commit 43086b3
Showing
18 changed files
with
418 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from ui import * | ||
import photos | ||
|
||
import sys | ||
sys.path.append('..') | ||
|
||
from CV import * | ||
from pathfinding import * | ||
import MazeEditView | ||
reload(MazeEditView) | ||
from MazeEditView import MazeEditView | ||
from StartEndView import StartEndView | ||
from SolutionView import SolutionView | ||
|
||
@in_background | ||
def act(sender): | ||
nv = sender.navigation_view | ||
p=photos.pick_image() | ||
#Generate maze map from image | ||
image=mazeGen.finalScan(p.resize((320,240))) | ||
|
||
def f_handle(image): | ||
'''Callback function for MazeEditView''' | ||
global edited,sev | ||
edited=image | ||
def f_handle_2(start,end): | ||
sol=SolutionView(edited, start, end) | ||
nv.push_view(sol) | ||
sev = StartEndView(image=edited,finished_handler=f_handle_2) | ||
sev.name='Step 3: Mark Start and End Points' | ||
sev.right_button_items=[ButtonItem(title='Continue', action=sev.finish)] | ||
nv.push_view(sev) | ||
|
||
#View for editing scan, f_handle is callback for returning edited image | ||
mev = MazeEditView(image=image,finished_handler=f_handle) | ||
mev.name='Step 2: Fix Mistakes' | ||
mev.right_button_items=[ButtonItem(title='Continue', action=mev.finish)] | ||
nv.push_view(mev) | ||
#Problem is here because mev is not closed automatically, code that closes is after wait modal. fix by pushing new view from within callback function. | ||
mev.wait_modal() | ||
sev.wait_modal() | ||
edited.show() | ||
|
||
v=View(background_color=(255,255,255),name='Step 1: Capture Image') | ||
|
||
startButton=Button(frame=(0,0,350,150), flex= 'LRBT') | ||
startButton.title='start' | ||
startButton.tint_color=(.5,.5,1) | ||
startButton.font = ('Menlo-Bold',100) | ||
startButton.action=act | ||
|
||
v.add_subview(startButton) | ||
|
||
nav=NavigationView(v) | ||
nav.present(hide_title_bar=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
'''View for editing the walls and structure of mazes, as well as marking the start and end''' | ||
|
||
import ui, io, time | ||
from PIL import Image | ||
from math import pi | ||
|
||
def pil_to_ui(img): | ||
with io.BytesIO() as b: | ||
img.save(b, "PNG") | ||
return ui.Image.from_data(b.getvalue()) | ||
|
||
class MazeEditView(ui.View): | ||
'''Used for correcting the maze scan''' | ||
def __init__(self, image, finished_handler): | ||
self.img = image.convert('L') | ||
self.finished_handler = finished_handler | ||
self.load=self.img.load() | ||
self.buttonView=None | ||
self.angle = 0 | ||
|
||
def invert(self,sender): | ||
'''Invert both the color of a button and the corresponding pixel in self.img''' | ||
x=int((sender.frame[0])/sender.frame[2])#sender.frame[2] is buttonsize | ||
y=int(sender.frame[1]/sender.frame[2]) | ||
if sender.background_color==(1,1,1,1): | ||
sender.background_color=(0,0,0,1) | ||
self.load[x,y]=0 | ||
|
||
elif sender.background_color==(0,0,0,1): | ||
sender.background_color=(1,1,1,1) | ||
self.load[x,y]=255 | ||
|
||
def rotate(self,sender): | ||
self.angle += 1 | ||
def anim(): | ||
self.buttonView.transform=ui.Transform().rotation((pi/2*self.angle)) | ||
ui.animate(anim,duration=0.5) | ||
|
||
def finish(self, *args): | ||
#uses *args to account for being activated by either button press or otherwise | ||
self.img = self.img.rotate(-90*self.angle) | ||
self.finished_handler(self.img) | ||
|
||
def makeButtons(self): | ||
buttonsize = int(self.height/16) | ||
self.startx=int((self.width/2-self.height/2)) | ||
|
||
rot=ui.Button(frame=(self.startx-2*buttonsize-10,10,2*buttonsize,2*buttonsize)) | ||
rot.image=ui.Image.named('ionicons-ios7-refresh-empty-256') | ||
rot.action=self.rotate | ||
rot.tint_color=(0,0,0) | ||
|
||
self.add_subview(rot) | ||
|
||
self.buttonView = ui.View(frame=(self.startx, 0, buttonsize*16,buttonsize*16)) | ||
for x in range(16): | ||
for y in range(16): | ||
frame=(x*buttonsize,y*buttonsize,buttonsize,buttonsize) | ||
b=ui.Button(frame=frame) | ||
b.background_color=self.load[x,y] | ||
b.action=self.invert | ||
self.buttonView.add_subview(b) | ||
self.add_subview(self.buttonView) | ||
|
||
def draw(self): | ||
if not self.buttonView: | ||
self.makeButtons() | ||
|
||
def will_close(self): | ||
if __name__ == '__main__': | ||
self.finish() | ||
if __name__ == '__main__': | ||
import photos | ||
def show(image): | ||
image.show() | ||
MazeEditView(image=photos.pick_image(),finished_handler=show).present(hide_title_bar=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
'''This view will compute the shortest path and then display it in a pretty format''' | ||
import ui | ||
import photos | ||
|
||
import sys; sys.path.append('..') | ||
|
||
from pathfinding import imageInput, dijkstra | ||
|
||
class SolutionView(ui.View): | ||
def __init__(self, image, start, goal): | ||
self.image = image.convert('RGB') | ||
self.load = self.image.load() | ||
self.start=start | ||
self.goal=goal | ||
|
||
sx, sy=start | ||
gx, gy=goal | ||
self.load[sx,sy]=(0,255,0) | ||
self.load[gx,gy]=(255,0,0) | ||
def pathCalc(self): | ||
#Create graph from image | ||
graph = imageInput.GraphFromImage(self.image) | ||
#Locate nodes in graph that correspond to start and finish | ||
for node in graph: | ||
if node.id == self.start: | ||
startNode = node | ||
if node.id == self.goal: | ||
goalNode = node | ||
#Calculate path | ||
return [x.id for x in dijkstra.Dijkstra(graph, startNode, goalNode)] | ||
|
||
def Djk2UI(self, path): | ||
'''Convert a path of (x,y) coordinates to a pretty ui path''' | ||
|
||
buttonsize=self.buttonsize | ||
#Center offset, used so that path is centered on tiles | ||
cenoff=0.5*buttonsize | ||
#Convert path to coordinates of the bigger window | ||
path = [(cenoff+self.startx+x*buttonsize,cenoff+y*buttonsize) for x,y in path] | ||
|
||
p=ui.Path() | ||
p.move_to(*path[0]) | ||
for point in path: | ||
p.line_to(*point) | ||
p.line_join_style=ui.LINE_JOIN_ROUND | ||
p.line_cap_style=ui.LINE_CAP_ROUND | ||
p.line_width=buttonsize/4 | ||
return p | ||
|
||
def draw(self): | ||
self.buttonsize = int(self.height/16) | ||
self.startx=int((self.width/2-self.height/2)) | ||
|
||
buttonsize=self.buttonsize | ||
for x in range(16): | ||
for y in range(16): | ||
frame=(self.startx+x*buttonsize,y*buttonsize,buttonsize,buttonsize) | ||
p=ui.Path.rect(*frame) | ||
ui.set_color(self.load[x,y]) | ||
p.fill() | ||
|
||
path=self.Djk2UI(self.pathCalc()) | ||
|
||
ui.set_color((0,0,1)) | ||
ui.set_shadow((0,0,0),2,2,5) | ||
path.stroke() | ||
|
||
|
||
if __name__ == '__main__': | ||
SolutionView(photos.pick_image(), (1,0), (12,14)).present(hide_title_bar=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
'''View for marking the start and end of a maze''' | ||
import ui | ||
from PIL import Image | ||
|
||
class target(ui.View): | ||
pass | ||
|
||
class dragDrop(ui.View): | ||
def snap(self): | ||
'''snap to nearest target in same dragContainer''' | ||
targets = self.superview.targets | ||
#find closest target | ||
centers = [t.center for t in targets] | ||
distances = [ abs(c[0]-self.center[0])+abs(c[1]-self.center[1]) for c in centers] | ||
|
||
self.center = centers[distances.index(min(distances))] | ||
def touch_moved(self, touch): | ||
cx, cy = touch.location | ||
ox, oy = touch.prev_location | ||
tx, ty = ox-cx, oy-cy | ||
self.x -= tx | ||
self.y -= ty | ||
def touch_ended(self,touch): | ||
self.snap() | ||
|
||
class dragContainer(ui.View): | ||
def __init__(self, dragDrops, targets): | ||
for t in targets: | ||
self.add_subview(t) | ||
for d in dragDrops: | ||
self.add_subview(d) | ||
self.dragDrops = dragDrops | ||
self.targets = targets | ||
|
||
|
||
class StartEndView(ui.View): | ||
def __init__(self, image, finished_handler): | ||
self.img = image.convert('RGB') | ||
self.load = self.img.load() | ||
self.finished_handler = finished_handler | ||
self.container = None | ||
|
||
def make(self): | ||
buttonsize = int(self.height/16) | ||
self.startx=int((self.width/2-self.height/2)) | ||
|
||
self.start=dragDrop(frame=(self.startx-buttonsize,0,buttonsize,buttonsize),background_color=(0,1,0)) | ||
self.end=dragDrop(frame=(self.startx-buttonsize,buttonsize,buttonsize,buttonsize), background_color=(1,0,0)) | ||
|
||
drags = self.start, self.end | ||
|
||
targets = [] | ||
for x in range(16): | ||
for y in range(16): | ||
frame=(self.startx+x*buttonsize,y*buttonsize,buttonsize,buttonsize) | ||
if self.load[x,y] == (255,255,255): | ||
bg=(1,1,1) | ||
else: | ||
bg=(0,0,0) | ||
targets.append(target(frame=frame, background_color=bg)) | ||
|
||
self.container = dragContainer(drags, targets) | ||
self.container.background_color=(1,1,1) | ||
self.container.frame = self.frame | ||
self.add_subview(self.container) | ||
|
||
def draw(self): | ||
if self.container is None: | ||
self.make() | ||
|
||
def finish(self, *args): | ||
sframe = self.start.frame | ||
eframe = self.end.frame | ||
start = (sframe[0]-self.startx)/sframe[2], sframe[1]/sframe[3] | ||
end = (eframe[0]-self.startx)/eframe[2], eframe[1]/eframe[3] | ||
start = tuple(int(c) for c in start) | ||
end = tuple(int(c) for c in end) | ||
self.finished_handler(start, end) | ||
|
||
if __name__ == '__main__': | ||
import photos | ||
s = StartEndView(photos.pick_image()) | ||
s.present(hide_title_bar=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
import bradley, perspective, redFinder | ||
import bradley, perspective, redFinder, mazeGen |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.