• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Polyhedron Constructors

I made a number of functions to create various polyhedrons, such as cubes and octahedrons for my map, as well as functions to move and rotate them. Converting these functions into a more general API hasn't been all that much work, so I decided to share these functions, even though the range of application might be not that high, especially given that there are quite a few very obscure ones among them. But who knows - maybe someone somewhere wakes up at 3 in the morning, yelling "Man, if only I could have a deltoidal hexacontahedron in my map."

There are geometric bodies I could add that would be more useful, but given that there are so many that I could do and I don't know if there's demand for them, it's better that if someone needs a specific geometry, he or she requests it and I try to implement a function for it.

The API allows special effects to be added to the vertices of the polyhedrons as well as lightning effects to the edges.

Ideas for applications:
-Creating and animating a rotating ball for a soccer map.
-A spell that sends an energy sphere at the opponent.
-Rotating holograms in a sci-fi map or an alien artifact.

Some of the functions can be cleaned up a bit. If a moderator deems this resource to be useful, I will do so.

Test map attached to this post.

vJASS:
library Polyhedron

//============================================================================================
//Polyhedron Constructors by Cyclotrutan
//============================================================================================

globals
    constant integer VERTEX_LIMIT = 62    //Reduce if that many vertices are not needed.
    constant integer EDGE_LIMIT = 180    //Reduce if that many edges are not needed.
endglobals

//This is a library of functions that construct the vertex coordinatates of various regular
//polyhedra (Platonic, Archimedean, and Catalan solids). The API provides the ability to add
//special effects at the vertex positions, as well as functions to move and rotate the
//polyhedron.

//============================================================================================

//To create a new polyhedron, call
//polyhedron.create(x,y,z,whichPolyhedron,edgeLength,vertexEffect,effectZoffset,effectScale,rotationSpeed,precessionSpeed)

//x,y,z: The map coordinates where the polyhedron is created.

//whichPolyhedron determines which polyhedron type is created. Valid input arguments are:
//"tetrahedron"            https://en.wikipedia.org/wiki/Tetrahedron
//"octahedron"            https://en.wikipedia.org/wiki/Octahedron
//"cube"            https://en.wikipedia.org/wiki/Cube
//"cuboctahedron"        https://en.wikipedia.org/wiki/Cuboctahedron
//"tetrakishexahedron"        https://en.wikipedia.org/wiki/Tetrakis_hexahedron
//"snubcube"            https://en.wikipedia.org/wiki/Snub_cube
//"triacontahedron"        https://en.wikipedia.org/wiki/Rhombic_triacontahedron
//"snubdodecahedron"        https://en.wikipedia.org/wiki/Snub_dodecahedron
//"disdyakistriacontahedron"    https://en.wikipedia.org/wiki/Disdyakis_triacontahedron
//"deltoidalhexacontahedron"    https://en.wikipedia.org/wiki/Deltoidal_hexecontahedron

//edgeLength determines the length of the polyhedron edges and therefore the size of the polyhedron.

//vertexEffect is the path to the special effect that will be visible at each vertex. If vertexEffect
//is an empty string, no special effects will be created.

//effectZoffset is a static shift of each special effect in Z-direction. This will help make the
//rotation look smoother if the special effect is not centered at the origin.

//effectScale is the scale of each special effect.

//rotationSpeed is the angle in radian that the polyhedron will rotate each time .Animate() is called.
//Can be ignored if there's no intention to use .Animate().

//precessionSpeed is the angle in radian that the rotation axis of the polyhedron will precess
//each time .Animate() is called. Can be ignored if there's no intention to use .Animate().

//============================================================================================

//polyhedron.createSimple(x,y,z,whichPolyhedron,edgeLength) creates a polyhedron without attaching
//special effects to it.

//.SetPosition(x,y,z) moves the polyhedron to the coordinates (x,y,z), while leaving the relative
//positions of the vertices unchanged.

//.SetOrientation(phi,theta,rotAngle) will orient the rotation axis of the polyhedron to point 
//towards the azimuth angle phi (0 to 2*PI) and the polar angle theta (PI/2 to -PI/2), then rotate 
//the polyhedron by the angle rotAngle. Calling this function repeatedly while keeping phi and theta 
//constant and changing rotAngle with each call will make the polyhedron rotate around the axis 
//defined by phi and theta.

//.Animate() will rotate the polyhedron by the angle defined by rotationSpeed and precess the
//rotation axis by precessionSpeed. Repeatedly calling this function will make the polyhedron
//rotate smoothly around a randomly oriented axis. If you want to have more control over the
//polyhedron animation, use SetOrientation instead.

//.SetScale(whichScale) will scale the polyhedron by the given factor. The new edge length will
//be edgeLength*scale.

//.destroy() will destroy the polyhedron and the associated special effects.

//To change additional attributes of special effects not covered in the API, use this template:
//set A = 0
//loop
//    call BlzSetSpecialEffectTimeScale( myPolyhedron.vertexEffect[A] , 0.5 )
//    set A = A + 1
//exitwhen A > myPolyhedron.numVertices - 1
//endloop

