Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
shrapnel
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
shrapnel
Commits
8b0be44e
Commit
8b0be44e
authored
Jul 03, 2012
by
Sam Rushing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
scrolling field demo + iOS touch events + quadtree
parent
216926d0
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
490 additions
and
0 deletions
+490
-0
coro/http/demo/websocket/field/field.html
coro/http/demo/websocket/field/field.html
+11
-0
coro/http/demo/websocket/field/field.js
coro/http/demo/websocket/field/field.js
+94
-0
coro/http/demo/websocket/field/field.py
coro/http/demo/websocket/field/field.py
+178
-0
coro/http/demo/websocket/field/quadtree.py
coro/http/demo/websocket/field/quadtree.py
+164
-0
coro/http/demo/websocket/field/region.py
coro/http/demo/websocket/field/region.py
+43
-0
No files found.
coro/http/demo/websocket/field/field.html
0 → 100644
View file @
8b0be44e
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<script
src=
"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
></script>
<body>
<canvas
id=
"canvas"
width=
"1024"
height=
"1024"
></canvas>
<div
id=
"msgs"
></div>
<script
src=
"field.js"
></script>
</body>
</html>
coro/http/demo/websocket/field/field.js
0 → 100644
View file @
8b0be44e
var
connection
;
var
msgs_div
=
document
.
getElementById
(
'
msgs
'
)
function
message
(
msg
)
{
msgs_div
.
innerHTML
=
msg
;
}
if
(
window
[
"
WebSocket
"
])
{
connection
=
new
WebSocket
(
"
ws://127.0.0.1:9001/field
"
)
connection
.
onopen
=
function
()
{
message
(
'
connected
'
)
};
connection
.
onclose
=
function
(
event
)
{
message
(
'
disconnected
'
)
}
connection
.
onmessage
=
function
(
event
)
{
//message ('websocket event: ' + event.data)
switch
(
event
.
data
[
0
])
{
case
'
F
'
:
// draw field
var
elems
=
event
.
data
.
split
(
'
|
'
)
context
.
clearRect
(
0
,
0
,
1024
,
1024
);
context
.
fillStyle
=
'
rgb(0,0,0,128)
'
;
for
(
i
=
0
;
i
<
elems
.
length
;
i
++
)
{
var
elem
=
elems
[
i
];
var
p
=
elem
.
split
(
'
,
'
)
switch
(
p
[
0
])
{
case
'
B
'
:
context
.
fillStyle
=
p
[
1
];
context
.
fillRect
(
parseInt
(
p
[
2
]),
parseInt
(
p
[
3
]),
parseInt
(
p
[
4
]),
parseInt
(
p
[
5
]));
break
;
}
}
break
;
case
'
C
'
:
context
.
clearRect
(
0
,
0
,
1024
,
1024
);
break
;
case
'
M
'
:
message
(
event
.
data
);
break
;
}
}
}
var
canvas
=
document
.
getElementById
(
'
canvas
'
)
var
context
=
canvas
.
getContext
(
'
2d
'
)
document
.
addEventListener
(
'
mousedown
'
,
on_mouse_down
,
false
)
document
.
addEventListener
(
'
mouseup
'
,
on_mouse_up
,
false
)
document
.
addEventListener
(
'
mousemove
'
,
on_mouse_move
,
false
)
document
.
addEventListener
(
'
keydown
'
,
on_key_down
,
false
)
document
.
addEventListener
(
'
keyup
'
,
on_key_up
,
false
)
document
.
addEventListener
(
'
touchstart
'
,
on_touch_start
,
false
)
document
.
addEventListener
(
'
touchmove
'
,
on_touch_move
,
false
)
document
.
addEventListener
(
'
touchend
'
,
on_touch_end
,
false
)
function
on_mouse_down
(
event
)
{
connection
.
send
(
'
MD,
'
+
event
.
clientX
+
'
,
'
+
event
.
clientY
)
}
function
on_mouse_up
(
event
)
{
connection
.
send
(
'
MU,
'
+
event
.
clientX
+
'
,
'
+
event
.
clientY
)
}
function
on_mouse_move
(
event
)
{
connection
.
send
(
'
MM,
'
+
event
.
clientX
+
'
,
'
+
event
.
clientY
)
}
function
make_touch_list
(
tl
)
{
var
result
=
new
Array
(
tl
.
length
);
for
(
i
=
0
;
i
<
tl
.
length
;
i
++
)
{
result
[
i
]
=
tl
[
i
].
pageX
+
'
.
'
+
tl
[
i
].
pageY
;
}
return
result
.
join
(
'
,
'
);
}
function
on_touch_start
(
event
)
{
event
.
preventDefault
();
connection
.
send
(
'
TS,
'
+
make_touch_list
(
event
.
touches
));
}
function
on_touch_end
(
event
)
{
// no touch list on this one...
connection
.
send
(
'
TE
'
);
}
function
on_touch_move
(
event
)
{
connection
.
send
(
'
TM,
'
+
make_touch_list
(
event
.
touches
));
}
function
on_key_down
(
event
)
{
connection
.
send
(
'
KD,
'
+
event
.
keyCode
)
}
function
on_key_up
(
event
)
{
connection
.
send
(
'
KU,
'
+
event
.
keyCode
)
}
coro/http/demo/websocket/field/field.py
0 → 100644
View file @
8b0be44e
# -*- Mode: Python -*-
from
coro.http.websocket
import
handler
,
websocket
import
pickle
import
random
import
re
import
quadtree
import
coro
W
=
coro
.
write_stderr
colors
=
[
'red'
,
'green'
,
'blue'
,
'magenta'
,
'purple'
,
'plum'
,
'orange'
]
# sample 'box' object.
class
box
:
def
__init__
(
self
,
color
,
rect
):
self
.
color
=
color
self
.
rect
=
rect
def
get_rect
(
self
):
return
self
.
rect
def
__repr__
(
self
):
return
'<box (%d,%d,%d,%d)>'
%
self
.
rect
class
field
:
def
__init__
(
self
,
w
=
1024
*
20
,
h
=
1024
*
20
):
self
.
w
=
w
self
.
h
=
h
self
.
clients
=
set
()
self
.
Q
=
quadtree
.
quadtree
()
self
.
generate_random_field
()
def
generate_random_field
(
self
):
for
i
in
range
(
5000
):
x
=
random
.
randint
(
0
,
self
.
w
-
100
)
y
=
random
.
randint
(
0
,
self
.
h
-
100
)
w
=
random
.
randint
(
50
,
300
)
h
=
random
.
randint
(
50
,
300
)
c
=
random
.
choice
(
colors
)
b
=
box
(
c
,
(
x
,
y
,
x
+
w
,
y
+
h
))
self
.
Q
.
insert
(
b
)
def
new_conn
(
self
,
*
args
,
**
kwargs
):
c
=
field_conn
(
self
,
*
args
,
**
kwargs
)
self
.
clients
.
add
(
c
)
class
field_conn
(
websocket
):
def
__init__
(
self
,
field
,
*
args
,
**
kwargs
):
websocket
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
send_mutex
=
coro
.
mutex
()
self
.
field
=
field
rx
=
random
.
randint
(
0
,
self
.
field
.
w
-
1024
)
ry
=
random
.
randint
(
0
,
self
.
field
.
h
-
1024
)
self
.
rect
=
(
rx
,
ry
,
rx
+
1024
,
ry
+
1024
)
self
.
draw_window
()
self
.
mouse_down
=
None
,
None
def
move_window
(
self
,
mx
,
my
):
x0
,
y0
,
x1
,
y1
=
self
.
rect
x0
=
x0
+
mx
;
y0
=
y0
+
my
x1
=
x1
+
mx
;
y1
=
y1
+
my
if
x0
<
0
:
x0
=
0
;
x1
=
1024
if
y0
<
0
:
y0
=
0
;
y1
=
1024
if
x1
>
self
.
field
.
w
-
1024
:
x1
=
self
.
field
.
w
-
1024
;
x0
=
x1
-
1024
if
y1
>
self
.
field
.
h
-
1024
:
y1
=
self
.
field
.
h
-
1024
;
y0
=
y1
-
1024
self
.
rect
=
(
x0
,
y0
,
x1
,
y1
)
self
.
draw_window
()
self
.
send_text
(
'M pos=%d,%d'
%
self
.
rect
[:
2
])
def
draw_window
(
self
):
r
=
[
'F'
]
px
,
py
=
self
.
rect
[:
2
]
for
ob
in
self
.
field
.
Q
.
search_gen
(
self
.
rect
):
c
=
ob
.
color
x0
,
y0
,
x1
,
y1
=
ob
.
get_rect
()
r
.
append
(
'B,%s,%d,%d,%d,%d'
%
(
c
,
x0
-
px
,
y0
-
py
,
x1
-
x0
,
y1
-
y0
))
self
.
send_text
(
'|'
.
join
(
r
))
def
send_text
(
self
,
payload
):
with
self
.
send_mutex
:
websocket
.
send_text
(
self
,
payload
)
def
handle_packet
(
self
,
p
):
data
=
p
.
unpack
()
event
=
p
.
unpack
().
split
(
','
)
#W ('packet = %r event=%r\n' % (p, event))
if
event
[
0
]
==
'KD'
:
ascii
=
int
(
event
[
1
])
if
ascii
==
87
:
# W
self
.
move_window
(
0
,
-
10
)
elif
ascii
==
65
:
# A
self
.
move_window
(
-
10
,
0
)
elif
ascii
==
83
:
# S
self
.
move_window
(
0
,
10
)
elif
ascii
==
68
:
# D
self
.
move_window
(
10
,
0
)
elif
ascii
==
82
:
# R
x0
,
y0
=
self
.
rect
[:
2
]
self
.
move_window
(
-
x0
,
-
y0
)
elif
event
[
0
]
==
'MD'
:
self
.
on_mouse_down
(
int
(
event
[
1
]),
int
(
event
[
2
]))
elif
event
[
0
]
==
'MU'
:
self
.
on_mouse_up
(
int
(
event
[
1
]),
int
(
event
[
2
]))
elif
event
[
0
]
==
'MM'
:
self
.
on_mouse_move
(
int
(
event
[
1
]),
int
(
event
[
2
]))
elif
event
[
0
]
==
'TS'
:
tl
=
self
.
unpack_touch_list
(
event
[
1
:])
self
.
on_mouse_down
(
tl
[
0
][
0
],
tl
[
0
][
1
])
elif
event
[
0
]
==
'TM'
:
tl
=
self
.
unpack_touch_list
(
event
[
1
:])
self
.
last_touch_move
=
tl
[
0
][
0
],
tl
[
0
][
1
]
self
.
on_mouse_move
(
tl
[
0
][
0
],
tl
[
0
][
1
])
elif
event
[
0
]
==
'TE'
:
# emulate mouse up by with saved last touch_move
x0
,
y0
=
self
.
last_touch_move
self
.
on_mouse_up
(
x0
,
y0
)
else
:
W
(
'unknown event: %r
\
n
'
%
(
event
,))
return
False
def
unpack_touch_list
(
self
,
tl
):
W
(
'touch_list=%r
\
n
'
%
(
tl
,))
return
[
[
int
(
y
)
for
y
in
x
.
split
(
'.'
)]
for
x
in
tl
]
def
on_mouse_down
(
self
,
x
,
y
):
self
.
mouse_down
=
x
,
y
def
on_mouse_up
(
self
,
x1
,
y1
):
x0
,
y0
=
self
.
mouse_down
self
.
mouse_down
=
None
,
None
# 1) draw a box in the region chosen
#if x0 > x1:
# x0, x1 = x1, x0
#if y0 > y1:
# y0, y1 = y1, y0
#px, py = self.rect[:2]
#b = box (random.choice (colors), (x0+px, y0+py, x1+px, y1+py))
#self.field.Q.insert (b)
# 2) or move the window
self
.
move_window
(
x0
-
x1
,
y0
-
y1
)
self
.
draw_window
()
def
on_mouse_move
(
self
,
x1
,
y1
):
x0
,
y0
=
self
.
mouse_down
if
x0
:
if
abs
(
x1
-
x0
)
>
10
or
abs
(
y1
-
y0
)
>
10
:
# moved enough to redraw
self
.
mouse_down
=
x1
,
y1
self
.
move_window
(
x0
-
x1
,
y0
-
y1
)
if
__name__
==
'__main__'
:
import
coro.http
import
coro.backdoor
import
os
cwd
=
os
.
getcwd
()
f
=
field
()
ih
=
coro
.
http
.
handlers
.
favicon_handler
()
sh
=
coro
.
http
.
handlers
.
coro_status_handler
()
th
=
handler
(
'/field'
,
f
.
new_conn
)
fh
=
coro
.
http
.
handlers
.
file_handler
(
cwd
)
# so you can browse the source
import
mimetypes
mimetypes
.
init
()
mimetypes
.
add_type
(
'text/plain'
,
'.py'
)
handlers
=
[
th
,
ih
,
sh
,
fh
]
#server = coro.http.server (('0.0.0.0', 9001))
server
=
coro
.
http
.
server
()
for
h
in
handlers
:
server
.
push_handler
(
h
)
#coro.spawn (server.start)
coro
.
spawn
(
server
.
start
,
(
'0.0.0.0'
,
9001
))
coro
.
spawn
(
coro
.
backdoor
.
serve
,
unix_path
=
'/tmp/ws.bd'
)
coro
.
event_loop
(
30.0
)
coro/http/demo/websocket/field/quadtree.py
0 → 100644
View file @
8b0be44e
# -*- Mode: Python; tab-width: 4 -*-
# SMR 2012: originally from dynwin, circa 1995-96.
# modernized, replace some funs with generators
#
# Quad-Tree. A 2D spatial data structure.
#
# Used to quickly locate 'objects' within a particular region. Each
# node in the tree represents a rectangular region, while its children
# represent that region split into four quadrants. An 'object' is
# stored at a particular level if it is contained within that region,
# but will not fit into any of the individual quadrants inside it.
#
# If an object is inserted into a quadtree that 'overflows' the current
# boundaries, the tree is re-rooted in a larger space.
import
region
contains
=
region
.
region_contains_region_p
intersects
=
region
.
region_intersect_p
# split a rect into four quadrants
def
split
(
rect
):
l
,
t
,
r
,
b
=
rect
w2
=
((
r
-
l
)
/
2
)
+
l
h2
=
((
b
-
t
)
/
2
)
+
t
return
(
(
l
,
t
,
w2
,
h2
),
(
w2
,
t
,
r
,
h2
),
(
l
,
h2
,
w2
,
b
),
(
w2
,
h2
,
r
,
b
)
)
# insert an object into the tree. The object must have a
# 'get_rect()' method in order to support searching.
def
insert
(
tree
,
tree_rect
,
ob
,
ob_rect
):
quads
=
split
(
tree_rect
)
# If tree_rect is in quads, then we've shrunk down to a
# degenerate rectangle, and we will store the object at
# this level without splitting further.
if
tree_rect
not
in
quads
:
for
i
in
range
(
4
):
if
contains
(
quads
[
i
],
ob_rect
):
if
not
tree
[
i
]:
tree
[
i
]
=
[
None
,
None
,
None
,
None
,[]]
insert
(
tree
[
i
],
quads
[
i
],
ob
,
ob_rect
)
return
tree
[
4
].
append
(
ob
)
# generate all the objects intersecting with <search_rect>
def
search_gen
(
tree
,
tree_rect
,
search_rect
):
quads
=
split
(
tree_rect
)
for
ob
in
tree
[
4
]:
if
intersects
(
ob
.
get_rect
(),
search_rect
):
yield
ob
for
i
in
range
(
4
):
if
tree
[
i
]
and
intersects
(
quads
[
i
],
search_rect
):
for
ob
in
search_gen
(
tree
[
i
],
quads
[
i
],
search_rect
):
yield
ob
# delete a particular object from the tree.
def
delete
(
tree
,
tree_rect
,
ob
,
ob_rect
):
if
tree
[
4
]:
try
:
tree
[
4
].
remove
(
ob
)
# is this branch now empty?
return
(
tree
[
4
]
==
[])
except
ValueError
:
# object not stored here
pass
quads
=
split
(
tree_rect
)
for
i
in
range
(
4
):
if
tree
[
i
]
and
intersects
(
quads
[
i
],
ob_rect
):
if
not
delete
(
tree
[
i
],
quads
[
i
],
ob
,
ob_rect
):
tree
[
i
]
==
None
# equivalent to "tree != [None,None,None,None,[]]"
return
not
filter
(
None
,
tree
)
return
tree
[
4
]
def
gen_all
(
tree
):
if
tree
[
4
]:
for
ob
in
tree
[
4
]:
yield
ob
for
quad
in
tree
[:
4
]:
if
quad
:
for
x
in
gen_all
(
quad
):
yield
x
# wrapper for a quadtree, maintains bounds, keeps track of the
# number of objects, etc...
class
quadtree
:
def
__init__
(
self
,
rect
=
(
0
,
0
,
16
,
16
)):
self
.
rect
=
rect
self
.
tree
=
[
None
,
None
,
None
,
None
,[]]
self
.
num_obs
=
0
self
.
bounds
=
(
0
,
0
,
0
,
0
)
def
__repr__
(
self
):
return
'<quad tree (objects:%d) bounds:%s >'
%
(
self
.
num_obs
,
repr
(
self
.
bounds
)
)
def
check_bounds
(
self
,
rect
):
l
,
t
,
r
,
b
=
self
.
bounds
L
,
T
,
R
,
B
=
rect
if
L
<
l
:
l
=
L
if
T
<
t
:
t
=
T
if
R
>
r
:
r
=
R
if
B
>
b
:
b
=
B
self
.
bounds
=
l
,
t
,
r
,
b
def
get_bounds
(
self
):
return
self
.
bounds
def
insert
(
self
,
ob
):
rect
=
ob
.
get_rect
()
while
not
contains
(
self
.
rect
,
rect
):
l
,
t
,
r
,
b
=
self
.
rect
w
,
h
=
r
-
l
,
b
-
t
# favor growing right and down
if
(
rect
[
2
]
>
r
)
or
(
rect
[
3
]
>
b
):
# resize, placing original in the upper left
self
.
rect
=
l
,
t
,
(
r
+
w
),
(
b
+
h
)
self
.
tree
=
[
self
.
tree
,
None
,
None
,
None
,
[]]
elif
(
rect
[
0
]
<
l
)
or
(
rect
[
1
]
<
t
):
# resize, placing original in lower right
self
.
rect
=
(
l
-
w
,
t
-
h
,
r
,
b
)
self
.
tree
=
[
None
,
None
,
None
,
self
.
tree
,
[]]
# we know the target rect fits in our space
insert
(
self
.
tree
,
self
.
rect
,
ob
,
rect
)
self
.
check_bounds
(
rect
)
self
.
num_obs
=
self
.
num_obs
+
1
def
gen_all
(
self
):
for
ob
in
gen_all
(
self
.
tree
):
yield
ob
def
search_gen
(
self
,
rect
):
for
ob
in
search_gen
(
self
.
tree
,
self
.
rect
,
rect
):
yield
ob
def
delete
(
self
,
ob
):
# we ignore the return, because we can't 'forget'
# the root node.
delete
(
self
.
tree
,
self
.
rect
,
ob
,
ob
.
get_rect
())
# sample 'box' object.
class
box
:
def
__init__
(
self
,
rect
):
self
.
rect
=
rect
def
get_rect
(
self
):
return
self
.
rect
def
__repr__
(
self
):
return
'<box (%d,%d,%d,%d)>'
%
self
.
rect
coro/http/demo/websocket/field/region.py
0 → 100644
View file @
8b0be44e
# -*- Mode: Python; tab-width: 4 -*-
# SMR 2012: originally from dynwin, circa 1995
###########################################################################
# regions
###########################################################################
#
# do two rectangular regions intersect?
#
# +--->
# | lb,tb-------+
# | | |
# | la,ta--+-----+ |
# | | | | |
# | | +-----+-rb,bb
# V | |
# +--------ra,ba
# a rect is (left,top,right,bottom)
# top is < bottom, left is < right
# proof: imagine all possible cases in 1 dimension,
# (there are six) and then generalize. simplify the
# expression and you get this. (trust me 8^)
def
region_intersect_p
(
a
,
b
):
return
(
a
[
2
]
>=
b
[
0
])
and
\
(
b
[
2
]
>=
a
[
0
])
and
\
(
a
[
3
]
>=
b
[
1
])
and
\
(
b
[
3
]
>=
a
[
1
])
def
point_in_region_p
(
x
,
y
,
r
):
return
(
r
[
0
]
<=
x
<=
r
[
2
])
and
(
r
[
1
]
<=
y
<=
r
[
3
])
# does region <a> fully contain region <b>?
def
region_contains_region_p
(
a
,
b
):
return
(
a
[
0
]
<=
b
[
0
])
and
\
(
a
[
2
]
>=
b
[
2
])
and
\
(
a
[
1
]
<=
b
[
1
])
and
\
(
a
[
3
]
>=
b
[
3
])
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment