Mapping coordinates to interact with a 2D Interaction Box - python

I want to detect whether or not a finger (or any object) is pointing at a certain box (on the screen) as shown in the image below.
The following code can be used to get the xy cordinates of the finger but what is the easiest way to define the interaction boxes and then map the cordinates to see if it matches any of the boxes on the outside of the screen.
I am using the latest version of the leap motion SDK (3.2.0) on Windows.
def on_frame(self, controller):
app_width = 800
app_height = 600
# Get the most recent frame and report some basic information
frame = controller.frame()
pointable = frame.pointables.frontmost
if pointable.is_valid:
iBox = frame.interaction_box
leapPoint = pointable.stabilized_tip_position
normalizedPoint = iBox.normalize_point(leapPoint, False)
app_x = normalizedPoint.x * app_width
app_y = (1 - normalizedPoint.y) * app_height
#The z-coordinate is not used
print ("X: " + str(app_x) + " Y: " + str(app_y))
The output then looks like this:
X: 467.883825302 Y: 120.019626617
X: 487.480115891 Y: 141.106081009
X: 505.537891388 Y: 164.418339729
X: 522.712898254 Y: 189.527964592
X: 539.482307434 Y: 213.160014153
X: 556.220436096 Y: 233.744287491
X: 573.109865189 Y: 253.145456314

First of all, this code won't tell you where the finger is pointing. It just tells you where the finger tip is located in space -- an important, but perhaps subtle, distinction.
Since you presumably have your boxes defined in screen coordinates, you could just check every box to see if the finger tip position is inside. Something like:
def check_in_box(box, point):
if point.x > box.left and point.x < box.right
and point.y > box.top and point.y < box.bottom:
return True
else:
return False
This assumes you have a suitable class to represent a 2D box.

Related

How to check if a moving picture is touched to another moving picture

def check_crash():
(x,y) = c.coords(my_car)
for car in other_carss :
(car_x,car_y) = c.coords(car)
if y < (car_y+ other_cars_height) and (y + my_car_height) >= (car_y+ other_cars_height):
if x > car_x and x < (car_x + other_cars_width):
c.delete(car)
lose_a_life()
root.after(100, check_crash)
The canvas has a method named find_overlapping which will return all objects that overlap a given rectangle.

Click-Circle game - clicking outside and inside the circle

