440 lines
14 KiB
Python
440 lines
14 KiB
Python
WHITE=(255,255,255)
|
|
|
|
from mywindow import Window
|
|
|
|
from mymaths import sign2,mean
|
|
from math import sqrt,atan,pi,cos,sin
|
|
from cmath import polar
|
|
|
|
import random
|
|
import time
|
|
|
|
class Figure:
|
|
def __init__(self,forms,color=WHITE):
|
|
"""Create a figure object."""
|
|
self.forms=forms
|
|
self.color=color
|
|
def show(self,window):
|
|
"""Show segments."""
|
|
for form in self.forms:
|
|
form.show(window)
|
|
|
|
|
|
class Form:
|
|
def __init__(self,points,closed=True,fill=False,width=1,color=WHITE):
|
|
"""Create the form object using points."""
|
|
self.points=points
|
|
self.closed=closed
|
|
self.fill=fill
|
|
self.width=1
|
|
self.color=color
|
|
def __add__(self,point):
|
|
"""Add a point to the form."""
|
|
self.points+=point
|
|
def __sub__(self,point):
|
|
"""Remove a point to the form."""
|
|
self.points.remove(point)
|
|
def center(self):
|
|
"""Return the point of the center."""
|
|
mx=mean([p.x for p in self.points])
|
|
my=mean([p.y for p in self.points])
|
|
return Point(mx,my)
|
|
def sides(self):
|
|
""""Return the list of the form sides."""
|
|
return [Segment(self.points[i%len(self.points)],self.points[(i+1)%len(self.points)],color=self.color,width=self.width) for i in range(len(self.points))]
|
|
def show(self,window):
|
|
"""Show the form using a window."""
|
|
for point in self.points:
|
|
point.show(window)
|
|
for side in self.sides():
|
|
side.show(window)
|
|
def __or__(self,other):
|
|
"""Return the bool: (2 sides are crossing)."""
|
|
for myside in self.sides():
|
|
for otherside in other.sides():
|
|
if myside|otherside:
|
|
return True
|
|
return False
|
|
def convex(self):
|
|
"""Return the bool (the form is convex)."""
|
|
center=self.center()
|
|
cx,cy=center[0],center[1]
|
|
angles=[]
|
|
l=len(self.points)
|
|
for i in range(l-1):
|
|
A=self.points[(i+l-1)%l]
|
|
B=self.points[i%l]
|
|
C=self.points[(i+1)%l]
|
|
u=Vector(A.x-B.x,A.y-B.y)
|
|
v=Vector(C.x-B.x,C.y-B.y)
|
|
angle=v^u
|
|
if angle>pi:
|
|
return True
|
|
return False
|
|
def getSparse(self): #as opposed to makeSparse which keeps the same form and return nothing
|
|
"""Return the form with the most sparsed points."""
|
|
center=self.center()
|
|
cx,cy=center[0],center[1]
|
|
list1=[]
|
|
for point in self.points:
|
|
px,py=point.x,point.y
|
|
vector=Vector(px-cx,py-cy)
|
|
angle=vector.polar()[1]
|
|
list1.append((angle,point))
|
|
list1=sorted(list1,key=lambda x:x[0])
|
|
points=[element[1] for element in list1]
|
|
return Form(points)
|
|
def makeSparse(self):
|
|
"""Change the form into the one with the most sparsed points."""
|
|
self=self.Sparse()
|
|
def __contains__(self,point):
|
|
"""Return the bool: (the point is in the form)."""
|
|
x,y=point[0],point[1]
|
|
p1=Point(x,y)
|
|
p2=Point(0,0)
|
|
line=Line(p1,p2)
|
|
line.show(window)
|
|
print(line.__dict__)
|
|
for segment in self.sides():
|
|
if segment|line:
|
|
return True
|
|
return False
|
|
def rotate(self,angle,center=None):
|
|
"""Rotate the form by rotating its points from the center of rotation.
|
|
Use center of the shape as default center of rotation.""" #Actually not working
|
|
if not center:
|
|
C=self.center()
|
|
for i in range(len(self.points)):
|
|
P=self.points[i]
|
|
v=Vector(P.x-C.x,P.y-C.y)
|
|
v.rotate(angle)
|
|
self.points[i]=v(C)
|
|
def move(self,*step):
|
|
"""Move the object by moving all its points using step."""
|
|
x,y=step[0],step[1]
|
|
for i in range(len(self.points)):
|
|
self.points[i].x+=x
|
|
self.points[i].y+=y
|
|
def moveTo(self,position):
|
|
"""Move the object to an absolute position."""
|
|
x,y=position[0],position[1]
|
|
cx,cy=self.center()
|
|
for i in range(len(self.points)):
|
|
vx=self.points[i].x-cx
|
|
vy=self.points[i].y-cy
|
|
self.points[i].x=vx+x
|
|
self.points[i].y=vy+y
|
|
def moveUntil(self,position):
|
|
"""Move the object to the position until the point is hit."""
|
|
pass
|
|
def update(self,input):
|
|
"""Update the points."""
|
|
for point in self.points:
|
|
point.update(input)
|
|
def __getitem__(self,index):
|
|
"""Return the point of index index."""
|
|
return self.points[index]
|
|
def __setitem__(self,index,value):
|
|
"""Change the points of a form."""
|
|
self.points[index]=value
|
|
def triangleArea(self,form):
|
|
"""Return the area of a triangle of type form."""
|
|
a,b,c=form.sides()
|
|
A=1/4*sqrt(4*a.l**2*b.l**2-(a.l**2+b.l**2-c.l**2)**2)
|
|
def __len__(self):
|
|
"""Return number of points."""
|
|
return len(self.points)
|
|
|
|
|
|
class Polygon:
|
|
def __init__(self,points,fill=False,width=1,color=WHITE,showpoints=True):
|
|
"""Create the polygon using points, fill, width, color and showpoints."""
|
|
self.points=points
|
|
self.fill=fill
|
|
self.width=1
|
|
self.color=color
|
|
self.showpoints=showpoints
|
|
def show(self,window):
|
|
"""Show the polygon using window."""
|
|
positions=[[p.x,p.y] for p in self.points]
|
|
window.draw.polygon(window.screen,self.color,positions,self.width)
|
|
if self.showpoints:
|
|
for point in self.points:
|
|
point.show(window)
|
|
return False
|
|
def update(self):
|
|
pass
|
|
|
|
class Point:
|
|
def __init__(self,*args,radius=5,fill=False,color=WHITE):
|
|
"""Create a point using x, y, radius, fill and color."""
|
|
self.x=args[0]
|
|
self.y=args[1]
|
|
self.n=sqrt(self.x**2+self.y**2)
|
|
self.a=atan(self.y/self.x)
|
|
self.radius=radius
|
|
self.fill=fill
|
|
self.color=color
|
|
def __contains__(self,other):
|
|
"""Return bool if objects is in point."""
|
|
ox,oy=other[0],other[1]
|
|
if self.radius>=sqrt((ox-self.x)**2+(oy-self.y)**2):
|
|
return True
|
|
else:
|
|
return False
|
|
def __getitem__(self,index):
|
|
"""Return x or y value using given index."""
|
|
if index==0:
|
|
return self.x
|
|
if index==1:
|
|
return self.y
|
|
def __setitem__(self,index,value):
|
|
"""Change x or y value using given index and value."""
|
|
if index==0:
|
|
self.x=value
|
|
if index==1:
|
|
self.y=value
|
|
def rotate(self,angle=pi,point=[0,0]):
|
|
"""Rotate the point using the angle and the center of rotation.
|
|
Uses [0,0] for the center of rotation by default."""
|
|
s=Vector(self.x,self.y)
|
|
v=Vector(self.x-point[0],self.y-point[1])
|
|
sn,sa=s.polar()
|
|
vn,va=v.polar()
|
|
self.x=s.x+vn*cos(sa+va)
|
|
self.y=s.y+vn*sin(sa+va)
|
|
print(self.x,self.y)
|
|
def move(self,*step):
|
|
"""Move the point using given step."""
|
|
self.x+=step[0]
|
|
self.y+=step[1]
|
|
def moveTo(self,position):
|
|
"""Move the point to position using given position."""
|
|
pass
|
|
def show(self,window):
|
|
"""Show a point using window."""
|
|
window.draw.circle(window.screen,self.color,[int(self.x),int(self.y)],self.radius,not self.fill)
|
|
def __add__(self,other):
|
|
"""Add two points together by making the sum of their components."""
|
|
""" if other.color==self.color:
|
|
color=self.color
|
|
else:
|
|
color=None
|
|
if other.width=self.width:
|
|
width=self.width
|
|
else:
|
|
width=None
|
|
if"""
|
|
return Point(self.x+other[0],self.y+other[1])
|
|
def __sub__(self,other):
|
|
return Point(self.x-other[0],self.y-other[1])
|
|
|
|
class Line:
|
|
def __init__(self,p1,p2,width=1,color=WHITE):
|
|
"""Create the line using 2 points, width and color."""
|
|
self.width=width
|
|
self.color=color
|
|
if p1.x!=p2.x:
|
|
self.a=(p2.y-p1.y)/(p2.x-p1.x)
|
|
else:
|
|
self.a=None
|
|
if self.a!=None:
|
|
self.b=p1.y-self.a*p1.x
|
|
else:
|
|
self.b=None
|
|
def evaluate(self,x):
|
|
"""Evaluate the affine function corresponding to the line using x."""
|
|
return self.a*x+self.b
|
|
def show(self,window):
|
|
"""Show the line using window."""
|
|
wcmx,wcmy,wcMx,wcMy=window.coordonnates
|
|
my=self.evaluate(wcmx)
|
|
My=self.evaluate(wcMx)
|
|
window.draw.line(window.screen,self.color,[wcmx,my],[wcMx,My],self.width)
|
|
def __or__(self,other):
|
|
"""Return bool for (2 lines are crossing)."""
|
|
if self.a==other.a:
|
|
return None
|
|
x=(self.b-other.b)/(other.a-self.a)
|
|
y=self.a*x+self.b
|
|
return Point(x,y)
|
|
|
|
|
|
class Segment(Line):
|
|
def __init__(self,p1,p2,width=1,color=WHITE):
|
|
"""Create the segment using 2 points, width and color."""
|
|
Line.__init__(self,p1,p2,width,color)
|
|
self.p1=p1
|
|
self.p2=p2
|
|
def center(self):
|
|
"""Return the point of the center of the Segment."""
|
|
x=(self.p1.x+self.p2.x)/2
|
|
y=(self.p1.y+self.p2.y)/2
|
|
return Point(x,y,color=self.color)
|
|
def show(self,window):
|
|
"""Show the segment using window."""
|
|
window.draw.line(window.screen,self.color,[self.p1.x,self.p1.y],[self.p2.x,self.p2.y],self.width)
|
|
def __len__(self):
|
|
"""Return the length of the segment."""
|
|
x=p1.x-p2.x
|
|
y=p1.y-p2.y
|
|
return sqrt(x**2+y**2)
|
|
|
|
def __or__(self,other):
|
|
"""Return bool for (2 segments are crossing)."""
|
|
if not self.a or not other.a or not self.b or not other.b:
|
|
return None
|
|
if self.a==other.a:
|
|
return None
|
|
x=(self.b-other.b)/(other.a-self.a)
|
|
y=self.a*x+self.b
|
|
if type(other)==Segment:
|
|
mx=max(min(self.p1.x,self.p2.x),min(other.p1.x,other.p2.x))
|
|
Mx=min(max(self.p1.x,self.p2.x),max(other.p1.x,other.p2.x))
|
|
my=max(min(self.p1.y,self.p2.y),min(other.p1.y,other.p2.y))
|
|
My=min(max(self.p1.y,self.p2.y),max(other.p1.y,other.p2.y))
|
|
if mx<=x<=Mx and my<=y<=My:
|
|
return Point(x,y,color=self.color)
|
|
else:
|
|
return None
|
|
if type(other)==Line:
|
|
mx=min(self.p1.x,self.p2.x)
|
|
Mx=max(self.p1.x,self.p2.x)
|
|
my=min(self.p1.y,self.p2.y)
|
|
My=max(self.p1.y,self.p2.y)
|
|
if mx<=x<=Mx and my<=y<=My:
|
|
return Point(x,y,color=self.color)
|
|
else:
|
|
return None
|
|
else:
|
|
return None
|
|
|
|
class Vector:
|
|
def __init__(self,*args,arrow=(3,3),width=1,color=WHITE):
|
|
"""Create a vector."""
|
|
self.x=args[0]
|
|
self.y=args[1]
|
|
self.width=width
|
|
self.color=color
|
|
def show(self,p,window,color=None):
|
|
"""Show the vector."""
|
|
if not color:
|
|
color=self.color
|
|
p1=Point(p[0],p[1],color=self.color)
|
|
p2=Point(self.x+p[0],self.y+p[1],color=self.color)
|
|
s=Segment(p1,p2,width=self.width,color=self.color)
|
|
s.show(window)
|
|
def __neg__(self):
|
|
"""Return the negative vector."""
|
|
x=-self.x
|
|
y=-self.y
|
|
return Vector(x,y,width=self.width,color=self.color)
|
|
def polar(self):
|
|
"""Return the polar coordonnates for the x and y position of the object."""
|
|
return list(polar(complex(self.x,self.y)))
|
|
def colinear(self,other):
|
|
"""Return if two vectors are colinear."""
|
|
return self.x*other.y-self.y*other.x==0
|
|
def scalar(self,other):
|
|
"""Return the scalar product between two vectors."""
|
|
return self.x*other.x+self.y*other.y
|
|
def __mul__(self,factor):
|
|
"""Multiply a vector by a given factor."""
|
|
if type(factor)==Vector:
|
|
pass
|
|
else:
|
|
self.x*=factor
|
|
self.y*=factor
|
|
def __add__(self,other):
|
|
"""Add two vectors together."""
|
|
return Vector(self.x+other.x,self.y+other.y,width=self.width,color=self.color)
|
|
def rotate(self,angle):
|
|
"""Rotate a vector using the angle of rotation."""
|
|
n,a=self.polar()
|
|
a+=angle
|
|
self.x=n*cos(a)
|
|
self.y=n*sin(a)
|
|
def __getitem__(self,index):
|
|
"""Return x or y value using given index."""
|
|
if index==0:
|
|
return self.x
|
|
if index==1:
|
|
return self.y
|
|
def __setitem__(self,index,value):
|
|
"""Change x or y value using given index and value."""
|
|
if index==0:
|
|
self.x=value
|
|
if index==1:
|
|
self.y=value
|
|
def __call__(self,*points):
|
|
"""Return points by applying the vector on those."""
|
|
points=[point+self for point in points]
|
|
if len(points)==1:
|
|
return points[0]
|
|
else:
|
|
return points
|
|
def angle(self):
|
|
"""Return the angle of a vector with the [1,0] direction in cartesian coordonnates."""
|
|
return self.polar()[1]
|
|
|
|
def __xor__(self,other):
|
|
"""Return the angle between two vectors."""
|
|
return self.angle()-other.angle()
|
|
|
|
|
|
class Manager:
|
|
def __init__(self,window,forms):
|
|
self.window=window
|
|
self.forms=forms
|
|
def __call__(self):
|
|
while self.window.open:
|
|
self.window.check()
|
|
self.update()
|
|
def update(self):
|
|
for form in self.forms:
|
|
form.update()
|
|
|
|
|
|
|
|
|
|
class Wrapper:
|
|
def __init__(self,form):
|
|
self.form=form
|
|
def update(self):
|
|
pass
|
|
|
|
if __name__=="__main__":
|
|
window=Window()
|
|
p1=Point(15,62)
|
|
p2=Point(250,400)
|
|
p3=Point(800,500)
|
|
p4=Point(400,400,color=(0,255,0))
|
|
points=[p1,p3,p2,p4]
|
|
f=Form([Point(random.randint(1,700),random.randint(1,600)) for i in range(10)],color=(0,0,255))
|
|
#f.show(window)
|
|
f2=f.getSparse()
|
|
p1.show(window)
|
|
p2.show(window)
|
|
v=Vector(p2[0]-p1[0],p2[1]-p1[1],color=(255,0,0))
|
|
center=f2.center()
|
|
while window.open:
|
|
window.check()
|
|
window.clear()
|
|
#v.rotate(0.1)
|
|
v.show(center,window)
|
|
f2.rotate(0.1)
|
|
time.sleep(0.1)
|
|
f2.show(window)
|
|
window.flip()
|
|
#Segment(f[0],f[1],color=(255,0,0)).center().show(window)
|
|
#print(p4 in f)
|
|
#window.clear()
|
|
#p4.show(window)
|
|
#a=Line(p4,p2,color=(255,0,0))
|
|
#b=Segment(p1,p3,color=(255,255,0))
|
|
#a.show(window)
|
|
#b.show(window)
|
|
#p=b|a
|
|
#window()
|
|
#a=Vector(1,5)
|