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

Reply via email to