How to determine collision in python in right way - python

Here I have made a code to create random sized bubbles which can be destroyed by collision of another object:
import tkinter
window = tkinter.Tk()
window.title("...")
c = tkinter.Canvas(width=800, height=500, bg="...")
ojct_id1 = c.create_polygon(...)
ojct_id2 = c.create_oval(...) # A polygon in an oval should constitute the object
def move ojct(event):
...
from random import randint
bubbles = list()
bubbles_r = list() # radius
bubbles_speed = list()
def create_bub():
...
def move_bubbles():
...
from time import sleep
while True:
if randint(1, 10) == 1:
create_bub()
move_bubbles()
window.update()
sleep(0.01)
The following code determines the position of any bubble:That helps to find out collision.
def hole_coord(id_num):
pos = c.coords(id_num)
x = (pos[0] + pos[2])/2
y = (pos[1] + pos[3])/2
return x, y
Now I have to make func. for deleting bubbles:
def del_bubbles():
del bubbles_r[i]
del bubbles_speed[i]
c.delete(bubbles[i])
del bubbles[i]
The following code determines, if the two objects are colliding:
from math import sqrt
def distance(id1, id2):
x1, y1 = hole_coord(id1)
x2, y2 = hole_coord(id2)
return sqrt((x2 - x1)/2 + (y2 - y1)/2)
def collision():
for bub in range(len(bubbles)-1, -1, -1):
if distance(ojct_id2, bubbles[bub]) < (15 + bubbles_r[bub]):
del_bubbles(bub)
Here it is sth. wrong: bubbles get deleted without a hit but if they are hit
often they don't get deleted. Can anybody help me? Thanks!

You are not computing the euclidean distance correctly.
def distance(id1, id2):
x1, y1 = hole_coord(id1)
x2, y2 = hole_coord(id2)
return sqrt((x2 - x1)/2 + (y2 - y1)/2) # <----- this is wrong
should be
def distance(id1, id2):
x1, y1 = hole_coord(id1)
x2, y2 = hole_coord(id2)
return sqrt((x2 - x1)**2 + (y2 - y1)**2) # <----- square instead of halve

Related

How to limit Voronoi cells even when infinite with python?

I want to limit infinite Voronoi regions to be on stage. So for the sample:
I want to have regions not infinite.
I'm trying to understand scipy.spartial.Voronoi documentation for many days. I've managed to link points with regions, but regions with vertices (my code). I also modified voronoi_plot_2d function to get limited ridges:
import numpy as np
from scipy.spatial import Voronoi
import matplotlib.pyplot as plt
from plotutils_moje import voronoi_plot_2d
class VoronoiPlaceholders:
def __init__(self, vertex1, point_idxs, points, vertex_placeholder=None, vertex2=None):
self.vertex1 = vertex1
self.vertex2 = vertex2
self.vertex_placeholder = vertex_placeholder
self.point_idxs = point_idxs
self.points = points
def __str__(self):
text = f'VoronoiPlaceholders(v1:{self.vertex1},'
if self.vertex2:
text = f'{text} v2:{self.vertex2};'
if self.vertex_placeholder:
text = f'{text} v2~{self.vertex_placeholder};'
text = f'{text} p1:{self.points[0]} ({self.point_idxs[0]}) and p2:{self.points[1]} ({self.point_idxs[1]}))'
return text
def __repr__(self):
return str(self)
def point_index_belongs_to(self, point_index):
return point_index in self.point_idxs
def is_precise_vertex2_available(self):
if self.vertex2:
return True
return False
def calculate_placeholders_for_all_points(vor):
""" inspiration: https://github.com/scipy/scipy/blob/main/scipy/spatial/_plotutils.py#L231-L261 """
center = vor.points.mean(axis=0)
ptp_bound = vor.points.ptp(axis=0)
infinite_segments = []
finite_segments = []
index = -1
for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):
simplex = np.asarray(simplex)
index += 1
point1 = vor.points[pointidx[0]]
point2 = vor.points[pointidx[1]]
p1, p2 = pointidx
if np.all(simplex >= 0):
vertex1, vertex2 = vor.vertices[simplex]
x1, y1 = vertex1
x2, y2 = vertex2
vor_obj = VoronoiPlaceholders(vertex1=(x1, y1), vertex2=(x2, y2),
point_idxs=(p1, p2), points=(point1, point2))
finite_segments.append(vor_obj)
continue
i = simplex[simplex >= 0][0] # finite end Voronoi vertex
t = vor.points[pointidx[1]] - vor.points[pointidx[0]] # tangent
t /= np.linalg.norm(t)
n = np.array([-t[1], t[0]]) # normal
midpoint = vor.points[pointidx].mean(axis=0)
direction = np.sign(np.dot(midpoint - center, n)) * n
if vor.furthest_site:
direction = -direction
far_point = vor.vertices[i] + direction * ptp_bound.max()
x1, y1 = vor.vertices[i]
x2, y2 = far_point
vor_obj = VoronoiPlaceholders(vertex1=(x1, y1), vertex_placeholder=(x2, y2),
point_idxs=(p1, p2), points=(point1, point2))
infinite_segments.append(vor_obj)
return infinite_segments + finite_segments
But I don't have idea how to connect ridges with finite vertices with regions. Could somebody help?

