Python Circle Shape Collison Class - python

this code needs to take in a x, y, and radius for 2 circles that is input by me and see if it collides. i'm confused on the circle class part on the collision and distance methods. i already typed in the formula which i think is correct to find the distance but i don't know how to call c1 and c2 coordinates so that part i know is wrong. as for the collision i was planning to write a if statement checking if the sum of c1 and c2 radius is equal or greater than the distance, that i also don't know how to do. so if anyone could help it is very much appreciated. also my professor gave us main class part and i don't understand why he put a for loop there so i don't know what that loop is for
class Shape:
"""Shape class: has methods move(), location(), and __init__().
Complete the location() method."""
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
self.x = self.x + deltaX
self.y = self.y + deltaY
def location(self):
'''Returns a tuple containing the ~x,y~ coordinates of an object.
return "Circle at coordinates (%d, %d)"\ % (self.x, self.y)
pass
class Circle(Shape):
"""Circle is a sub-class of shape and inherits the move() and location() methods."""
pi = 3.14159
def __init__(self, x=0, y=0, r=1):
Shape.__init__(self, x, y)
self.radius = r
def area(self):
return self.radius * self.radius * self.pi
def __str__(self):
return "Circle of radius %s at coordinates (%d, %d)"\ % (self.radius, self.x, self.y)
# Class methods
#classmethod
def is_collision(Circle, c1, c2):
'''Return True or None'''
if c1.r + c2.r >= dist:
pass # fill this in
else:
not
#classmethod
def distance(Circle, c1, c2):
"""calculate distance between two circles"""
dist = math.sqrt(((c1.x-c2.x)**2)+((c1.y-c2.y)**2))
pass
from shape import Shape
from circle import Circle
c1 = Circle(100, 100, 100)
c2 = Circle(150, 150, 100)
c1_xdelta = 2
c1_ydelta = 3
c2_xdelta = 1
c2_ydelta = -1
for i in range(1,20):
c1.move(c1_xdelta, c1_ydelta)
c2.move(c2_xdelta, c2_ydelta)
# Print c1.__str__()
print(c1)
# Print c2.__str__()
print(c2)
# Print collision True or None
print("Collision: {collision}".format(collision = Circle.is_collision())
Example Output:
~Circle~ 1: Circle: x,y; coordinates: 0, 0; radius: 5.
~Circle~ 2: Circle: x,y; coordinates: 0, 0; radius: 5.
Collision: True
~Circle~ 1: Circle: x,y; coordinates: 16, 16; radius: 5.
~Circle~ 2: Circle: x,y; coordinates: 16, 136; radius: 5.
Collision: None

After correcting the collision() and distance() methods, your code should look something like:
import math
class Shape:
"""Shape class: has methods move(), location(), and __init__()."""
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
self.x = self.x + deltaX
self.y = self.y + deltaY
def location(self):
return "Circle at coordinates (%d, %d)" % (self.x, self.y)
class Circle(Shape):
"""Circle is a sub-class of shape and inherits the move() and location() methods."""
pi = 3.14159
def __init__(self, x=0, y=0, r=1):
Shape.__init__(self, x, y)
self.radius = r
def area(self):
return self.radius * self.radius * self.pi
def __str__(self):
return "Circle of radius %s at coordinates (%d, %d)" % (self.radius, self.x, self.y)
# Class methods
#classmethod
def is_collision(Circle, c1, c2):
'''Return True or False'''
return c1.radius + c2.radius >= Circle.distance(c1, c2)
#classmethod
def distance(Circle, c1, c2):
"""calculate distance between two circles"""
return math.sqrt(((c1.x-c2.x)**2)+((c1.y-c2.y)**2))
Example use:
from circle import Circle
c1 = Circle(0, 0, 5)
c2 = Circle(0, 0, 5)
print(c1)
print(c2)
print("Collision: {collision}".format(collision = Circle.is_collision(c1, c2)))
c1.move(16, 16)
c2.move(16, 136)
print(c1)
print(c2)
print("Collision: {}".format(Circle.is_collision(c1, c2)))
Example output:
Circle of radius 5 at coordinates (0, 0)
Circle of radius 5 at coordinates (0, 0)
Collision: True
Circle of radius 5 at coordinates (16, 16)
Circle of radius 5 at coordinates (16, 136)
Collision: False

Related

Use object from one class as attribute for another class

I am trying to make a circle which asks only for a center and radius. Here is my code:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {(self.center), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
What am I doing wrong?
You can assign the __repr__ method to your point class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point: {self.x, self.y}"
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {((self.center)), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
It looks like you're not actually getting any info from the class that's being passed, and just trying to print the object itself. I haven't tested this code myself but try
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {((self.center.x),(self.center.y)), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
or use another function that returns the string to be printed:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
def get_point(self):
return f'Point: {self.x, self.y}'
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {self.center.get_point()},{self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()

I'm trying to generate an output of Sierpinski Triangle. I was wondering how to use the midpt function in the 2d point class to achieve this output?

I have to generate the Sierpinski Triangle using a 2d point class and tkinter canvas.The midpt function is essentially going to take input from a randomly chosen vertex and the last plotted midpoint. You can choose any vertices to plot the first midpoint. The points also need to be instances of the 2d point class. I desperately need help because I can't seem to figure this out. Here is what the output is supposed to look like.
This is what I have done so far, but it is not using the 2d point class to generate the triangle.
import math
from fractions import Fraction
from random import randrange
from Tkinter import *
# the 2D point class
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
# Mutators and Accessors
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = value
# String function
def __str__(self):
floatX = float(str(self.x))
floatY = float(str(self.y))
return "({},{})".format(floatX, floatY)
# Distance function
def dist(self, other):
distance = math.sqrt(((self.x - other.x)**2)+((self.y - other.y)**2))
return "{}".format(distance)
# Midpoint function
def midpt(self, other):
x0 = float(str(((self.x + other.x))))/2
y0 = float(str(((self.y + other.y)/2)))
return Point(x0, y0)
# the coordinate system class: (0,0) is in the top-left corner
# inherits from the Canvas class of Tkinter
class ChaosGame(Canvas):
def __init__(self, master):
Canvas.__init__(self, master, bg = "white")
self.pack(fill = BOTH, expand = 1)
def plotPoints(self, triangle, NumberPoints):
x0, y0 = WIDTH / 2, HEIGHT / 2
direction = center
for i in range(NumberPoints):
point = randrange(len(triangle))
direction = triangle[point]
x0 = (direction[0] + x0) / 2
y0 = (direction[1] + y0) / 2
color = direction[1]
self.plot(x0, y0)
self.plotV(5, 510)
self.plotV(290, 5)
self.plotV(590, 510)
def plot(self, x, y):
POINT_COLORS=["black"]
RADIUS = 0
color = POINT_COLORS
self.create_oval(x, y, x+2, y+2, outline = color, fill = color)
def plotV(self, x, y):
POINT_COLORS=["red"]
RADIUS = 3
color = POINT_COLORS
self.create_oval(x, y, x+RADIUS*2, y+RADIUS*2, outline = color, fill = color)
##########################################################
# ***DO NOT MODIFY OR REMOVE ANYTHING BELOW THIS POINT!***
# the default size of the canvas is 600x520
WIDTH = 600
HEIGHT = 520
# the number of points to plot
NumberPoints = 50000
# the vertices
A = (5, 510)
B = (290, 5)
C = (590, 510)
triangle = (A, B, C)
center = (WIDTH/2, HEIGHT/2)
# create the window
window = Tk()
window.geometry("{}x{}".format(WIDTH, HEIGHT))
window.title("2D Points...Plotted")
# create the chaos game as a Tkinter canvas inside the window
s = ChaosGame(window)
# plot some random points
s.plotPoints(triangle, NumberPoints)
# wait for the window to close
window.mainloop()
The problem was that you were duplicating the Point-based code in the midpt() method in your plotPoints() method, but for tuples instead of Points. Since the triangle is handed to us as a list of tuples, we convert that to a list of Points, and modify our plot() method to accept a Point, and run the whole plotPoints() method in terms of Points:
from random import choice
from Tkinter import *
class Point(object):
''' a 2D point class '''
def __init__(self, x=0, y=0):
self.x = float(x)
self.y = float(y)
# Mutators and Accessors
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = float(value)
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = float(value)
# String function
def __str__(self):
return "({},{})".format(self.x, self.y)
# Midpoint function
def midpt(self, other):
x0 = (self.x + other.x) / 2
y0 = (self.y + other.y) / 2
return Point(x0, y0)
class ChaosGame(Canvas):
''' Plotting class that inherits from Canvas class of Tkinter '''
VERTEX_RADIUS = 3
VERTEX_COLORS = ["red"]
POINT_RADIUS = 1
POINT_COLORS = ["black"]
def __init__(self, master):
Canvas.__init__(self, master, bg="white")
self.pack(fill=BOTH, expand=1)
def plotPoints(self, triangle, NumberPoints):
point = Point(WIDTH / 2, HEIGHT / 2)
deltoid = [Point(x, y) for x, y in triangle] # tuples -> Points
for _ in range(NumberPoints):
point = point.midpt(choice(deltoid))
self.plot(point)
for vertex in deltoid:
self.plotV(vertex)
def plot(self, point):
radius = self.POINT_RADIUS
color = self.POINT_COLORS
x, y = point.x, point.y
self.create_oval(x, y, x + radius*2, y + radius*2, outline=color, fill=color)
def plotV(self, vertex):
radius = self.VERTEX_RADIUS
color = self.VERTEX_COLORS
x, y = vertex.x, vertex.y
self.create_oval(x, y, x + radius*2, y + radius*2, outline=color, fill=color)
The stuff beyond:
##########################################################
# ***DO NOT MODIFY OR REMOVE ANYTHING BELOW THIS POINT!***
not duplicated here. I also dealt with some whackiness in your Point methods in the way that they insisted on converting numbers to strings and back to numbers, e.g.:
x0 = float(str(((self.x + other.x))))/2
Instead doing:
x0 = (self.x + other.x) / 2
and forcing self.x to be a float when the Point is created.

How to add a #classmethod to a class that allows circle objects to be created with a tuple instead of a point for a center’s location

I have the below code which is are point and circle classes:
import math
class Point:
"""Two-Dimensional Point(x, y)"""
def __init__(self, x=0, y=0):
# Initialize the Point instance
self.x = x
self.y = y
def __iter__(self):
yield self.x
yield self.y
def __iadd__(self, other):
self.x = self.x + other.x
self.y = self.y + other.y
return self
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
def __rmul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
#classmethod
def from_tuple(cls, tup):
x, y = tup
return cls(x, y)
def loc_from_tuple(self, tup):
# self.x=t[0]
# self.y=t[1]
self.x, self.y = tup
#property
def magnitude(self):
# """Return the magnitude of vector from (0,0) to self."""
return math.sqrt(self.x ** 2 + self.y ** 2)
def distance(self, self2):
return math.sqrt((self2.x - self.x) ** 2 + (self2.y - self.y) ** 2)
def __str__(self):
return 'Point at ({}, {})'.format(self.x, self.y)
def __repr__(self):
return "Point(x={},y={})".format(self.x, self.y)
class Circle():
"""Circle(center, radius) where center is a Point instance"""
def __init__(self, center= Point(0,0), radius=1):
# Point.__init__(self,center)
self.center = 1 * center
self.radius = radius
# if not isinstance(center,Point):
# raise TypeError("The center must be a Point!")
#property
def center(self):
return self._center
#center.setter
def center(self, _center):
self._center = _center
if (isinstance(self._center, Point) is False):
raise TypeError("The center must be a Point!")
def __getitem__(self,item):
return self.center[item]
def __iadd__(self, other):
self.center.x = self.center.x + other.center.x
self.center.y = self.center.y + other.center.y
self.radius = self.radius + other.radius
self = Circle(Point(self.center.x, self.center.y), self.radius)
return self
def __add__(self,other):
return Circle(
Point(self.center.x + other.center.x, self.center.y+other.center.y),
self.radius + other.radius)
#classmethod
def from_tuple(cls, center,radius):
return cls(center, radius)
#property
def radius(self):
return self._radius
#radius.setter
def radius(self, radius):
if radius < 0:
raise ValueError('The radius cannot be negative')
self._radius = radius
#property
def area(self):
"""Calculate and return the area of the Circle"""
return math.pi * self.radius ** 2
#property
def diameter(self):
"""Calculate and return the diameter of the Circle"""
return self.radius * 2
def __str__(self):
return "Circle with center at ({0}, {1}) and radius {2}".format(self.center.x, self.center.y, self.radius)
def __repr__(self):
return "Circle(center=Point({0}, {1}), radius={2})".format(self.center[0],self.center[1],self.radius)
I added a #classmethod called from_tuple() to the Circle class that allows Circle objects to be created with a tuple instead of a Point for the center’s location. The resultant instance should have a Point as the center just like any other Circle object. I am supposed to code it so the tuple input is required, but allow the radius to default to 1. The expected output is below:
center_point = 3, 4
circle = Circle.from_tuple(center=center_point)
print(circle)
Circle(center=Point(3, 4), radius=1)
circle = Circle.from_tuple(center=center_point, radius = 3)
print(circle)
Circle(center=Point(3, 4), radius=3)
circle = Circle.from_tuple(center_point, 2)
print(circle)
Circle(center=Point(3, 4), radius=2)
circle = Circle.from_tuple()
Traceback (most recent call last):
[...]
TypeError: from_tuple() missing 1 required positional argument:
'center'
I wrote my class-method but it always results in the error TypeError: from_tuple() missing 1 required positional argument: 'radius'. I can;t find out how to fix this. Any help would be appreciated.
The simplest way would be to create a Point from that tuple and then hand it over to __init__ via cls
#classmethod
def from_tuple(cls, center, radius=1)
return cls(Point(*center), radius)
Here I also give radius a default value, so it's possible to describe a radius 1 circle with only the coordinates of its center, as is the case with your __init__ method

Rotate 2D polygon without changing its position

I've got this code:
class Vector2D(object):
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
def rotate(self, angle):
angle = math.radians(angle)
sin = math.sin(angle)
cos = math.cos(angle)
x = self.x
y = self.y
self.x = x * cos - y * sin
self.y = x * sin + y * cos
def __repr__(self):
return '<Vector2D x={0}, y={1}>'.format(self.x, self.y)
class Polygon(object):
def __init__(self, points):
self.points = [Vector2D(*point) for point in points]
def rotate(self, angle):
for point in self.points:
point.rotate(angle)
def center(self):
totalX = totalY = 0.0
for i in self.points:
totalX += i.x
totalY += i.y
len_points = len(self.points)
return Vector2D(totalX / len_points, totalY / len_points)
The problem is that when I rotate the polygon it also moves, not only rotates.
So how to rotate polygon around its center, without changing its position?
You're rotating around 0/0, not around its center. Try moving the polygon before rotating, such that its center is 0/0. Then rotate it, and finally move it back.
For instance, if you only need movement of vertices/polygons for this particular case, you could probably simply adjust rotate to be:
def rotate(self, angle):
center = self.center()
for point in self.points:
point.x -= center.x
point.y -= center.y
point.rotate(angle)
point.x += center.x
point.y += center.y

Move points and check specific start value, using classes python

I need to be able to move points and check a specific point value. This is the code:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self)
#Here I want to move my points
Next class is a linestring. It must be able to handle x set of points
class LineString(Point):
def __init__(self, *points):
self.points = []
for point in points:
if not isinstance(point, Point):
point = Point(*point)
self.points.append(point)
def __getitem__(self):
#Here I want to inspect the value of the specific
# e.g. y value for the start point after it has been moved
I'm a bit unsure of how to get the __getitem__ to work and whether it's in the right position. Should it be under class Point? Could this be done in another way?
Edited code;
from numpy import sqrt
import math
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def dist(self, point):
return math.hypot(self.x - point.x, self.y - point.y)
def move(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy
class LineString(Point):
def __init__(self, *points):
self.points = []
for point in points:
if not isinstance(point, Point):
point = Point(*point)
self.points.append(point)
def length(self):
return sum(p1.dist(p2) for p1, p2 in zip(self.points[1:], self.points[:-1]))
def move (self, x, y):
for p in self.points:
p.move(x, y)
def __getitem__(self, key):
return self.points[key]
I think this is roughly what you want:
You don't seem to actually need a dictionary (for a line, I think a list makes more sense anyway). So the Line class is just a list of Points, and it provides a move_all_points function to translate them all. Because Line subclasses a list, you get all the standard behaviour of lists for free:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return "<Point({},{})>".format(self.x, self.y)
def __str__(self):
return(repr(self))
def move(self, dx, dy):
"""Move the point by (dx, dy)."""
self.x += dx
self.y += dy
class Line(list):
"""A list of points that make up a line."""
def move_all_points(self, dx, dy):
for p in self:
p.move(dx, dy)
So then you can use them as follows:
>>> p1, p2, p3 = Point(0, 0), Point(5, 0), Point(10, 10)
>>> my_line = Line((p1, p2, ))
>>> print my_line
[<Point(0,0)>, <Point(5,0)>]
>>> my_line.append(p3)
>>> print my_line
[<Point(0,0)>, <Point(5,0)>, <Point(10,10)>]
>>> p4 = Point(100,100)
>>> my_line.move_all_points(1, 1)
>>> print my_line
[<Point(1,1)>, <Point(6,1)>, <Point(11,11)>]
>>> my_line.append(p4)
>>> print my_line
[<Point(1,1)>, <Point(6,1)>, <Point(11,11)>, <Point(100,100)>]

Categories