How to extend a line segment in both directions - python

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))

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?

TypeError: unsupported operand type(s) for +=: 'float' and 'function'

I'm just trying to simulate a simple path planning problem using an artificial potential field (APF). To do so, I have a Point class each instance of which represents the location of an agent. A bunch of functions to move the agent's location, to find its distance to some other points, and to compute an APF corresponding to that are implemented. An Obstacle class is also defined each instance of which is simply a point in addition to the obstacle's radius.
import autograd.numpy as np
from autograd import grad
import math
class Point(object):
def __init__(self,x,y):
self.X = x
self.Y = y
def distance(self, goal):
dx = self.X - goal.X
dy = self.Y - goal.Y
return math.hypot(dx, dy)
def move(self, value):
self.X += value
self.Y += value
def APF(self, goal, k, obstacles):
num = self.distance(goal)**2
temp = self.distance(goal)**(2*k)
for item in obstacles:
temp = temp + (self.distance(item.point)**2 - item.radius**2)
den = temp**(1/k)
return num/den
class Obstacle(object):
def __init__(self, point, radius):
self.point = point
self.radius = radius
To test the code above, the following main snippet is taken into account. In particular, it is supposed to iteratively compute the gradient of the APF and to add the result to the agent's location (say, moving it) until the gradient vanishes.
if __name__== "__main__" :
start = Point(0.0, 0.0)
goal = Point(15.0, 5.0)
p1 = Point(2.0, 2.0)
p2 = Point(3.0, 3.0)
p3 = Point(4.0, 4.0)
p4 = Point(5.0, 5.0)
obs1 = Obstacle(p1, 1.0)
obs2 = Obstacle(p2, 2.0)
obs3 = Obstacle(p3, 3.0)
obs4 = Obstacle(p4, 4.0)
obstacles = [obs1, obs2, obs3, obs4]
trajectory = [start]
k = 7.0
temp = start
while grad(temp.APF(goal, k, obstacles)) != 0.0:
next = temp.move(grad(temp.APF(goal, k, obstacles)))
trajctory.append(next)
temp = next
However, I've encountered the following error:
Traceback (most recent call last):
File "test_APF.py", line 53, in <module>
next = temp.move(grad(temp.APF(goal, k, obstacles)))
File "test_APF.py", line 17, in move
self.X += value
TypeError: unsupported operand type(s) for +=: 'float' and 'function'
To me APF returns numbers so grad should be okay with it. Then, move will also receive numbers as it argument. Can you please help me spotting the issue?
import autograd.numpy as np
from autograd import grad
import math
def APF(k,start,goal, obstacles):
dist = math.hypot(start[0] - goal[0], start[1] - goal[1])
num = dist**2
temp = dist**(2*k)
for item in obstacles:
temp = temp + (dist ** 2 - item.radius ** 2)
den = temp ** (1 / k)
return num / den
class Point(object):
def __init__(self,x,y):
self.X = x
self.Y = y
def distance(self, goal):
dx = self.X - goal.X
dy = self.Y - goal.Y
return math.hypot(dx, dy)
def move(self, value):
self.X += value
self.Y += value
class Obstacle(object):
def __init__(self, point, radius):
self.point = point
self.radius = radius
if __name__== "__main__" :
start = (0.0, 0.0)
goal = (15.0, 5.0)
p1 = Point(2.0, 2.0)
p2 = Point(3.0, 3.0)
p3 = Point(4.0, 4.0)
p4 = Point(5.0, 5.0)
obs1 = Obstacle(p1, 1.0)
obs2 = Obstacle(p2, 2.0)
obs3 = Obstacle(p3, 3.0)
obs4 = Obstacle(p4, 4.0)
obstacles = [obs1, obs2, obs3, obs4]
trajectory = [start]
k = 7.0
temp = start
print(grad(APF)(k,start,goal, obstacles))
# next = temp.move(grad(temp.APF(goal, k, obstacles)))
# trajctory.append(next)
# temp = next
You have to create two classes to handle this.. See my reference class for info.
According to the Autograd readme, autograd.grad() returns a function.
>>> grad_tanh = grad(tanh) # Obtain its gradient function
>>> grad_tanh(1.0) # Evaluate the gradient at x = 1.0
You're passing the function, not its return value, to your .move() function.