Python 2.7 Inheriting Values from a Class which Inherits Values from User Input

Learning Python and making a program... I have read the docs and forums on inheritance, but am struggling to wrap my head around this while trying to implement it. Can someone please help me understand?
I understand, I think, inheritance from user defined data into a class, I successfully implemented it. But now I want to have another class inherit from the class that inherits the user defined data, a second degree inheritance?
I am building a program that uses some heavy math. I have a portion which a user will define: angle, x0:x5, and y0:y5. Then I have a class calculate_xy_at_angle that takes the user defined data and calculates the new x and y points.
Then I have another class that will take the new x and y points and calculate ax:fx and ay:fy for a polynomial equation. My code is as follows (I cut out the code after x2... as it is long and you get the picture)
My problem is that I don't understand how the values from
class calculate_xy_at_angle
pass their calculated values to
class abcdef_of_x?
And once a user defines the data, how do I retrieve the values from the last class? What do I have to do, in a sense, to get the pipeline started?
### Placeholders for User defined data
angle = 30
x0 = 0
x1 = 1
x2 = 5
x3 = 7
x4 = 5
x5 = 1
y0 = 0
y1 = 5
y2 = 8
y3 = 9
y4 = 2
y5 = 0
class calculate_xy_atangle(object):
def __init__(self,angle,x0,x1,x2,x3,x4,x5,y0,y1,y2,y3,y4,y5): # will be user defined data
self.angle = angle
self.x0 = x0
self.x1 = x1
self.x2 = x2
self.x3 = x3
self.x4 = x4
self.x5 = x5
self.y0 = y0
self.y1 = y1
self.y2 = y2
self.y3 = y3
self.y4 = y4
self.y5 = y5
### x
def x0_at_angle(self):
x_0 = (self.x0*math.cos(math.radians(self.angle)))-(self.y0*math.sin(math.radians(self.angle)))
print x_0
return x_0
def x1_at_angle(self):
x_1 = (self.x1*math.cos(math.radians(self.angle)))-(self.y1*math.sin(math.radians(self.angle)))
print x_1
return x_1
def x2_at_angle(self):
x_2 = (self.x2*math.cos(math.radians(self.angle)))-(self.y2*math.sin(math.radians(self.angle)))
print x_2
return x_2
#### more code
### y
def y0_at_angle(self):
y_0 = (self.x0*math.sin(math.radians(self.angle)))+(self.y0*math.cos(math.radians(self.angle)))
print y_0
return y_0
def y1_at_angle(self):
y_1 = (self.x1*math.sin(math.radians(self.angle)))+(self.y1*math.cos(math.radians(self.angle)))
print y_1
return y_1
def y2_at_angle(self):
y_2 = (self.x2*math.sin(math.radians(self.angle)))+(self.y2*math.cos(math.radians(self.angle)))
print y_2
return y_2
### more code
class abcdef_of_x(calculate_xy_atangle): # should inherit values from previous class
def __init__(self,.....???): # this is where I am stuck on how to initialize and define
self.x0 = x0 # ?
self.x1 = x1 # ?
self.x2 = x2
self.x3 = x3
self.x4 = x4
self.x5 = x5
def ax(self):
ax = (-1*self.x0)+(5*self.x1)+(-10*self.x2)+(10*self.x3)+(-5*self.x4)+(self.x5)
print "ax =", ax
return ax
def bx(self):
bx = (5*self.x0)+(-20*self.x1)+(30*self.x2)+(-20*self.x3)+(5*self.x4)
print "bx =", bx
return bx
def cx(self):
cx = (-10*self.x0)+(30*self.x1)+(-30*self.x2)+(10*self.x3)
print "cx =", cx
return cx
## more code
class abcdef_of_y(object): # this should also inherit from first class
def __init__(self, y0, y1, y2, y3, y4, y5):
self.y0 = y0
self.y1 = y1
self.y2 = y2
self.y3 = y3
self.y4 = y4
self.y5 = y5
def ay(self):
ay = (-1 * self.y0) + (5 * self.y1) + (-10 * self.y2) + (10 * self.y3) + (-5 * self.y4) + (self.y5)
print "ay =", ay
return ay
def by(self):
by = (5 * self.y0) + (-20 * self.y1) + (30 * self.y2) + (-20 * self.y3) + (5 * self.y4)
print "by =", by
return by
### more code
Ok, you missed out a little big thing so I, will just state the point you should remember that is sufficient for you to solve the problem
class claculate_xy_atangle(object):
def __init__(self, x, y):
self.x = x
self.y = y
class abcdef_of_x(calculate_xy_atangle):
def __init__(self):
super().__init__(x, y) #call the parent class constructor which is prerogative of the child class
def get_x_y():
return self.x, self.y
if __name__ == "__main__":
child = abcdef_of_x(12, 10)
x, y = child.get_x_y() #This give the value 12, 10
Now you will get a doubt why not the super class calculate_xy_atangle doesn't call super().____init____(), by default python does it for you since every class inherits the super class object.