//.AddLightningEdges(lightningType,cutOffDist) will created lightning effects of the type
//specified by the string "lightningType" and connect each pair of vertices that are cutOffDist
//or less apart. The cutOffDist should be slightly higher than edgeLength. If that doesn't
//produce the desired results, increase or decrease the value until the right vertices are
//connected.

//============================================================================================
//============================================================================================

struct polyhedron

    readonly real x                //Starting position of polyhedron.
    readonly real y
    readonly real z

    private real array X0[VERTEX_LIMIT]        //Starting position of vertices relative to position of polyhedron.
    private real array Y0[VERTEX_LIMIT]
    private real array Z0[VERTEX_LIMIT]

    private real array X[VERTEX_LIMIT]        //Current position of vertices relative to position of polyhedron.
    private real array Y[VERTEX_LIMIT]
    private real array Z[VERTEX_LIMIT]

    readonly integer numVertices
    effect array vertexEffect[VERTEX_LIMIT]
    real effectZoffset
    
    readonly integer numLightnings = 0
    lightning array edgeLightning[EDGE_LIMIT]
    private integer array lightningOrigin[EDGE_LIMIT]
    private integer array lightningEnd[EDGE_LIMIT]

    private real rotPhi = 0
    private real rotTheta = 0
    private real rotAngle = 0
    real rotSpeed
    real precessionSpeed
    real scale = 1

    //============================================================================================
    //API
    //============================================================================================
    method SetPosition takes real x, real y, real z returns nothing
        local integer A = 0
        local integer O
        local integer E
        set .x = x
        set .y = y
        set .z = z
        
        loop
        exitwhen A > .numVertices - 1
            call BlzSetSpecialEffectPosition( .vertexEffect[A] , .x + .X[A] , .y + .Y[A] , .z + .Z[A] + .effectZoffset  )
            set A = A + 1
        endloop

        set A = 0
        loop
        exitwhen A > .numLightnings
            set O = .lightningOrigin[A]
            set E = .lightningEnd[A]
            call MoveLightningEx( .edgeLightning[A] , true , .x + .X[O] , .y +.Y[O] , .z + .Z[O] , .x + .X[E] , .y + .Y[E] , .z + .Z[E] )
            set A = A + 1
        endloop
    endmethod
    
    method SetOrientation takes real phi, real theta, real rotAngle returns nothing
        local integer A
        local real nx
        local real ny
        local real nz
        local real angle
        local real cosAngle
        local real sinAngle
        local real oneMinCos
        local real array M
        local real xt
        local real yt
        local real zt
        local integer O
        local integer E

        set .rotAngle = rotAngle

        set .rotPhi = phi
        set .rotTheta = theta
        if .rotTheta > bj_PI/2 then
            set .rotTheta = bj_PI - .rotTheta
            set .rotPhi = .rotPhi + bj_PI
        elseif .rotTheta < -bj_PI/2 then
            set .rotTheta = -bj_PI - .rotTheta
            set .rotPhi = .rotPhi + bj_PI
        endif
        
        set nx = Cos(.rotPhi)*Cos(.rotTheta)
        set ny = Sin(.rotPhi)*Cos(.rotTheta)
        set nz = Sin(.rotTheta)

        set cosAngle = Cos(.rotAngle)
        set sinAngle = Sin(.rotAngle)
        set oneMinCos = 1 - cosAngle

        set M[1] = nx*nx*oneMinCos + cosAngle
        set M[2] = nx*ny*oneMinCos - nz*sinAngle
        set M[3] = nx*nz*oneMinCos + ny*sinAngle
        set M[4] = ny*nx*oneMinCos + nz*sinAngle
        set M[5] = ny*ny*oneMinCos + cosAngle
        set M[6] = ny*nz*oneMinCos - nx*sinAngle
        set M[7] = nz*nx*oneMinCos - ny*sinAngle
        set M[8] = nz*ny*oneMinCos + nx*sinAngle
        set M[9] = nz*nz*oneMinCos + cosAngle

        set A = 0
        loop
        exitwhen A > .numVertices - 1
            set .X[A] = M[1]*.X0[A] + M[2]*.Y0[A] + M[3]*.Z0[A]
            set .Y[A] = M[4]*.X0[A] + M[5]*.Y0[A] + M[6]*.Z0[A]
            set .Z[A] = M[7]*.X0[A] + M[8]*.Y0[A] + M[9]*.Z0[A]
            call BlzSetSpecialEffectPosition( .vertexEffect[A] , .x + .X[A] , .y + .Y[A] , .z + .Z[A] + .effectZoffset )
            set A = A + 1
        endloop

        set A = 0
        loop
        exitwhen A > .numLightnings
            set O = .lightningOrigin[A]
            set E = .lightningEnd[A]
            call MoveLightningEx( .edgeLightning[A] , true , .x + .X[O] , .y + .Y[O] , .z + .Z[O] , .x + .X[E] , .y + .Y[E] , .z + .Z[E] )
            set A = A + 1
        endloop
    endmethod

    method SetScale takes real whichScale returns nothing
        local integer A = 0
        local integer O
        local integer E
        loop
        exitwhen A > .numVertices - 1
            set .X0[A] = .X0[A]*whichScale/.scale
            set .Y0[A] = .Y0[A]*whichScale/.scale
            set .Z0[A] = .Z0[A]*whichScale/.scale
            set .X[A] = .X[A]*whichScale/.scale
            set .Y[A] = .Y[A]*whichScale/.scale
            set .Z[A] = .Z[A]*whichScale/.scale
            call BlzSetSpecialEffectPosition( .vertexEffect[A] , .x + .X[A] , .y + .Y[A] , .z + .Z[A] )
            set A = A + 1
        endloop
        set .scale = whichScale

        set A = 0
        loop
        exitwhen A > .numLightnings
            set O = .lightningOrigin[A]
            set E = .lightningEnd[A]
            call MoveLightningEx( .edgeLightning[A] , true , .x + .X[O] , .y + .Y[O] , .z + .Z[O] , .x + .X[E] , .y + .Y[E] , .z + .Z[E] )
            set A = A + 1
        endloop
    endmethod

    method Animate takes nothing returns nothing
        local integer A
        local real nx
        local real ny
        local real nz
        local real angle
        local real cosAngle
        local real sinAngle
        local real oneMinCos
        local real array M
        local real x
        local real y
        local real z
        local real xt
        local real yt
        local real zt
        local integer O
        local integer E

        set .rotAngle = .rotAngle + .rotSpeed

        set .rotPhi = .rotPhi + .precessionSpeed
        set .rotTheta = .rotTheta + .precessionSpeed*.rotSpeed
        if .rotTheta > bj_PI/2 then
            set .rotTheta = bj_PI - .rotTheta
            set .rotPhi = .rotPhi + bj_PI
            set .precessionSpeed = -.precessionSpeed
            set .precessionSpeed = -.precessionSpeed
        elseif .rotTheta < -bj_PI/2 then
            set .rotTheta = -bj_PI - .rotTheta
            set .rotPhi = .rotPhi + bj_PI
            set .precessionSpeed = -.precessionSpeed
            set .precessionSpeed = -.precessionSpeed
        endif
        
        set nx = Cos(.rotPhi)*Cos(.rotTheta)
        set ny = Sin(.rotPhi)*Cos(.rotTheta)
        set nz = Sin(.rotTheta)

        set cosAngle = Cos(.rotAngle)
        set sinAngle = Sin(.rotAngle)
        set oneMinCos = 1 - cosAngle

        set M[1] = nx*nx*oneMinCos + cosAngle
        set M[2] = nx*ny*oneMinCos - nz*sinAngle
        set M[3] = nx*nz*oneMinCos + ny*sinAngle
        set M[4] = ny*nx*oneMinCos + nz*sinAngle
        set M[5] = ny*ny*oneMinCos + cosAngle
        set M[6] = ny*nz*oneMinCos - nx*sinAngle
        set M[7] = nz*nx*oneMinCos - ny*sinAngle
        set M[8] = nz*ny*oneMinCos + nx*sinAngle
        set M[9] = nz*nz*oneMinCos + cosAngle

        set A = 0
        loop
        exitwhen A > .numVertices - 1
            set .X[A] = M[1]*.X0[A] + M[2]*.Y0[A] + M[3]*.Z0[A]
            set .Y[A] = M[4]*.X0[A] + M[5]*.Y0[A] + M[6]*.Z0[A]
            set .Z[A] = M[7]*.X0[A] + M[8]*.Y0[A] + M[9]*.Z0[A]
            call BlzSetSpecialEffectPosition( .vertexEffect[A] , .x + .X[A] , .y + .Y[A] , .z + .Z[A] + .effectZoffset )
            set A = A + 1
        endloop

        set A = 0
        loop
        exitwhen A > .numLightnings
            set O = .lightningOrigin[A]
            set E = .lightningEnd[A]
            call MoveLightningEx( .edgeLightning[A] , true , .x + .X[O] , .y + .Y[O] , .z + .Z[O] , .x + .X[E] , .y + .Y[E] , .z + .Z[E] )
            set A = A + 1
        endloop
    endmethod
    
    method AddLightningEdges takes string lightningType, real cutOffDist returns nothing
        local real cod2 = cutOffDist*cutOffDist
        local integer A = 0
        local integer B
        local integer L = 0
        local real dist
        
        loop
        exitwhen A > .numVertices - 1
            set B = A + 1
            loop
            exitwhen B > .numVertices - 1
                set dist = (.X0[A]-.X0[B])*(.X0[A]-.X0[B]) + (.Y0[A]-.Y0[B])*(.Y0[A]-.Y0[B]) + (.Z0[A]-.Z0[B])*(.Z0[A]-.Z0[B])
                if dist < cod2 then
                    set .lightningOrigin[L] = A
                    set .lightningEnd[L] = B
                    set .numLightnings = .numLightnings + 1
                    set .edgeLightning[L] = AddLightningEx( lightningType , true , .X[A] , .Y[A] , .Z[A] , .X[B] , .Y[B] , .Z[B] )
                    set L = L + 1
                endif
                set B = B + 1
            endloop
            set A = A + 1
        endloop
    endmethod

    method onDestroy takes nothing returns nothing
        local integer A = 0
        loop
        exitwhen A > .numVertices - 1
            call DestroyEffect(.vertexEffect[A])
            set A = A + 1
        endloop
    endmethod