I am trying to code a game that has a red circle in which the user is supposed to click up to 7 times in the window. If the user clicks outside the circle, the circle will change its position to where the user clicked. And the game should end when the user has clicked 3 times inside the circle (does not have to be in a row) or when the user has clicked 7 times in total.
I have coded and done quite most of it I think, its just I cant seem to make it work as I want to.
from graphics import *
def draw_circle(win, c=None):
x = random.randint(0,500)
y = random.randint(0,500)
if var is None:
centa = Point(x,y)
var = Circle(centa,50)
var.setFill(color_rgb(200,0,0))
var.draw(win)
else:
p1 = c.p1
x_dif = (p1.x - x) * -1
y_dif = (p1.y - y) * -1
var.move(x_dif, y_dif)
return (var, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
var,x,y = draw_circle(win)
while score <= 7:
mouseClick2=win.getMouse()
if mouseClick2.y >= y-50 and mouseClick2.y <= y +50 and
mouseClick2.x >= x-50 and mouseClick2.x <= x+50:
score=score + random.randint(0,5)
var,x,y = draw_circle(win, c)
print ("Success!")
print (("the score is, {0}").format(score))
thanks for the help in advance!
I see a couple problems.
your if mouseClick2.y >= y-50... conditional is spread out on two lines, but you don't have a line continuation character.
You never call main().
You don't import random.
You call draw_circle in the while loop with an argument of c, but there is no variable by that name in the global scope. You probably meant to pass in var.
c in draw_circle ostensibly refers to the circle object you want to manipulate, but half the time you manipulate var instead of c.
you assign a value to cvar in the loop, but never use it.
Your else block in draw_circle calculates the movement delta by subtracting the cursor coordinates from c.p1. But c.p1 is the upper-left corner of the circle, not the center of the circle. So your hit detection is off by fifty pixels.
import random
from graphics import *
def draw_circle(win, c=None):
x = random.randint(0,500)
y = random.randint(0,500)
if c is None:
centa = Point(x,y)
c = Circle(centa,50)
c.setFill(color_rgb(200,0,0))
c.draw(win)
else:
center_x = c.p1.x + 50
center_y = c.p1.y + 50
x_dif = (center_x - x) * -1
y_dif = (center_y - y) * -1
c.move(x_dif, y_dif)
return (c, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
var,x,y = draw_circle(win)
while score <= 7:
mouseClick2=win.getMouse()
if mouseClick2.y >= y-50 and mouseClick2.y <= y +50 and \
mouseClick2.x >= x-50 and mouseClick2.x <= x+50:
score=score + random.randint(0,5)
var,x,y = draw_circle(win, var)
print ("Success!")
print (("the score is, {0}").format(score))
main()
Additional possible improvements:
Your hit detection checks whether the cursor is in a 50x50 rectangle centered on the circle. You could instead check whether the cursor is inside the circle if you measured the distance between the cursor and the center, and checked whether it was less than the radius.
var and c could stand to have more descriptive names.
mouseClick2 doesn't make much sense as a name, considering there's no mouseClick1.
The movement delta arithmetic could be simplified: (a-b) * -1 is the same as (b-a).
If you only use a variable's value once, you can sometimes avoid creating the variable at all if you nest expressions.
it might be nice to define constants, such as for the circle's radius, instead of having magic numbers in your code.
You can save five characters by using += to increment the score.
import math
import random
from graphics import *
RADIUS = 50
def draw_circle(win, circle=None):
x = random.randint(0,500)
y = random.randint(0,500)
if circle is None:
circle = Circle(Point(x,y),RADIUS)
circle.setFill(color_rgb(200,0,0))
circle.draw(win)
else:
circle.move(
x - circle.p1.x - RADIUS,
y - circle.p1.y - RADIUS
)
return (circle, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
circle,x,y = draw_circle(win)
while score <= 7:
cursor = win.getMouse()
if math.hypot(cursor.x - x, cursor.y - y) <= RADIUS:
score += random.randint(0,5)
circle,x,y = draw_circle(win, circle)
print ("Success!")
print (("the score is, {0}").format(score))
main()
I'm not really a python guy, but I see that your hitbox is wrong. If there are any other issues then comment it/them to me.
Solving hitbox to be circle:
What you have already written is good to have thing but you should check if click was in circle not square. Pythagoras triangle is solution for this.
Check:
if (math.sqrt(delta_x **2 + delta_y **2) <= circle_radius)
where delta_x and delta_y is center coordinate minus mouse position

Creating a Button (from image) in Zelle's Graphics

I have a start button image that I am trying to turn into a button in my program. However, I believe I am doing the math wrong or something wrong obviously because it's not working. Basically, what I am trying to do is if the person clicks on the button, it will initiate an if statement. Any ideas? Thanks in advance!
#Assigning Mouse x,y Values
mousePt = win.getMouse()
xValue = startImage.getHeight()
yValue = startImage.getWidth()
#Assigning Buttons
if mousePt <= xValue and mousePt <= yValue:
hour = 2
startImage is the image I want to make a button. hour is a variable stated in other code.
You're comparing apples to oranges. This line:
if mousePt <= xValue and mousePt <= yValue:
is roughly the same as saying:
if Point(123, 45) <= 64 and Point(123, 45) <= 64:
It makes no sense to compare Points to widths and heights. You need to combine the widths and heights with the center position of the image and extract the X & Y values from the mouse position:
from graphics import *
win = GraphWin("Image Button", 400, 400)
imageCenter = Point(200, 200)
# 64 x 64 GIF image from http://www.iconsdb.com/icon-sets/web-2-green-icons/video-play-icon.html
startImage = Image(imageCenter, "video-play-64.gif")
startImage.draw(win)
imageWidth = startImage.getWidth()
imageHeight = startImage.getHeight()
imageLeft, imageRight = imageCenter.getX() - imageWidth/2, imageCenter.getX() + imageWidth/2
imageBottom, imageTop = imageCenter.getY() - imageHeight/2, imageCenter.getY() + imageHeight/2
start = False
while not start:
# Obtain mouse Point(x, y) value
mousePt = win.getMouse()
# Test if x,y is inside image
x, y = mousePt.getX(), mousePt.getY()
if imageLeft < x < imageRight and imageBottom < y < imageTop:
print("Bullseye!")
break
win.close()
This particular icon shows up as a circle, the area you can click includes its rectangular bounding box, some of which is outside the circle. It's possible to limit the clicks to exactly the visible image but that takes more work.

Checking if clicks are within a graphic object [Python Graphics Module]

Here is the module I'm using: http://mcsp.wartburg.edu/zelle/python/graphics/graphics.pdf
I want to see whether a user's clicks are within a shape or not. I used the in operator, but I know that is incorrect. Below is a chunk of my code:
win = GraphWin("Click Speed", 700, 700)
theTarget = drawTarget(win, random.randrange(0,685), random.randrange(0,685))
while theTarget in win:
click = win.getMouse()
if click in theTarget:
print("Good job")
I left out the code that draws theTarget shape because it is length and unnecessary. It is a moving circle.
I'm using a while loop so it allows me to constantly get the user's clicks.
How do I go about checking whether or not a user's clicks are in the specified Target shape by using the getMouse() command?
I'm going to have to use this in the future for more abstract shapes (not simple circles).
Circle
For the simple case of a circle, you can determine whether the mouse is inside using the distance formula. For example:
# checks whether pt1 is in circ
def inCircle(pt1, circ):
# get the distance between pt1 and circ using the
# distance formula
dx = pt1.getX() - circ.getCenter().getX()
dy = pt1.getY() - circ.getCenter().getY()
dist = math.sqrt(dx*dx + dy*dy)
# check whether the distance is less than the radius
return dist <= circ.getRadius()
def main():
win = GraphWin("Click Speed", 700, 700)
# create a simple circle
circ = Circle(Point(350,350),50)
circ.setFill("red")
circ.draw(win)
while True:
mouse = win.getMouse()
if inCircle(mouse,circ):
print ("Good job")
main()
Oval
For the more advanced example of an ellipse we will need to use a formula found here. Here is the function implemting that:
def inOval(pt1, oval):
# get the radii
rx = abs(oval.getP1().getX() - oval.getP2().getX())/2
ry = abs(oval.getP1().getY() - oval.getP2().getY())/2
# get the center
h = oval.getCenter().getX()
k = oval.getCenter().getY()
# get the point
x = pt1.getX()
y = pt1.getY()
# use the formula
return (x-h)**2/rx**2 + (y-k)**2/ry**2 <= 1
Polygon
For a polygon of abitrary shape we need to reference this. I have converted that to a python equivalent for you. Check the link to see why it works because I am honestly not sure
def inPoly(pt1, poly):
points = poly.getPoints()
nvert = len(points) #the number of vertices in the polygon
#get x and y of pt1
x = pt1.getX()
y = pt1.getY()
# I don't know why this works
# See the link I provided for details
result = False
for i in range(nvert):
# note: points[-1] will give you the last element
# convenient!
j = i - 1
#get x and y of vertex at index i
vix = points[i].getX()
viy = points[i].getY()
#get x and y of vertex at index j
vjx = points[j].getX()
vjy = points[j].getY()
if (viy > y) != (vjy > y) and (x < (vjx - vix) * (y - viy) / (vjy - viy) + vix):
result = not result
return result

TurtleGraphics Python: Bouncing turtle off the walls?

So, I am trying to make a realistic bouncing function, where the turtle hits a wall and bounces off at the corresponding angle. My code looks like this:
def bounce(num_steps, step_size, initial_heading):
turtle.reset()
top = turtle.window_height()/2
bottom = -top
right = turtle.window_width()/2
left = -right
turtle.left(initial_heading)
for step in range(num_steps):
turtle.forward(step_size)
x, y = turtle.position()
if left <= x <= right and bottom <= y <= top:
pass
else:
turtle.left(180-2 * (turtle.heading()))
So, this works for the side walls, but I don't get how to make it bounce correctly off the top/bottom. Any suggestions?
Try something like this:
if not (left <= x <= right):
turtle.left(180 - 2 * turtle.heading())
elif not (bottom <= y <= top):
turtle.left(-2 * turtle.heading())
else:
pass
My python syntax is a little rusty, sorry :P. But the math is a little different for a horizontal vs. a vertical flip.
EDIT:
I suspect that what is happening is your turtle is getting into a situation where it is pointing upwards and stuck above the top wall. That would lead it to just flip indefinitely. You could try adding the following conditions:
if (x <= left and 90 <= turtle.heading() <= 270) or (right <= x and not 90 <= turtle.heading() <= 270):
turtle.left(180 - 2 * turtle.heading())
elif (y <= bottom and turtle.heading() >= 180) or (top <= y and turtle.heading <= 180):
turtle.left(-2 * turtle.heading())
else:
pass
If that works, there is probably a bug elsewhere in your code. Edge handling is tricky to get right. I assume that turtle.heading() will always return something between 0 and 360 - if not then it will be even more tricky to get right.
Gday,
Your problem seems to be that you are using the same trigonometry to calculate the right and left walls, as you are the top and bottom. A piece of paper and a pencil should suffice to calculate the required deflections.
def inbounds(limit, value):
'returns boolean answer to question "is turtle position within my axis limits"'
return -limit < value * 2 < limit
def bounce(num_steps, step_size, initial_heading):
'''given the number of steps, the size of the steps
and an initial heading in degrees, plot the resultant course
on a turtle window, taking into account elastic collisions
with window borders.
'''
turtle.reset()
height = turtle.window_height()
width = turtle.window_width()
turtle.left(initial_heading)
for step in xrange(num_steps):
turtle.forward(step_size)
x, y = turtle.position()
if not inbounds(height, y):
turtle.setheading(-turtle.heading())
if not inbounds(width, x):
turtle.setheading(180 - turtle.heading())
I've used the setheading function and a helper function (inbounds) to further declare the intent of the code here. Providing some kind of doc-string is also good practice in any code that you write (provided the message it states is accurate!!)
Your mileage may vary on the use of xrange, Python 3.0+ renames it to simply range.

Categories