Frage

Ich versuche eine iterative Funktion zu finden, die XYZ -Koordinaten für ein hexagonales Netz erzeugt. Mit einer Start -Hex -Position (z. B. 0,0,0 für den Einfachheit halber) möchte ich die Koordinaten für jeden aufeinanderfolgenden "Ring" von Sechseckern berechnen, wie hier dargestellt:

Bisher habe ich nur das geschafft, dies zu finden (Beispiel in JavaScript):

var radius = 3
var xyz = [0,0,0];

// for each ring
for (var i = 0; i < radius; i++) {
    var tpRing = i*6;
    var tpVect = tpRing/3;
    // for each vector of ring
    for (var j = 0; j < 3; j++) {
        // for each tile in vector
        for(var k = 0; k < tpVect; k++) {
            xyz[0] = ???;
            xyz[1] = ???;
            xyz[2] = ???;
            console.log(xyz);
        }
    }
}

Ich weiß, dass jeder Ring sechs Punkte enthält als der vorherige und jeder 120 ° -Vektor enthält einen zusätzlichen Punkt für jeden Schritt aus der Mitte. Ich weiß das auch x + y + z = 0 Für alle Fliesen. Aber wie kann ich eine Liste von Koordinaten erstellen, die der folgenden Sequenz folgen?

    0, 0, 0

    0,-1, 1
    1,-1, 0
    1, 0,-1
    0, 1,-1
   -1, 1, 0
   -1, 0, 1

    0,-2, 2
    1,-2, 1
    2,-2, 0
    2,-1,-1
    2, 0,-2
    1, 1,-2
    0, 2,-2
   -1, 2,-1
   -2, 2, 0
   -2, 1, 1
   -2, 0, 2
   -1,-1, 2
War es hilfreich?

Lösung

Eine andere mögliche Lösung, die hereinläuft O (Radius2), im Gegensatz zu den O (Radius4) von Tehmicks Lösung (Auf Kosten vieler Stil) ist Folgendes:

radius = 4
for r in range(radius):
    print "radius %d" % r
    x = 0
    y = -r
    z = +r
    print x,y,z
    for i in range(r):
        x = x+1
        z = z-1
        print x,y,z
    for i in range(r):
        y = y+1
        z = z-1
        print x,y,z
    for i in range(r):
        x = x-1
        y = y+1
        print x,y,z
    for i in range(r):
        x = x-1
        z = z+1
        print x,y,z
    for i in range(r):
        y = y-1
        z = z+1
        print x,y,z
    for i in range(r-1):
        x = x+1
        y = y-1
        print x,y,z

oder etwas besser geschrieben:

radius = 4
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
for r in range(radius):
    print "radius %d" % r
    x = 0
    y = -r
    z = +r
    print x,y,z
    for j in range(6):
        if j==5:
            num_of_hexas_in_edge = r-1
        else:
            num_of_hexas_in_edge = r
        for i in range(num_of_hexas_in_edge):
            x = x+deltas[j][0]
            y = y+deltas[j][1]
            z = z+deltas[j][2]            
            print x,y,z

Es ist von der Tatsache inspiriert, dass die Sechsecke tatsächlich selbst im Außenbereich eines Sechsecks stehen, sodass Sie die Koordinaten von 1 seiner Punkte finden und dann die anderen berechnen können, indem Sie sich an ihren 6 Kanten bewegen.

Andere Tipps

Nicht nur x + y + z = 0, aber die absoluten Werte von x, y und z entsprechen dem doppelten Radius des Rings. Dies sollte ausreichen, um jedes Sechseck an jedem aufeinanderfolgenden Ring zu identifizieren:

var radius = 4;
for(var i = 0; i < radius; i++)
{
    for(var j = -i; j <= i; j++)
    for(var k = -i; k <= i; k++)
    for(var l = -i; l <= i; l++)
        if(Math.abs(j) + Math.abs(k) + Math.abs(l) == i*2 && j + k + l == 0)
            console.log(j + "," + k + "," + l);
    console.log("");
}

Dies war ein lustiges Puzzle.

O (Radius2) aber mit (hoffentlich) etwas mehr Stil als Ofris Lösung. Mir kam ein, dass Koordinaten erzeugt werden konnten, als ob Sie mit einem Richtungsvektor (Bewegungsvektor) um den Ring "gehen", und dass eine Kurve dem Verschiebung der Null um den Bewegungsvektor entspricht.

Diese Version hat auch den Vorteil Erics Lösung Da es sich nie auf ungültige Koordinaten berührt (Erics lehnt sie ab, aber dieser muss sie noch nie testen).

# enumerate coords in rings 1..n-1; this doesn't work for the origin
for ring in range(1,4):
    # start in the upper right corner ...
    (x,y,z) = (0,-ring,ring)
    # ... moving clockwise (south-east, or +x,-z)
    move = [1,0,-1]         

    # each ring has six more coordinates than the last
    for i in range(6*ring):
        # print first to get the starting hex for this ring
        print "%d/%d: (%d,%d,%d) " % (ring,i,x,y,z)
        # then move to the next hex
        (x,y,z) = map(sum, zip((x,y,z), move))

        # when a coordinate has a zero in it, we're in a corner of
        # the ring, so we need to turn right
        if 0 in (x,y,z):
            # left shift the zero through the move vector for a
            # right turn
            i = move.index(0)
            (move[i-1],move[i]) = (move[i],move[i-1])

    print # blank line between rings

Drei Prost auf Pythons Sequenzschneide.

OK, nachdem ich beide Optionen ausprobiert habe, die ich mich für Ofris Lösung entschieden habe, da sie etwas schneller ist und es einfach gemacht hat, einen anfänglichen Offset -Wert zu liefern. Mein Code sieht jetzt so aus:

var xyz = [-2,2,0];
var radius = 16;
var deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]];
for(var i = 0; i < radius; i++) {
        var x = xyz[0];
        var y = xyz[1]-i;
        var z = xyz[2]+i;
        for(var j = 0; j < 6; j++) {
                for(var k = 0; k < i; k++) {
                        x = x+deltas[j][0]
                        y = y+deltas[j][1]
                        z = z+deltas[j][2]
                        placeTile([x,y,z]);
                }
        }
}

Die "Placetile" -Methode verwendet Clonenode, um ein vordefiniertes SVG -Element zu kopieren, und es dauert ca. 0,5 ms pro Fliesen, um mehr als gut genug zu sein. Ein großes Dankeschön an Tehmick und Ofri für Ihre Hilfe!

JS

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top