//=================================================================================
//Polyhedron constructor functions.
//=================================================================================



    private method CreateNthVertex takes integer A, string vertexEffect returns nothing
        if vertexEffect != "" then
            set .vertexEffect[A] = AddSpecialEffect( vertexEffect , .x + .X0[A] , .y + .Y0[A] )
            call BlzSetSpecialEffectZ( .vertexEffect[A] , .z + .Z0[A] + .effectZoffset )
        endif
    endmethod

    private method CreateDeltoidalHexacontahedron takes real edgeLength, string vertexEffect returns nothing
        
        local integer A
        local integer P
        local integer S

        local real array c1
        local real array c2
        local real array c3
        local real array c4
        local real array c5
        local integer array sign
        local integer array permutation

        set .numVertices = 62

        set c1[1] = 0
        set c1[2] = 0
        set c1[3] = 2.7778
        
        set c2[1] = 0
        set c2[2] = 2.4241
        set c2[3] = 1.4982
        
        set c3[1] = 0
        set c3[2] = 0.9732
        set c3[3] = 2.548
        
        set c4[1] = 1.3889
        set c4[2] = 2.2472
        set c4[3] = 0.8584
        
        set c5[1] = 1.5747
        set c5[2] = 1.5747
        set c5[3] = 1.5747

        set sign[1] = 1
        set sign[2] = 1
        set sign[3] = 1

        set sign[4] = 1
        set sign[5] = 1
        set sign[6] = -1

        set sign[7] = 1
        set sign[8] = -1
        set sign[9] = 1

        set sign[10] = 1
        set sign[11] = -1
        set sign[12] = -1
        
        set sign[13] = -1
        set sign[14] = 1
        set sign[15] = 1

        set sign[16] = -1
        set sign[17] = 1
        set sign[18] = -1

        set sign[19] = -1
        set sign[20] = -1
        set sign[21] = 1

        set sign[22] = -1
        set sign[23] = -1
        set sign[24] = -1

        set permutation[1] = 1
        set permutation[2] = 2
        set permutation[3] = 3

        set permutation[4] = 3
        set permutation[5] = 1
        set permutation[6] = 2

        set permutation[7] = 2
        set permutation[8] = 3
        set permutation[9] = 1

        set A = 0
        set P = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 7
                set .X0[A] = edgeLength*sign[3*S + 1]*c4[permutation[3*P + 1]]
                set .Y0[A] = edgeLength*sign[3*S + 2]*c4[permutation[3*P + 2]]
                set .Z0[A] = edgeLength*sign[3*S + 3]*c4[permutation[3*P + 3]]
                call .CreateNthVertex(A,vertexEffect)
                set A = A + 1
                
                if P == 0 then
                    set .X0[A] = edgeLength*sign[3*S + 1]*c5[permutation[3*P + 1]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c5[permutation[3*P + 2]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c5[permutation[3*P + 3]]
                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                endif
                if sign[3*S + P+1] == 1 then
                    set .X0[A] = edgeLength*sign[3*S + 1]*c2[permutation[3*P + 1]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c2[permutation[3*P + 2]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c2[permutation[3*P + 3]]
                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                
                    set .X0[A] = edgeLength*sign[3*S + 1]*c3[permutation[3*P + 1]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c3[permutation[3*P + 2]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c3[permutation[3*P + 3]]
                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                    
                    if sign[3*S + P+2] == 1 then
                        set .X0[A] = edgeLength*sign[3*S + 1]*c1[permutation[3*P + 1]]
                        set .Y0[A] = edgeLength*sign[3*S + 2]*c1[permutation[3*P + 2]]
                        set .Z0[A] = edgeLength*sign[3*S + 3]*c1[permutation[3*P + 3]]
                        call .CreateNthVertex(A,vertexEffect)
                        set A = A + 1
                    endif
                endif
                set S = S + 1
            endloop
            set P = P + 1
        endloop
    endmethod

    private method CreateDisdyakisTriacontahedron takes real edgeLength, string vertexEffect returns nothing
        
        local integer A
        local integer P
        local integer S

        local real phi = 1.61803
        local real x = 1.7156
        local real R = 1.06509
        local real scale = 1.3
        local real array c1
        local real array c2
        local integer array sign
        local integer array permutation

        set .numVertices = 62

        set c1[1] = 0
        set c1[2] = scale
        set c1[3] = phi
        
        set c2[1] = 0
        set c2[2] = phi
        set c2[3] = scale/phi

        set sign[1] = 1
        set sign[2] = 1
        set sign[3] = 1

        set sign[4] = 1
        set sign[5] = 1
        set sign[6] = -1

        set sign[7] = 1
        set sign[8] = -1
        set sign[9] = 1

        set sign[10] = 1
        set sign[11] = -1
        set sign[12] = -1
        
        set sign[13] = -1
        set sign[14] = 1
        set sign[15] = 1

        set sign[16] = -1
        set sign[17] = 1
        set sign[18] = -1

        set sign[19] = -1
        set sign[20] = -1
        set sign[21] = 1

        set sign[22] = -1
        set sign[23] = -1
        set sign[24] = -1

        set permutation[1] = 1
        set permutation[2] = 2
        set permutation[3] = 3

        set permutation[4] = 3
        set permutation[5] = 1
        set permutation[6] = 2

        set permutation[7] = 2
        set permutation[8] = 3
        set permutation[9] = 1

        set A = 0
        set P = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 7
                if sign[3*S + P+1] == 1 then
                    set .X0[A] = edgeLength*sign[3*S + 1]*c1[permutation[3*P + 1]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c1[permutation[3*P + 2]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c1[permutation[3*P + 3]]
                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                
                    set .X0[A] = edgeLength*sign[3*S + 1]*c2[permutation[3*P + 1]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c2[permutation[3*P + 2]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c2[permutation[3*P + 3]]
                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                endif    
                set S = S + 1
            endloop
            set P = P + 1
        endloop
        

        set c1[1] = R*phi*phi/2
        set c1[2] = R*phi/2
        set c1[3] = R/2

        set S = 0
        loop
        exitwhen S > 7
            set .X0[A] = edgeLength*sign[3*S + 1]
            set .Y0[A] = edgeLength*sign[3*S + 2]
            set .Z0[A] = edgeLength*sign[3*S + 3]
            call .CreateNthVertex(A,vertexEffect)
            set A = A + 1
            
            set P = 0
            loop
            exitwhen P > 2
                set .X0[A] = edgeLength*sign[3*S + 1]*c1[permutation[3*P + 1]]
                set .Y0[A] = edgeLength*sign[3*S + 2]*c1[permutation[3*P + 2]]
                set .Z0[A] = edgeLength*sign[3*S + 3]*c1[permutation[3*P + 3]]
                call .CreateNthVertex(A,vertexEffect)
                set A = A + 1
            
                set P = P + 1
            endloop
            set S = S + 1
        endloop
        
        set sign[1] = 1
        set sign[2] = -1
        
        set c1[1] = 0
        set c1[2] = 0
        set c1[3] = R*phi
        
        set S = 0
        loop
        exitwhen S > 1
            set P = 0
            loop
            exitwhen P > 2
                set .X0[A] = edgeLength*sign[S+1]*c1[permutation[3*P + 1]]
                set .Y0[A] = edgeLength*sign[S+1]*c1[permutation[3*P + 2]]
                set .Z0[A] = edgeLength*sign[S+1]*c1[permutation[3*P + 3]]
                call .CreateNthVertex(A,vertexEffect)
                set A = A + 1
            
                set P = P + 1
            endloop
            set S = S + 1
        endloop
    endmethod

    private method CreateSnubDodecahedron takes real edgeLength, string vertexEffect returns nothing
        
        local integer A
        local integer P
        local integer S
        local integer E
        local integer I

        local real phi = 1.61803
        local real x = 1.7156
        local real array c
        local integer array sets
        local integer array sign
        local integer array permutation
        local real scale = 0.9

        set .numVertices = 60

        set c[0] = phi * SquareRoot(3 - x*x) / 2
        set c[1] = x * phi * SquareRoot(3 - x*x) / 2
        set c[2] = phi * SquareRoot((x-1-(1/x))*phi) / 2
        set c[3] = x*x * phi * SquareRoot(3 - x*x) / 2
        set c[4] = x * phi * SquareRoot((x-1-(1/x))*phi) / 2
        set c[5] = phi * SquareRoot(1 - x + (phi + 1)/x) / 2
        set c[6] = phi * SquareRoot(x - phi + 1) / 2
        set c[7] = x*x * phi * SquareRoot((x-1-(1/x))*phi) / 2
        set c[8] = x * phi * SquareRoot(1-x+(phi+1)/x) / 2
        set c[9] = SquareRoot((x+2)*phi + 2) / 2
        set c[10] = x * SquareRoot(x * (phi + 1) - phi) / 2
        set c[11] = SquareRoot((x*x) * (2*phi + 1) - phi) / 2
        set c[12] = phi * SquareRoot(x*x + x) / 2
        set c[13] = phi*phi * SquareRoot(x * (x+phi) + 1) / (2*x)
        set c[14] = phi * SquareRoot(x * (x+phi) + 1) / 2
        
        set sets[1] = 2
        set sets[2] = 1
        set sets[3] = 14
        
        set sets[4] = 0
        set sets[5] = 8
        set sets[6] = 12
        
        set sets[7] = 7
        set sets[8] = 6
        set sets[9] = 11

        set sign[1] = -1
        set sign[2] = -1
        set sign[3] = -1

        set sign[4] = -1
        set sign[5] = 1
        set sign[6] = 1

        set sign[7] = 1
        set sign[8] = 1
        set sign[9] = -1

        set sign[10] = 1
        set sign[11] = -1
        set sign[12] = 1

        set permutation[1] = 1
        set permutation[2] = 2
        set permutation[3] = 3

        set permutation[4] = 3
        set permutation[5] = 1
        set permutation[6] = 2

        set permutation[7] = 2
        set permutation[8] = 3
        set permutation[9] = 1

        set A = 0
        set P = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 3
                set E = 0
                loop
                exitwhen E > 2
                    set .X0[A] = edgeLength*sign[3*S + 1]*c[sets[3*E + permutation[3*P + 1]]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c[sets[3*E + permutation[3*P + 2]]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c[sets[3*E + permutation[3*P + 3]]]

                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                    set E = E + 1
                endloop
                set S = S + 1
            endloop
            set P = P + 1
        endloop
        
        set sets[1] = 3
        set sets[2] = 4
        set sets[3] = 13
        
        set sets[4] = 9
        set sets[5] = 5
        set sets[6] = 10

        set sign[1] = 1
        set sign[2] = 1
        set sign[3] = 1

        set sign[4] = 1
        set sign[5] = -1
        set sign[6] = -1

        set sign[7] = -1
        set sign[8] = 1
        set sign[9] = -1

        set sign[10] = -1
        set sign[11] = -1
        set sign[12] = 1

        set permutation[1] = 1
        set permutation[2] = 2
        set permutation[3] = 3

        set permutation[4] = 3
        set permutation[5] = 1
        set permutation[6] = 2

        set permutation[7] = 2
        set permutation[8] = 3
        set permutation[9] = 1

        set P = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 3
                set E = 0
                loop
                exitwhen E > 1
                    set .X0[A] = edgeLength*sign[3*S + 1]*c[sets[3*E + permutation[3*P + 1]]]
                    set .Y0[A] = edgeLength*sign[3*S + 2]*c[sets[3*E + permutation[3*P + 2]]]
                    set .Z0[A] = edgeLength*sign[3*S + 3]*c[sets[3*E + permutation[3*P + 3]]]

                    call .CreateNthVertex(A,vertexEffect)
                    set A = A + 1
                    set E = E + 1
                endloop
                set S = S + 1
            endloop
            set P = P + 1
        endloop
    endmethod

    private method CreateSnubCube takes real edgeLength, string vertexEffect returns nothing
        
        local integer A
        local integer P = 0
        local integer S
        local integer I

        local real t = 1.83929
        local real a = 1/1.60972
        local real array c
        local integer array sign
        local integer array permutation

        set .numVertices = 24

        set c[1] = a
        set c[2] = a/t
        set c[3] = a*t

        set sign[1] = -1
        set sign[2] = -1
        set sign[3] = -1

        set sign[4] = -1
        set sign[5] = 1
        set sign[6] = 1

        set sign[7] = 1
        set sign[8] = 1
        set sign[9] = -1

        set sign[10] = 1
        set sign[11] = -1
        set sign[12] = 1

        set permutation[1] = 1
        set permutation[2] = 2
        set permutation[3] = 3

        set permutation[4] = 3
        set permutation[5] = 1
        set permutation[6] = 2

        set permutation[7] = 2
        set permutation[8] = 3
        set permutation[9] = 1

        set A = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 3
                set .X0[A] = edgeLength*sign[3*S + 1]*c[permutation[3*P + 1]]
                set .Y0[A] = edgeLength*sign[3*S + 2]*c[permutation[3*P + 2]]
                set .Z0[A] = edgeLength*sign[3*S + 3]*c[permutation[3*P + 3]]

                call .CreateNthVertex(A,vertexEffect)
                set A = A + 2
                set S = S + 1
            endloop

            set P = P + 1
        endloop

        set sign[1] = 1
        set sign[2] = 1
        set sign[3] = 1

        set sign[4] = 1
        set sign[5] = -1
        set sign[6] = -1

        set sign[7] = -1
        set sign[8] = 1
        set sign[9] = -1

        set sign[10] = -1
        set sign[11] = -1
        set sign[12] = 1

        set permutation[1] = 3
        set permutation[2] = 2
        set permutation[3] = 1

        set permutation[4] = 2
        set permutation[5] = 1
        set permutation[6] = 3

        set permutation[7] = 1
        set permutation[8] = 3
        set permutation[9] = 2

        set A = 1
        set P = 0
        loop
        exitwhen P > 2
            set S = 0
            loop
            exitwhen S > 3
                set .X0[A] = edgeLength*sign[3*S + 1]*c[permutation[3*P + 1]]
                set .Y0[A] = edgeLength*sign[3*S + 2]*c[permutation[3*P + 2]]
                set .Z0[A] = edgeLength*sign[3*S + 3]*c[permutation[3*P + 3]]

                call .CreateNthVertex(A,vertexEffect)
                set A = A + 2
                set S = S + 1
            endloop

            set P = P + 1
        endloop
    endmethod

    private method CreateTetrakisHexahedron takes real edgeLength, string vertexEffect returns nothing
        local integer A = 0
        local real phi
        local integer X = 1
        local integer Y = 1
        local integer Z = 1
        local real offset = 0.5
        local real m = 1.333

        set .numVertices = 14

        loop
        exitwhen A > 7
            if ModuloInteger(A,2) == 1 then
                set X = -1*X
            endif
            if A == 2 or A == 6 then
                set Y = -1*Y
            endif
            if A == 4 then
                set Z = -1*Z
            endif

            set .X0[A] = X*m*edgeLength/2
            set .Y0[A] = Y*m*edgeLength/2
            set .Z0[A] = Z*m*edgeLength/2

            call .CreateNthVertex(A,vertexEffect)

            set A = A + 1
        endloop

        set .X0[A] = ((1+offset)*m*edgeLength)/2
        set .Y0[A] = 0
        set .Z0[A] = 0
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = -((1+offset)*m*edgeLength)/2
        set .Y0[A] = 0
        set .Z0[A] = 0
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = ((1+offset)*m*edgeLength)/2
        set .Z0[A] = 0
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = -((1+offset)*m*edgeLength)/2
        set .Z0[A] = 0
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = 0
        set .Z0[A] = ((1+offset)*m*edgeLength)/2
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = 0
        set .Z0[A] = -((1+offset)*m*edgeLength)/2
        call .CreateNthVertex(A,vertexEffect)    
    endmethod

    private method CreateTriacontahedron takes real edgeLength, string vertexEffect returns nothing
        local real t = 0.8616*edgeLength
        local real p = 1.618
        local integer A = -1
        local integer B
        local integer C
        local integer N = 0

        set A = -1
        loop
        exitwhen A > 1
            set B = -1
            loop
            exitwhen B > 1
                set C = -1
                loop
                exitwhen C > 1
                    set .X0[N] = A*t
                    set .Y0[N] = B*t
                    set .Z0[N] = C*t
                    call .CreateNthVertex(N,vertexEffect)
                    set N = N + 1
                    if B == 1 then
                        set .X0[N] = 0
                        set .Y0[N] = A*t*p
                        set .Z0[N] = C*t/p
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1

                        set .X0[N] = A*t/p
                        set .Y0[N] = 0
                        set .Z0[N] = C*t*p
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1

                        set .X0[N] = A*t*p
                        set .Y0[N] = C*t/p
                        set .Z0[N] = 0
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1

                        set .X0[N] = A*edgeLength/1.46
                        set .Y0[N] = 2*C*edgeLength/1.46
                        set .Z0[N] = 0
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1

                        set .X0[N] = 0
                        set .Y0[N] = A*edgeLength/1.46
                        set .Z0[N] = 2*C*edgeLength/1.46
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1

                        set .X0[N] = 2*C*edgeLength/1.46
                        set .Y0[N] = 0
                        set .Z0[N] = A*edgeLength/1.46
                        call .CreateNthVertex(N,vertexEffect)
                        set N = N + 1
                    endif
                    set C = C + 2
                endloop
                set B = B + 2
            endloop
            set A = A + 2
        endloop
        set .numVertices = 32
    endmethod

    private method CreateCuboctahedron takes real edgeLength, string vertexEffect returns nothing
        local integer A = 0
        local real phi
        local real Z
        local real XY

        set .numVertices = 12

        loop
        exitwhen A > .numVertices - 1
            if A == 0 then
                set phi = 0
                set Z = edgeLength/SquareRoot(2)
                set XY = edgeLength/SquareRoot(2)
            elseif A == 4 then
                set phi = bj_PI/4
                set Z = 0
                set XY = edgeLength
            elseif A == 8 then
                set phi = 0
                set Z = -edgeLength/SquareRoot(2)
                set XY = edgeLength/SquareRoot(2)
            endif
            set .X0[A] = XY*Cos(phi)
            set .Y0[A] = XY*Sin(phi)
            set .Z0[A] = Z

            call .CreateNthVertex(A,vertexEffect)

            set A = A + 1
            set phi = phi + bj_PI/2
        endloop
    endmethod

    private method CreateCube takes real edgeLength, string vertexEffect returns nothing
        local integer A = 0
        local real phi = bj_PI/4
        local real Z = -edgeLength/2

        set .numVertices = 8

        loop
        exitwhen A > .numVertices - 1
            if A == 4 then
                set Z = edgeLength/2
            endif

            set .X0[A] = edgeLength/SquareRoot(2)*Cos(phi)
            set .Y0[A] = edgeLength/SquareRoot(2)*Sin(phi)
            set .Z0[A] = Z

            call .CreateNthVertex(A,vertexEffect)

            set A = A + 1
            set phi = phi + bj_PI/2
        endloop
        
    endmethod

    private method CreateOctahedron takes real edgeLength, string vertexEffect returns nothing
        local integer A = 0
        local real phi = 0
        local real Z = 0

        set .numVertices = 6

        loop
        exitwhen A > 3
            set .X0[A] = edgeLength/SquareRoot(2)*Cos(phi)
            set .Y0[A] = edgeLength/SquareRoot(2)*Sin(phi)
            set .Z0[A] = Z

            call .CreateNthVertex(A,vertexEffect)

            set A = A + 1
            set phi = phi + bj_PI/2
        endloop

        set .X0[A] = 0
        set .Y0[A] = 0
        set .Z0[A] = edgeLength/SquareRoot(2)
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = 0
        set .Z0[A] = -edgeLength/SquareRoot(2)
        call .CreateNthVertex(A,vertexEffect)
    endmethod

    private method CreateTetrahedron takes real edgeLength, string vertexEffect returns nothing
        local real L = edgeLength*SquareRoot(3.0/8.0)
        local integer A = 0
        set .numVertices = 4

        set .X0[A] = SquareRoot(8.0/9.0)*L
        set .Y0[A] = 0
        set .Z0[A] = -L/3
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = -SquareRoot(2.0/9.0)*L
        set .Y0[A] = SquareRoot(2.0/3.0)*L
        set .Z0[A] = -L/3
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = -SquareRoot(2.0/9.0)*L
        set .Y0[A] = -SquareRoot(2.0/3.0)*L
        set .Z0[A] = -L/3
        call .CreateNthVertex(A,vertexEffect)
        set A = A + 1

        set .X0[A] = 0
        set .Y0[A] = 0
        set .Z0[A] = L
        call .CreateNthVertex(A,vertexEffect)
    endmethod
    

    static method create takes real x, real y, real z, string whichPolyhedron, real edgeLength, string vertexEffect, real effectZoffset, real effectScale, real rotationSpeed, real precessionSpeed returns polyhedron
        local polyhedron newPolyhedron = polyhedron.allocate()
        local integer A = 0

        set newPolyhedron.effectZoffset = effectZoffset
        set newPolyhedron.x = x
        set newPolyhedron.y = y
        set newPolyhedron.z = z
        
        if whichPolyhedron == "deltoidalhexacontahedron" then                    //62 (Catalan)
            call newPolyhedron.CreateDeltoidalHexacontahedron(edgeLength , vertexEffect)
        elseif     whichPolyhedron == "disdyakistriacontahedron" then                //62 (Catalan)
            call newPolyhedron.CreateDisdyakisTriacontahedron(edgeLength , vertexEffect)
        elseif     whichPolyhedron == "snubdodecahedron" then                    //60 (Archimedean)
            call newPolyhedron.CreateSnubDodecahedron(edgeLength , vertexEffect)
        elseif whichPolyhedron == "triacontahedron" then                    //32 (Catalan)
            call newPolyhedron.CreateTriacontahedron(edgeLength , vertexEffect)
        elseif whichPolyhedron == "snubcube" then                        //24 (Archimedean)
            call newPolyhedron.CreateSnubCube(edgeLength , vertexEffect)
        elseif whichPolyhedron == "tetrakishexahedron" then                    //14 (Catalan)
            call newPolyhedron.CreateTetrakisHexahedron(edgeLength , vertexEffect)
        elseif whichPolyhedron == "cuboctahedron" then                        //12 (Archimedean)
            call newPolyhedron.CreateCuboctahedron(edgeLength , vertexEffect)
        elseif whichPolyhedron == "cube" then                            //8 (Platonic)
            call newPolyhedron.CreateCube(edgeLength , vertexEffect)
        elseif whichPolyhedron == "octahedron" then                        //6 (Platonic)
            call newPolyhedron.CreateOctahedron(edgeLength , vertexEffect)
        elseif whichPolyhedron == "tetrahedron" then                        //4 (Platonic)
            call newPolyhedron.CreateTetrahedron(edgeLength , vertexEffect)
        else
            call BJDebugMsg("Invalid polyhedron type")
            return 0
        endif

        loop
        exitwhen A > newPolyhedron.numVertices - 1
            call BlzSetSpecialEffectScale( newPolyhedron.vertexEffect[A] , effectScale )
            set A = A + 1
        endloop
        
        set newPolyhedron.rotSpeed = rotationSpeed
        set newPolyhedron.precessionSpeed = precessionSpeed
        return newPolyhedron
    endmethod
    
    static method createSimple takes real x, real y, real z, string whichPolyhedron, real edgeLength returns polyhedron
        local polyhedron newPolyhedron = polyhedron.create(x, y, z, whichPolyhedron, edgeLength, "", 0, 0, 0, 0)
        return newPolyhedron
    endmethod
endstruct

endlibrary
 

Attachments

  • PolyhedronTest.w3m
    40.1 KB · Views: 28
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
1668095891906.png


THIS is absolutely awesome! What a cool demo map. A bit laggy in the beginning, but I would attribute that to the massive amount of custom shapes on the screen rather than to the efficiency of the resource itself.

I've updated your script (but not your demo map) to reduce the war3map.j code length by about 800 lines. This is because the "create" method is calling functions which are declared below itself, making it so JassHelper duplicated ALL of those functions. The solution was to simply move the "create" methods to the bottom of the struct.

Approved!
 
View attachment 413509

THIS is absolutely awesome! What a cool demo map. A bit laggy in the beginning, but I would attribute that to the massive amount of custom shapes on the screen rather than to the efficiency of the resource itself.

I've updated your script (but not your demo map) to reduce the war3map.j code length by about 800 lines. This is because the "create" method is calling functions which are declared below itself, making it so JassHelper duplicated ALL of those functions. The solution was to simply move the "create" methods to the bottom of the struct.

Approved!
Thank you very much! Oh, I didn't know that was a thing. I guess I should fix that in my maps as well.

I could still do some improvements to the API. I think a good idea is to detach the creation of the special effects from the creation of the polyhedron and make that separately, with more customization options such as Yaw/Pitch/Roll/Scale etc. of the special effects.
 
Top