Build image using Turtle World, python

Here are my code that uses instruction from a text file to build an image... the instruction assign a turtle and a direction x and y, for example: 1, 100, 100. Uses the turtle number one this turtle goes to x = 100 and y = 100.
from swampy.TurtleWorld import *
def draw_to(t,x,y,steps):
x_diff = x - t.get_x()
x_step = 1.0*x_diff/steps
y_diff = y - t.get_y()
y_step = 1.0*y_diff/steps
for step in range(steps):
t.fd(x_step)
t.lt()
t.fd(y_step)
t.rt()
def process (s,tlist):
parts = s.split(',')
t = tlist[int(parts[0])-1]
x = int(parts[1])
y = int(parts[2])
draw_to(t,x,y,50)
fturtles = open('turtles.txt','r')
instructions = fturtles.readlines()
fturtles.close()
world = TurtleWorld()
turtle_list = []
num_turtles = int(instructions[0])
for tNum in range(num_turtles):
new_turtle = Turtle(world)
new_turtle.set_delay(0.01)
turtle_list.append(new_turtle)
for lineNum in range(1,len(instructions)):
process(instructions[lineNum],turtle_list)
print "just processed", instructions[lineNum]
wait_for_user()
The code works fine, the problem is i tried to improve the functionality by changing the color of the pen of turtle, for example, in text file if i put : 1,100, 100, red, it will tell the turtle to use the color red. I tried to use that in a new function but i dont have any idea how to do that. If somebody can help me to clarify how to do that, it will be aprecciated.
How about redefining your process() function as follows:
STEPS = 50
# ...
def process(instruction, turtle_list):
index, x, y, color = instruction.split(',')
t = turtle_list[int(index) - 1]
t.set_pen_color(color.strip())
draw_to(t, int(x), int(y), STEPS)
Using a simple turtle.txt file:
3
1, 100, 100, red
2, 100, 0, blue
3, 0, 100, green
I get:
My rework of your code follows but note that I used Python 3 and the turtle module that comes with it, not TurtleWorld, but most things map over fairly well:
import sys
from turtle import *
class TurtleWorld(Turtle):
""" for Turtle World compatibility """
def set_pen_color(self, *args):
return self.pencolor(*args)
def get_x(self): return self.xcor()
def get_y(self): return self.ycor()
STEPS = 50
DELAY = 0
instruction_filename = sys.argv[1]
def draw_to(t, x, y, steps):
x_diff = x - t.get_x()
x_step = x_diff / float(steps)
y_diff = y - t.get_y()
y_step = y_diff / float(steps)
for step in range(steps):
t.fd(x_step)
t.lt(90)
t.fd(y_step)
t.rt(90)
def process(instruction, turtle_list):
index, x, y, color = instruction.split(',')
t = turtle_list[int(index) - 1]
t.set_pen_color(color.strip())
draw_to(t, int(x), int(y), STEPS)
instruction_file = open(instruction_filename)
instructions = instruction_file.readlines()
instruction_file.close()
turtle_list = []
num_turtles = int(instructions[0])
for tNum in range(num_turtles):
new_turtle = TurtleWorld()
turtle_list.append(new_turtle)
delay(DELAY)
for instruction in instructions[1:]:
process(instruction, turtle_list)
print("just processed", instruction)
exitonclick()

How to extend a line segment in both directions