How to determine collision in python in right way

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

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.

Python language-center of a circle using OOP

class Point:
def __init__(self, initX, initY):
""" Create a new point at the given coordinates. """
self.x = initX
self.y = initY
def getX(self):
return self.x
def getY(self):
return self.y
def distanceFromOrigin(self):
return ((self.x ** 2) + (self.y ** 2))** 0.5
def __str__(self):
return "x=" + str(self.x) + ", y=" + str(self.y)
def get_line_to(self, target):
mx = (-target.x + self.x )
my = (-target.y + self.y)
grad=my/mx
c=-(grad*(self.x))+self.y
return grad
def halfway(self, target):
"""calculating midpoint"""
mx = (self.x + target.x) / 2
my = (self.y + target.y) / 2
return Point(mx, my)
def cencd(p1,p2,p3):
"""calculating the center of a circle"""
ma=(p2.getY-p1.getY)/(p2.getX-p1.getX)
mb=(p3.getY-p2.getY)/(p3.getX-p2.getX)
hw=p1.halfway(p2)
x=(ma*mb*(p1.getY-p3.getY)+mb*(p1.getX+p2.getX)-ma*(p2.getX+p3.getX))/2*(mb-ma)
ya=-(1/ma)*((x-hw.getX)+hw.getY)
return x,ya
"""defining the points for p1,p2 and p3"""
p = Point(5,5)
q = Point(6,-2)
r=Point(2,-4)
print(cencd(p,q,r))
I get this error message:SyntaxError: duplicate argument 'p1' in function definition on
Traceback (most recent call last):
File "python", line 45, in
File "python", line 34, in cencd
TypeError: unsupported operand type(s) for -: 'method' and 'method'
please assist.
"""working solution """"
ma=(p2.y-p1.y)/(p2.x-p1.x)
mb=(p3.y-p2.y)/(p3.x-p2.x)
hw=p1.halfway(p2)
x1=(ma*mb*(p1.y-p3.y)+mb*(p1.x+p2.x)-ma*(p2.x+p3.x))/(2*(mb-ma))
ya=-(1/ma)*((x1-hw.x))+hw.y
You don't need getters or setters in python nor is it pythonic to use them, you should access the attributes directly:
def cencd(p1, p2, p3):
"""calculating the center of a circle"""
ma = (p2.y - p1.y) / (p2.x - p1.x)
mb = (p3.y - p2.y) / (p3.x - p2.x)
hw = p1.halfway(p2)
x = (ma * mb * (p1.y - p3.y) + mb * (p1.x + p2.x) - ma * (p2.x + p3.x)) / 2 * (mb - ma)
ya = -(1 / ma) * ((x - hw.x) + hw.y)
return x, ya
Both getX and getY are methods in your code, not attributes. So you will need to call them using getX() and getY().
So ma=(p2.getY-p1.getY)/(p2.getX-p1.getX) becomes:
ma = (p2.getY()-p1.getY())/(p2.getX()-p1.getX())
And so on, the other code changes.
Otherwise, you can also define your methods as #property:
class Point:
...
...
#property
def getX(self):
return self.x
#property
def getY(self):
return self.y
...
And now you can access these as p1.getX and p2.getY and so on.
Note that the above #property decorator turns the method into a getter, which makes sense to use only with private variables (variables defined to start with _).
As such, since both x and y are normal attributes of your class, you can access them directly without using and property decorators or using getter methods, like p1.x and p2.y, as #Padraic points in his post.
As Padraic Cunningham said, we don't need getters or setters in Python, but as mu said we can make getters if we want, but normally they are used to get "fake" attributes that are actually computed from true attributes. For example, in the code below I've added a fake norm attribute to your Point class.
I've also added a few more double-underscore methods (aka dunder methods or magic methods) to your class. These methods are discussed in the official Python docs.
One of the most common dunder methods is __repr__() which should return a string that corresponds to how you create an instance of the class. This is especially handy when you're using a class in the interactive interpreter. FWIW, if a class doesn't define a __str__() method its __repr__() method will be used if you attempt to turn a class instance into a string. If a __repr__() method hasn't been defined a default one will be used.
The other dunder methods I've added make it easier to perform arithmetic operations on points; this can make code easier to write and to read. I think you'll agree that it makes the cencd() function a little clearer. (I'm not sure exactly what that function's supposed to do; I assume you've got the algebra correct :) ).
This code was tested on Python 2.6.6; it should run ok on Python 3 without modification.
#!/usr/bin/env python
''' Point class demo
From http://stackoverflow.com/q/28602056/4014959
Written by koseph, Padraic Cunningham, and PM 2Ring
2015.02.19
'''
from __future__ import print_function
from __future__ import division
class Point(object):
def __init__(self, initX, initY):
""" Create a new point at the given coordinates. """
self.x, self.y = initX, initY
#property
def norm(self):
return self.x ** 2 + self.y ** 2
def distance_from_origin(self):
return self.norm ** 0.5
def __repr__(self):
return 'Point({self.x}, {self.y})'.format(self=self)
def __str__(self):
return 'x={self.x}, y={self.y}'.format(self=self)
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, scale):
return Point(self.x * scale, self.y * scale)
__rmul__ = __mul__
def __neg__(self):
return -1 * self
def __sub__(self, other):
return self + -other
def weighted_mean(self, other, weight):
cweight = 1.0 - weight
x = cweight * self.x + weight * other.x
y = cweight * self.y + weight * other.y
return Point(x, y)
def halfway(self, other):
return self.weighted_mean(other, 0.5)
def cencd(p1, p2, p3):
""" Calculate the center of a circle """
a = p2 - p1
b = p3 - p2
ma = a.y / a.x
mb = b.y / b.x
hw = p1.halfway(p2)
x = ma * mb * (p1 - p3).y + mb * (p1 + p2).x - ma * (p2 + p3).x
x /= 2.0 * (mb - ma)
y = -(x - hw.x + hw.y) / ma
return Point(x, y)
p1 = Point(3, 4)
print(p1)
print('p1 is {0!r}, its norm is {1}'.format(p1, p1.norm))
print('and its distance from the origin is', p1.distance_from_origin(), end='\n\n')
p2 = Point(7, 2)
print('p2 is', repr(p2), end='\n\n')
print('p1 + p2 is', repr(p1 + p2))
print('p1 * 0.1 is', repr(p1 * 0.1))
print('p2 - p1 is', repr(p2 - p1), end='\n\n')
p3 = 4 * p1
print('p3 is', repr(p3), end='\n\n')
print('Weighted means from p1 to p3')
for i in range(5):
weight = i / 4.0
print('{0} {1:4.2f} {2!r}'.format(i, weight, p1.weighted_mean(p3, weight)))
print()
print('center of a circle for p1, p2, & p3:', repr(cencd(p1, p2, p3)))
output
x=3, y=4
p1 is Point(3, 4), its norm is 25
and its distance from the origin is 5.0
p2 is Point(7, 2)
p1 + p2 is Point(10, 6)
p1 * 0.1 is Point(0.3, 0.4)
p2 - p1 is Point(4, -2)
p3 is Point(12, 16)
Weighted means from p1 to p3
0 0.00 Point(3.0, 4.0)
1 0.25 Point(5.25, 7.0)
2 0.50 Point(7.5, 10.0)
3 0.75 Point(9.75, 13.0)
4 1.00 Point(12.0, 16.0)
center of a circle for p1, p2, & p3: Point(8.22727272727, 12.4545454545)

Categories