Files
2020-07-29 12:59:12 +02:00

241 lines
8.0 KiB
Python

"""
The goal of this program is to make an interpolation of the points of any
curve in order to make it a parametric function.
There are 2 main types of interpolations:
- Polynomial Interpolation:
- Bezier Interpolation:
"""
#Polynomial Interpolation
from .polynomial import Polynomial
#Pseudo Bezier Interpolation
from .curves import BezierCurve
from .abstract import Line,Point
#additional imports for showing the interpolations more easily
from .curves import Trajectory
from . import colors
#Deprectated function
def directInterpolation(points,t):
x=[pt[0] for pt in points]
y=[pt[1] for pt in points]
plx=Polynomial.createFromInterpolation(range(len(x)),x)
ply=Polynomial.createFromInterpolation(range(len(y)),y)
l=len(pts)
mst=100
# Creation of the points
# pts=[(random.uniform(xmin,xmax),random.uniform(ymin,ymax)) for i in range(n)]
# # """ Tests:
# # Calculations for n points in dimension 2:
#
# x=[pt[0] for pt in pts]
# y=[pt[1] for pt in pts]
# plx=Polynomial.createFromInterpolation(range(len(x)),x)
# ply=Polynomial.createFromInterpolation(range(len(y)),y)
# print(plx)
# print(ply)
# l=len(pts)
# mst=100
# npts=[(plx(l*st/mst),ply(l*st/mst)) for st in range(mst)]
# grapher=Grapher(context,functions=[plx,ply])
# """
class Interpolation:
"""Base class of all interpolations."""
def __init__(self,points,create=True):
"""Create the interpolation using a list of n-dimensional points."""
self.points=points
if create: self.create()
def create(self):
"""Create the necessary attributes for the interpolation.
This method is to be overloaded."""
pass
def sample(self,n):
"""Make a sample of the interpolation for n points."""
m=n-1
return [self(t/m) for t in range(n)]
def __str__(self):
"""Return the string representation of the interpolation."""
return "Itp("+",".join(map(str,self.points))+")"
class ExtraInterpolation(Interpolation):
"""Extra features for interpolations."""
def getSegments(self):
"""Return the segments formed by the points."""
return [Segment(self.points[i],self.points[i+1]) for i in range(len(self.points)-1)]
def getTrajectory(self):
"""Return the trajectory associated with the points of the interpolation."""
return Trajectory.createFromTuples(self.points)
def getPointsType(self):
"""Return the points under a point type instead of just a tuple type."""
return [Point(*p) for p in self.points]
def getPoint(self,t,**kwargs):
"""Return the point of position t in the parametric function."""
return Point(*self(t),**kwargs)
segments=property(getSegments)
trajectory=property(getTrajectory)
points_type=property(getPointsType)
class VisualInterpolation(Interpolation):
"""Visual features for interpolation, this class allows to show an
interpolation on a graphical context."""
def __init__(self,points,
color=colors.RED,
point_color=colors.LIGHTRED,
trajectory_color=colors.GREEN,
**kwargs):
"""Create a visual interpolation."""
self.color=color
self.point_color=point_color
self.trajectory_color=trajectory_color
Interpolation.__init__(self,points,**kwargs)
def show(self,context,n,color=None):
"""Show the polynomial interpolation by sampling the function using:
-n: the number of points
-context:the context in which the interpolation is shown."""
if not color: color=self.color
points=self.sample(n)
context.draw.lines(context.screen,color,points,width=1,connected=False)
def showTrajectory(self,context,color=None):
"""Show the trajectory defined by the points of the interpolation."""
if not color: color=self.trajectory_color
Trajectory.createFromTuples(self.points).show(context,color=color)
class PolynomialInterpolation(VisualInterpolation,ExtraInterpolation):
"""Make an interpolation using the lagrangian polynomial interpolator
over list of n-dimensional points."""
def create(self):
"""Create the components useful for the interpolation which are the
split components and the lagrangian polynomials."""
self.createComponents()
self.createPolynomials()
def createComponents(self):
"""Split its components of each point in separate lists."""
self.components=[[pt[i] for pt in self.points] for i in range(len(self.points[0]))]
def createPolynomials(self):
"""Create its polynomials using its components."""
lpts=len(self.points)
self.polynomials=[Polynomial.createFromInterpolation(range(lpts),c) for c in self.components]
def __call__(self,t):
"""Evaluate the parametric interpolation for the input 't' between 0 and 1."""
lcps=len(self.components)
lpts=len(self.points)-1
return tuple([self.polynomials[i](lpts*t) for i in range(lcps)])
class PseudoBezierInterpolation(VisualInterpolation):
"""Make an interpolation using the bezier interpolation over a list of
n-dimensional points."""
def create(self):
"""Create the lines, the intruding points and the bezier curves."""
self.createLines()
self.createIntrudingPoints()
self.createBezierCurves()
def createLines(self):
"""Create the lines of the duos of consecutive points."""
l=len(self.points)
lines=[Line.createFromTwoPoints(self.points[i],self.points[i+1]) for i in range(l-1)]
def createIntrudingPoints(self):
"""Create the points of intersection formed by some of the lines."""
l=len(lines)
intruding_points=[lines[i].crossLine(lines[i+1]) for i in range(l-1)]
def __call__(self,t):
"""Evaluate the parametric interpolation for the input 't' between 0 and 1."""
l=len(lines)
intruding_points=[lines[i].crossLine(lines[i+1]) for i in range(l-1)]
bezier_curves=[]
for i in range(l):
bezier_points=[self.points[i],self.intruding_points[i],self.points[i+1]]
b=BezierCurve(bezier_points)
bezier_curves.append(b)
if __name__=="__main__":
#To show the points
from .context import Context
from . import colors
#To create the points
import random
context=Context(name="Interpolation Demonstration")
#Parameters
h=1; w=1; xmin,xmax,ymin,ymax=[-w,w,-h,h] #corners
l=5 #number of points
n=0 #number of steps
m=100 #max number of steps
#Final version
#pts=[Point.random() for i in range(10)]
pts=[Point(2*x,random.randint(-5,5)) for x in range(l)]
interpolation=PolynomialInterpolation([p.components for p in pts])
interpolation.color
npts=interpolation.sample(200)
#Setting the console
context.console.append(["interpolation: "+str(interpolation),"trajectory: "+str(interpolation.trajectory)])
#Main loop of the context
while context.open:
#Update the context
context.check()
context.control()
context.clear()
context.show()
#Update data components
Point.turnPoints([1/100/l for i in range(l)],pts)
#trajectory=Trajectory(pts,colors.GREEN)
interpolation=PolynomialInterpolation([p.components for p in pts])
npts=interpolation.sample(200) #Sample 200 points by interpolation
#Additional features
n=(n+1)%(m+1)
c1=interpolation(n/m)
pt1=Point(*c1,radius=0.1,color=colors.lighten(colors.RED,2),fill=True)
c2=interpolation.trajectory(n/m)
pt2=Point(*c2,radius=0.1,color=colors.lighten(colors.GREEN,2),fill=True)
#Show visual components
pt1.show(context)
pt2.show(context)
interpolation.show(context,200)
interpolation.showTrajectory(context)
#Console
context.showConsole()
#Flip the context
context.flip()