Here's a program that will map points from one quadrilateral to another
quadrilateral:
import pygame, math
WIDTH = 800
HEIGHT = 600
BLACK = ( 0, 0, 0, 255)
WHITE = (255, 255, 255, 255)
RED = (255, 0, 0, 255)
YELLOW = (255, 255, 0, 255)
BLUE = ( 0, 0, 255, 255)
GREEN = ( 0, 255, 0, 255)
class Quad(object):
data = None
point = None
def __init__(self, p1, p2, p3, p4):
self.p1 = list(p1)
self.p2 = list(p2)
self.p3 = list(p3)
self.p4 = list(p4)
def Render(self, bg):
pygame.draw.line(bg, RED, self.p1, self.p2, 1)
pygame.draw.line(bg, YELLOW, self.p2, self.p3, 1)
pygame.draw.line(bg, BLUE, self.p3, self.p4, 1)
pygame.draw.line(bg, GREEN, self.p4, self.p1, 1)
if self.point:
pygame.draw.rect(bg, BLACK, [self.point[0]-2,
self.point[1]-2, 4, 4], 0)
def SetPoint(self, offset):
if offset == None:
self.point = None
return
s, t = offset
x1, y1 = self.p1
x2, y2 = self.p2
x3, y3 = self.p4
x4, y4 = self.p3
xa = x1 + t * (x2 - x1)
ya = y1 + t * (y2 - y1)
xb = x3 + t * (x4 - x3)
yb = y3 + t * (y4 - y3)
X = xa + s * (xb - xa)
Y = ya + s * (yb - ya)
self.point = X, Y
def HitTest(self, pos):
x, y = float(pos[0]), float(pos[1])
x1, y1 = self.p1
x2, y2 = self.p2
x3, y3 = self.p4
x4, y4 = self.p3
Ax = x2 - x1
Ay = y2 - y1
Bx = x4 - x3
By = y4 - y3
Cx = x3 - x1
Cy = y3 - y1
Dx = x - x1
Dy = y - y1
Ex = Bx - Ax
Ey = By - Ay
a = -Ax * Ey + Ay * Ex
b = Ey * Dx - Dy * Ex + Ay * Cx - Ax * Cy
c = Dx * Cy - Dy * Cx
det = b * b - 4 * a * c
if det >= 0:
if abs(a) < 0.001:
t = -c / float(b)
else:
t = (-b - math.sqrt(det)) / float(2 * a)
denom = (Cx + Ex * t)
if denom > 0.01:
s = (Dx - Ax * t) / float(denom)
else:
s = (Dy - Ay * t) / float(Cy + Ey * t)
if (t >= 0) and (t <= 1) and (s >= 0) and (s <= 1):
return s, t
class Square(Quad):
def __init__(self, posx, posy, width, height):
p1 = posx, posy
p2 = posx + width, posy
p3 = posx + width, posy + height
p4 = posx, posy + height
super(Square, self).__init__(p1, p2, p3, p4)
def main():
pygame.init()
bg = pygame.display.set_mode([WIDTH, HEIGHT], 0, 32)
quit = 0
data = []
data.append( Quad([ 20, 50], [120, 30], [150, 110], [ 10, 130]) )
data.append( Square(200, 20, 100, 100) )
data.append( Quad([210, 170], [250, 260], [100, 240], [120, 150]) )
while not quit:
bg.fill(WHITE)
for quad in data:
quad.Render(bg)
pygame.display.flip()
pygame.event.pump()
moved = 0
for e in pygame.event.get():
if e.type == pygame.QUIT:
quit = 1
break
elif e.type == pygame.MOUSEMOTION:
if not moved:
moved = 1
for quad in data:
offset = quad.HitTest(e.pos)
if offset:
break
for quad in data:
quad.SetPoint(offset)
pygame.quit()
main()