I've been stuck on this annoying problems for eons. I'm trying to write code so that I can scale a line segment meaning if the amount that I was to scale by(for example) is 2 and the current length of the line is 33 it will increase the entire length to 67. Meaning I add half to the beginning and half to the end...
new front ---a--------b--- new back... But I'm having trouble translating it into code. Here is an example of the code.. The endpoints method should return the endpoints in a tuple such as (p1, p2)
from point import Point
import math
class Line:
def __init__(self,aPoint=Point(), bPoint=Point()):
self.firstPoint = aPoint
self.secondPoint = bPoint
def getEndPoints(self):
return (self.firstPoint, self.secondPoint)
def scale(self,factor):
if factor < 1:
x1 = self.firstPoint.x +(self.secondPoint.x - self.firstPoint.x) * (factor)
x2 = self.secondPoint.x +(self.firstPoint.x - self.secondPoint.x) * (factor)
print(str(x1))
y1 = self.firstPoint.y +(self.secondPoint.y - self.firstPoint.y) * (factor)
y2 = self.secondPoint.y +(self.firstPoint.y - self.secondPoint.y) * (factor)
else:
x1 = -(self.firstPoint.x +(self.secondPoint.x - self.firstPoint.x) * (factor))
x2 = -(self.secondPoint.x +(self.firstPoint.x - self.secondPoint.x) * (factor))
y1 = self.firstPoint.y +(self.secondPoint.y - self.firstPoint.y) * (factor)
y2 = self.secondPoint.y +(self.firstPoint.y - self.secondPoint.y) * (factor)
self.firstPoint = Point(x1, y1)
self.secondPoint = Point(x2, y2)
if __name__ == "__main__":
p1 = Point(5,5)
p2 = Point(20,35)
l1 = Line(p1,p2)
l1.scale(2)
p5 = Point(-2.5,-10)
p6 = Point(27.5,50)
assert l1.getEndPoints() == (p5,p6)
These tests are not working correctly but the above are.. I'm getting a(5.0, 5.0) and b(20.0, 35.0)
l1.scale(0.5)
p5 = Point(8.75,12.5)
p6 = Point(16.25,27.5)
class Point:
'''Point class represents and manipulates
x,y coordinates.'''
def __init__(self,x=0,y=0):
'''Create a new point with default
x,y coordinates at 0,0.'''
self.x = x
self.y = y
def distanceTo(self,aPoint):
return ((self.x-aPoint.x) ** 2 + (self.y-aPoint.y) ** 2)** .5
not sure if I get it right but
use linear interpolation (parametric line equation)
You got line defined by endpoints p0,p1 in form of vectors so any point on it is defined as:
p(t)=p0+(p1-p0)*t
where p(t) is the point (vector) and t is scalar parameter in range
t=<0.0,1.0>
if you do not know the vector math then rewrite it to scalars
x(t)=x0+(x1-x0)*t
y(t)=y0+(y1-y0)*t
so if t=0 then you get the point p0 and if t=1 then you get the point p1
Now just rescale the t range
so you have scale s
t0=0.5-(0.5*s)` ... move from half of line by scale towards p0
t1=0.5+(0.5*s)` ... move from half of line by scale towards p1
so new endpoints are
q0=p0+(p1-p0)*t0
q1=p0+(p1-p0)*t1
[edit1] I see it like this
def scale(self,factor):
t0=0.5*(1.0-factor)
t1=0.5*(1.0+factor)
x1 = self.firstPoint.x +(self.secondPoint.x - self.firstPoint.x) * t0
y1 = self.firstPoint.y +(self.secondPoint.y - self.firstPoint.y) * t0
x2 = self.firstPoint.x +(self.secondPoint.x - self.firstPoint.x) * t1
y2 = self.firstPoint.y +(self.secondPoint.y - self.firstPoint.y) * t1
self.firstPoint = Point(x1, y1)
self.secondPoint = Point(x2, y2)
Take in mind I do not code in python so handle with prejudice ...
For a scale factor s, the coordinates of the new points are given by
Xa' = Xa (1+s)/2 + Xb (1-s)/2
Ya' = Ya (1+s)/2 + Yb (1-s)/2
Xb' = Xb (1+s)/2 + Xa (1-s)/2
Yb' = Yb (1+s)/2 + Ya (1-s)/2
With the common metrik, you only need to adjust each dimension seperately.
I rewrote some parts of the code, to fit it better to the usual Python style
You might want to work through the things, you are unfamiliar with to save yourself a lot of time in the future.
class Line:
def __init__(self, point_one, point_two):
self.point_one = point_one
self.point_two = point_two
def __str__(self):
return 'Line(p1:{},p2:{})'.format(self.point_one, self.point_two)
#property
def points(self):
return self.point_one, self.point_two
#property
def length(self):
return ((self.point_one.x - self.point_two.x)**2 + (self.point_one.y - self.point_two.y)**2)**0.5
def scale(self, factor):
self.point_one.x, self.point_two.x = Line.scale_dimension(self.point_one.x, self.point_two.x, factor)
self.point_one.y, self.point_two.y = Line.scale_dimension(self.point_one.y, self.point_two.y, factor)
#staticmethod
def scale_dimension(dim1, dim2, factor):
base_length = dim2 - dim1
ret1 = dim1 - (base_length * (factor-1) / 2)
ret2 = dim2 + (base_length * (factor-1) / 2)
return ret1, ret2
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point(x={},y={})'.format(self.x, self.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
if __name__ == "__main__":
p1 = Point(5, 5)
p2 = Point(20, 35)
l1 = Line(p1, p2)
print(l1)
print(l1.length)
l1.scale(2)
print(l1)
print(l1.length)
p5 = Point(-2.5, -10)
p6 = Point(27.5, 50)
assert l1.points == (p5, p6)
Note, that the scale method modifies the orginal line and points. If you want to get a new line, the method should be:
def scale(self, factor):
x1, x2 = Line.scale_dimension(self.point_one.x, self.point_two.x, factor)
y1, y2 = Line.scale_dimension(self.point_one.y, self.point_two.y, factor)
return Line(Point(x1, y1), Point(x2, y2))

