Toon posts:

[Python] Array pointslist

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik zit met het volgende probleem, ik ben in python een kleine game aan het schrijven dat gebruik maakt van polygonen. De polygonen die ik gebruik zitten in een array.
Python:
1
2
3
4
5
6
7
8
9
10
# Array
hexes = [ ((0,20), (10,0), (35,0), (45,20), (35,40), (10, 40)),
          ((35,40), (45,20), (70,20), (80,40), (70,60), (45, 60)),
          ((70,60), (80,40), (105,40), (115,60), (105,80), (80, 80)),
          ((70,20), (80,0), (105,0), (115,20), (105,40), (80, 40)) ] 
colors = [ 255000000,000255000,000000255,255255255 ]

# Draw map
for v,k in zip(hexes, colors):
    pygame.draw.polygon(screen, k, v)
De bovenstaande code werkt perfect, hoe zet alle polygonen op het scherm. Maar nu wou ik laatst inbouwen dat als je op een polygoon klikt die van kleur veranderd, daarvoor heb ik een handige functie op internet gevonden.
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def pointInPoly(point, pointsList):
    "Return True if point is contained in polygon (defined by given list of points.)"
        
    assert len(pointsList) >= 3, 'Not enough points to define a polygon (I require 3 or more.)'
    assert len(point) >= 2, 'Not enough dimensions to define a point(I require 2 or more.)'
        
    # If given values are ints, code will fail subtly. Force them to floats.
    x,y = float(point[0]), float(point[1])
    xp = [float(p[0]) for p in pointsList]
    yp = [float(p[1]) for p in pointsList]

    # Initialize loop
    c=False
    i=0
    npol = len(pointsList)
    j=npol-1
        
    while i < npol:
        if ((((yp[i]<=y) and (y<yp[j])) or 
            ((yp[j]<=y) and(y<yp[i]))) and 
            (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])):
            c = not c
            j = i
            i += 1
        
    return c
Als ik deze functie een van de waarde geef dat in de array zitten loopt het fout. Ik denk zelf dat het komt doordat er een [ voor en ] achter staat. Nu vroeg ik me af is het mogelijk om die op een manier weg te krijgen zonder ze te moeten strippen.


Hele Code
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import pygame, sys, os, string
from string import *
from pygame.locals import * 
 
pygame.init() 
 
window = pygame.display.set_mode((400, 400)) 
pygame.display.set_caption('HexWar') 
screen = pygame.display.get_surface() 
    
# Array
hexes = [ ((0,20), (10,0), (35,0), (45,20), (35,40), (10, 40)),
          ((35,40), (45,20), (70,20), (80,40), (70,60), (45, 60)),
          ((70,60), (80,40), (105,40), (115,60), (105,80), (80, 80)),
          ((70,20), (80,0), (105,0), (115,20), (105,40), (80, 40)) ] 
colors = [ 255000000,000255000,000000255,255255255 ]

# Draw map
for v,k in zip(hexes, colors):
    pygame.draw.polygon(screen, k, v)

# Refresh Screen
pygame.display.flip() 

# Point in hex
def pointInPoly(point, pointsList):
    "Return True if point is contained in polygon (defined by given list of points.)"
        
    assert len(pointsList) >= 3, 'Not enough points to define a polygon (I require 3 or more.)'
    assert len(point) >= 2, 'Not enough dimensions to define a point(I require 2 or more.)'
        
    # If given values are ints, code will fail subtly. Force them to floats.
    x,y = float(point[0]), float(point[1])
    xp = [float(p[0]) for p in pointsList]
    yp = [float(p[1]) for p in pointsList]

    # Initialize loop
    c=False
    i=0
    npol = len(pointsList)
    j=npol-1
        
    while i < npol:
        if ((((yp[i]<=y) and (y<yp[j])) or 
            ((yp[j]<=y) and(y<yp[i]))) and 
            (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])):
            c = not c
            j = i
            i += 1
        
    return c

# Main Loop     
def input(events): 
    for event in events:
        if event.type == QUIT: 
            sys.exit(0)
        elif event.type == 5:
            for k in hexes:
                if pointInPoly(event.pos ,k) == true:
                    pygame.draw.polygon(screen, 000000000, k)   
        else: 
            print event
        pygame.display.flip()
 
while True: 
   input(pygame.event.get())

[ Voor 3% gewijzigd door Verwijderd op 25-02-2005 20:36 ]


Verwijderd

Je pointInPoly routine is gewoon fout. Zoals hij er nu staat komt het script in een eindeloze lus (regels 43-49): i wordt namelijk alleen verhoogd als aan de if conditie voldaan wordt; zoniet, dan wordt nooit aan de terminatievoorwaarde voldaan.

De i += 1 een niveau naar boven halen heb ik geprobeerd maar werkt niet. Verder ben ik hier niet zo in thuis dus ik weet niet wat het algoritme zou moeten zijn. Ik raad je aan contact op te nemen met de auteur van het algoritme, of een ander te zoeken. Overigens, als je alleen maar met zeshoeken werkt kun je het ook faken door gewoon op een vierkant te testen binnen (of over de rand van) de zeshoek. Afhankelijk van de eisen die je er aan stelt is het binnen acceptabele grenzen onnauwkeurig, en een stuk sneller en makkelijker.

Verder: "true" is een onbekende identifier (je bedoelt waarschijnlijk "True", met een hoofdletter), en je hoeft bij een boolse functie in een conditie sowieso niet op == True te testen. Dat de functie zelf een boolean teruggeeft is conditie genoeg.

[ Voor 30% gewijzigd door Verwijderd op 25-02-2005 20:59 ]


Verwijderd

Om het je helemaal makkelijk te maken:

Ik heb een beetje geGoogled en deze pagina gevonden waar precies het gebruikte algoritme beschreven wordt.

En ik heb het speciaal voor jou even opnieuw vertaald naar Python:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def pointInPoly(point, pointsList):
    "Return True if point is contained in polygon (defined by given list of points.)"
        
    assert len(pointsList) >= 3, 'Not enough points to define a polygon (I require 3 or more.)'
    assert len(point) >= 2, 'Not enough dimensions to define a point(I require 2 or more.)'
        
    # If given values are ints, code will fail subtly. Force them to floats.
    x,y = float(point[0]), float(point[1])
    xp = [float(p[0]) for p in pointsList]
    yp = [float(p[1]) for p in pointsList]

    # Initialize loop
    oddNodes = False
    N = len(pointsList)
        
    for i in range(N):
        # j is index of next polygon in list
        j = (i + 1) % N

        # Do big-ass check that I don't understand anything of
        # Source: http://www.alienryderflex.com/polygon/
        if (yp[i] < y and yp[j] >= y) or (yp[j] < y and yp[i] >= y):
            if (xp[i] + (y - yp[i])/(yp[j] - yp[i])*(xp[j] - xp[i])) < x:
                oddNodes = not oddNodes

    return oddNodes

Verwijderd

Topicstarter
Thanks voor de hulp :) het werkt inderdaad nu. Nu ga ik me effe amuseren met de code te begrijpen. Big Thanks _/-\o_

Verwijderd

Topicstarter
*Removed*

[ Voor 110% gewijzigd door Verwijderd op 27-02-2005 11:36 . Reden: Opgelost :) sry ]