Rectangle Enclosure (Python3)

I am trying to create a solution to this problem, with my code focusing on looping(for and while):
Let parameter Q be a list of "rectangles", specified by width, height,
and (x,y)-location of the lower left corner. Enclosure(Q) returns the
smallest rectangle that contains each rectangle in Q . The way a
rectangle is represented is by tuple, (x,y,width,height).
Here is my code so far:
def Enclosure(Q):
c = []
d = []
for (x,y,width,height) in sorted(Q):
c.append(x)
d.append(y)
print(c)
print(min(c))
e=tuple([min(c)]+[min(d)])
print(e)
Ignore the print statements, those are only there for debugging purposes. My code to this point creates a tuple of the (x,y) coordinates of the lower left corner of the enclosing rectangle that I am trying to have the program form. But after this point, I have absolutely no idea on how to find the (height,width) of the enclosing rectangle. How can I do that?
Also, here is an example of the program should do when it runs:
R1 = (10,20,5,100) #R1,R2,R3 are each rectangles
R2 = (15,5,30,150) #layout of the tuple:(x,y,width,height)
R3 = (-4,30,20,17)
Enclosure([R1,R2,R3])
(-4, 5, 49, 150) #rectangle that encloses R1,R2,R3
Try this:
def Enclosure(Q):
c = []
d = []
x2 = []
y2 = []
for (x,y,width,height) in sorted(Q):
c.append(x)
d.append(y)
x2.append(width + x)
y2.append(height + y)
e = tuple([min(c)]+[min(d)] + [max(x2) - min(c)] + [max(y2) - min(d)])
print(e)
You could replace e = tuple... to:
e=(min(c), min(d), max(x2) - min(c), max(y2) - min(d)) # This makes a tuple directly
to avoid making first a list, and converting it to tuple as you did.
Make sure you can explain why you used inheritance or your teacher will know you are cheating:
class Geometry(object):
def __init__(self, x, y):
self.x = x
self.y = y
class Point(Geometry):
def __repr__(self):
return "<Point at {s.x},{s.y}>".format(s=self)
class Rectangle(Geometry):
def __init__(self, x, y, width, height):
super(Rectangle, self).__init__(x, y)
self.width = width
self.height = height
#property
def oposite_corner(self):
return Point(self.x + self.width, self.y + self.height)
def __repr__(self):
return "<Rectange of {s.width}x{s.height} at {s.x},{s.y}>".format(s=self)
def enclosing_rectangle(rect_list):
x1, y1, x2, y2 = (
min([r.x for r in rect_list]),
min([r.y for r in rect_list]),
max([r.oposite_corner.x for r in rect_list]),
max([r.oposite_corner.y for r in rect_list]),
)
return Rectangle(x1, y1, x2 - x1, y2 - y1)
Please test and fix any bug by yourself (hint: super changed):
>>> l = [Rectangle(1, 2, 3, 4), Rectangle(-1, -1, 1, 1), Rectangle(3, 4, 1, 1)]
>>> enclosing_rectangle(l)
<Rectangle of 5x7 at -1,-1>
[update]
What?!? A delete vote? Care to explain what is so offensive with this answer?

Categories