• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Maths help creating complex shapes in warcraft Astroids, Lemniscates and more

Status
Not open for further replies.
Level 3
Joined
Oct 7, 2011
Messages
37
Hi Folks,

I was interested in creating a complex shape to make a moving unit that creates doodads around them look less boring then just a straight rectangle and I stumbled across this post and this tutorial

I managed to get Daelin's example working from the tutorial link to draw a Cuspoid ok in Jass he had an example in GUI that i converted ok.
He had the formulas for drawing some other complex objects but no implementations so I was trying to convert from my bad maths to working shapes.

Cuspoid.jpg

You can see from the image that it has the text displayed correctly in the centre of the shape and the shape is correct too for an added bonus :ogre_haosis:

JASS:
/*
[url]http://www.thehelper.net/threads/graphics-static-shapes-gui.33870/[/url]
deltoid (three cusps hypocycloid)
x=[2/3 cos? – 1/3 cos(2?)] * radius
y=[2/3 sin? + 1/3 sin(2?)] * radius
*/
function Draw_Cuspoid takes player owner, integer unitType, location centre, real radius returns nothing
    local real twoThirds = 2.0 / 3.0
    local real oneThird = 1.0 / 3.0
    local real X = 0
    local real Y = 0
    local real angle = 0
    local real centreX = GetLocationX(centre)
    local real centreY = GetLocationY(centre)
    local integer index = 1
    local location tempPosition   
    
    call FloatTextAtPoint(centre, "Cuspoid")
    loop
    exitwhen index > 50
        set angle = ((360 / 50) * I2R(index))
        set X = (((twoThirds) * (Cos(angle))) - ((oneThird) * (Cos((2.00 * angle)))))
        set X = (X * radius) + centreX
        set Y = (((twoThirds) * (Sin(angle))) + ((oneThird) * (Sin((2.00 * angle)))))
        set Y = (Y * radius) + centreY
        set tempPosition = Location(X,Y)
        call CreateUnit( owner, unitType, X, Y, AngleBetweenPoints(centre,tempPosition))
        call RemoveLocation(tempPosition)
        set index = index + 1
    endloop    
endfunction
I've managed to get Astroid, Cardiod and Nephroid to draw correctly but they centre in the wrong position and my Lemniscate is very wrong i think could anyone with some better Jass or mostly Maths skills take a look and tell me how to fix my code please

The shapes other than Lemniscate seem correct but they are way off centre position for some reason I probably have some sign around the wrong way or converted the formulas incorrectly.
i.e.

Astroid.jpg

The shape is correct but the centre point is outside the shape entirely above the top right corner ( I also failed in the screenshot since its not even visible but trust me it exists heh )
JASS:
/*
[url]http://www.thehelper.net/threads/graphics-static-shapes-gui.33870/[/url]
Astroid (4 cusps hypocycloid)
x= x0 + radius * cos^3(angle) = x0 + radius * cos(angle) * cos(angle) * cos(angle)
y= y0 + radius * sin^3(angle) = y0 + radius * sin(angle) * sin(angle) * sin(angle)
*/
function Draw_Astroid takes player owner, integer unitType, location centre, real radius returns nothing
    local real X = 0
    local real Y = 0
    local real x0 = 0
    local real y0 = 0
    local real angle = 0
    local real centreX = GetLocationX(centre)
    local real centreY = GetLocationY(centre)
    local integer index = 1
    local location tempPosition   
    
    call FloatTextAtPoint(centre, "Astroid")
    loop
    exitwhen index > 50
        set angle = ((360 / 50) * I2R(index))
        set X = (x0 + (radius * Pow(Cos(angle),3))) + centreX
        set Y = (y0 + (radius * Pow(Sin(angle),3))) + centreY
        if(index == 1) then
            set x0 = X
            set y0 = Y 
        else
            set tempPosition = Location(X,Y)
            call CreateUnit( owner, unitType, X, Y, AngleBetweenPoints(centre,tempPosition))
            call RemoveLocation(tempPosition)
        endif
        set index = index + 1
    endloop    
endfunction
The formulas are above each function as how I interpreted them from the original tutorial from Daelin (tutorial same link as above)

I've attached my test map for this the main code is in the "map-specific custom script code" area
The Functions that I am hoping someone can check over are;
  • Draw_Lemniscate
  • Draw_Nephroid
  • Draw_Cardiod
  • Draw_Astroid
The Draw cuspoids trigger selects a center position and calls the functions at 1 second after the map starts

Additional bonus if anyone knows of a way to detect whether a point is inside any of these areas? I could use the angle i guess from the centre point to the point in question then increment out from the centre point and if i hit the desired point before one of the dummies its inside otherwise outside, does that sound feasible?
 

Attachments

  • ExampleDestructableCreationMapv2.w3x
    41.9 KB · Views: 103
Last edited:
Level 3
Joined
Oct 7, 2011
Messages
37
Partially working now

Ok I've changed them to convert from degrees to radians as suggested

I've also drawn them at centered over 0,0 rather than the actual coordinates and translated to the correct position when creating the units at least that was my intention by taking the centreX and centreY out of the formula

JASS:
function Draw_Nephroid takes player owner, integer unitType, location centre, real radius returns nothing
    local real X = 0
    local real Y = 0
    local real x0 = 0
    local real y0 = 0
    local real angle = 0
    local real centreX = GetLocationX(centre)
    local real centreY = GetLocationY(centre)
    local integer index = 1
    local location tempPosition   
    
    call FloatTextAtPoint(centre, "Nephroid")
    loop
    exitwhen index > 75
    //I dont understand this angle if i set it to the correct value 360/75 it masses the units to closely together if 10 perfect if 15 not so bad but a bit patchy
        set angle = ((10) * I2R(index)) * bj_DEGTORAD
        set X = (x0 + radius * (3 * Cos(angle) - Cos(3 * angle)))
        set Y = (y0 + radius * (3 * Sin(angle) - Sin(3 * angle)))
        if(index == 1) then
            set x0 = X
            set y0 = Y            
        else
            set tempPosition = Location(X,Y)
            call CreateUnit( owner, unitType, X + centreX, Y + centreY, AngleBetweenPoints(centre,tempPosition))
            call RemoveLocation(tempPosition)
        endif
        set index = index + 1
    endloop    
endfunction
I think this is probably correct now? the text isn't centered inside the object but starts on a corner of it at least all the other shapes are similar except for the original example from Daelin which is still dead center for the text

JASS:
/*
[url]http://www.thehelper.net/threads/graphics-static-shapes-gui.33870/[/url]
Lemniscate
x=x0 + radius * cos(angle) / 1 + sin^2(angle)
y=y0 + radius * sin(angle) * cos(angle) / 1 + sin^2(angle)
*/
function Draw_Lemniscate takes player owner, integer unitType, location centre, real radius returns nothing
    local real X = 0
    local real Y = 0
    local real x0 = 0
    local real y0 = 0
    local real angle = 0
    local real centreX = GetLocationX(centre)
    local real centreY = GetLocationY(centre)
    local integer index = 1
    local location tempPosition   
    
    call FloatTextAtPoint(centre, "Lemniscate")
    loop
    exitwhen index > 100
        set angle = ((360 / 100) * I2R(index)) * bj_DEGTORAD
        set X = x0 + (((Cos(angle) / 1 + Pow(Sin(angle),2)) * radius) )
        set Y = y0 + (((Sin(angle) * Cos(angle) / 1 + Pow(Sin(angle),2)) * radius))
        if(index == 1) then
            set x0 = X
            set y0 = Y            
        else
            set tempPosition = Location(X,Y)
            call CreateUnit( owner, unitType, X + centreX, Y + centreY, AngleBetweenPoints(centre,tempPosition))
            call RemoveLocation(tempPosition)
        endif
        set index = index + 1
    endloop    
endfunction
Complex Shape: A shape made of a combination of 2 or more shapes.

Also known as a compound figure or compound shape.
It might be bending the definition slightly but you could draw some of these shapes from combinations of others and they are definitely not simple shapes

Thank you for your reply PurgeandFire111 certainly fixed most of the issues in one hit :thumbs_up:

Ive reuploaded the current code if anyone needs to see the shapes its currently making
 
It is most likely an issue of order of operations. This is the code that Daelin posted:
JASS:
x=x0+a*cosφ / 1+sin^2(φ)
y=y0+a*sinφ*cosφ/1+sin^2(φ)
The problem is that if defined that way, it will look like this (where b is x0):
attachment.php

Which of course, isn't the way Daelin means it to be. :p So I assume that is where the problem is. Yours is:
x = x0 + ( (cos φ / 1) + sin2(φ) ) * a
Which is probably not the right way. We can assume 1 and sin should be added because ([cos x] / 1) would just be (cos x), so there would be no point in having the 1 there otherwise.

Since I can't actually test them myself, I would recommend that you play with the code a bit with different combinations to see which one works. For example:
  • x = x0 + (a * cos φ) / (1 + sin2(φ))
    y = y0 + (a * sin φ * cos φ) / (1 + sin2(φ))
    .
  • x = (x0 + a * cos φ ) / (1 + sin2(φ))
    y = (y0 + a * sin φ * cos φ) / (1 + sin2(φ))

Hopefully I didn't read it wrong or anything. If you need any help with implementation or whatever you can ask in this thread.
 

Attachments

  • MSP30161a3f2ghhh225ic4h00006992idci7e63i1eg.gif
    MSP30161a3f2ghhh225ic4h00006992idci7e63i1eg.gif
    1 KB · Views: 250
Level 3
Joined
Oct 7, 2011
Messages
37
Thank you for the reply again ;)
Definitely narrowing down the issues the /1 being useless in the old position makes sense heh I've tried your suggestions one looks very promising but maybe i have to keep the loop going past 360 degrees or something? it seems like it almost completes the shape 1 corner missing?

The first formula
JASS:
set X = x0 + (radius * Cos(angle)) / (1 + Pow(Sin(angle),2))
set Y = y0 + (radius * Sin(angle) * Cos(angle)) / (1 + Pow(Sin(angle),2))
Produces this
LemniscateFormula1.jpg


The second
JASS:
set X = (x0 + radius * Cos(angle)) / (1 + Pow(Sin(angle),2))
set Y = (y0 + radius * Sin(angle) * Cos(angle)) / (1 + Pow(Sin(angle),2))
produces this
LemniscateFormula2.jpg


According to a quick google search the first one is definitely the correct shape do you have any ideas why it wouldn't be completing it though?
 
Haha, awesome. Tbh, both look pretty cool lol.

But anyway, it may either be a problem with the code or hitting the op limit. To verify that it is not the latter, add a debug message (call BJDebugMsg(I2S(index))) before endloop and make sure that the index reaches 100. If it doesn't, then there is your problem and we'll fix it from there. :)

If not, then we know it is something with the code and then we'll figure out where to go.
 
Level 17
Joined
Jul 17, 2011
Messages
1,863
JASS:
set X = (x0 + radius * Cos(angle)) / (1 + Pow(Sin(angle),2))
set Y = (y0 + radius * Sin(angle) * Cos(angle)) / (1 + Pow(Sin(angle),2))

what is this x0 and y0 it should be xθ and yθ or in your case "angle"

for the above shapes that you are creating, its possible that you are hitting some number restriction such as a<360 withing the code
 
Level 3
Joined
Oct 7, 2011
Messages
37
Heh I had no idea x0 and y0 was to align it in the quadrants does that mean it should be a value between -1 and 1?

I thought it meant the first value of x and y so I was setting it to that on index == 1

I've tried a few things from your suggestions I tried commenting out a few of the other shapes in case the map was running out of units or something and I tried the debug message unfortunately no change the loop did get to 100 and commenting out the others didn't help

The angle value in radians starts at 0.052 at index 1 in the loop and ends at 5.236 at index 100
In degrees thats 3 at index 1 and 300 at index 100

Ahhh brain wave heh

Ok I tested it the angle was being automatically changed to int variables instead of reals

changed
JASS:
set angle = ((360 / 100) * I2R(index)) * bj_DEGTORAD
to
JASS:
set angle = ((360.0 / 100.0) * I2R(index)) * bj_DEGTORAD
and its not clamping the values anymore

Ok if i set the x0 and y0 to both 0 it works fine and the text is centered at last heh

Thanks everyone specifically PurgeandFire111 ;) Ill finish up a function for checking if a point is within the shape then maybe post this in the code section if anyones interested in making mathematical shapes at some point
 
Last edited:
I didn't mean aligning in quadrants, I just meant that it offsets by x or y coordinates. Just a horizontal or vertical shift. :) So if it is "x = 500 + radius*Cos(angle)...." or w/e, it will shift the graph 500 units to the right of where "x = radius*Cos(angle)..." alone would be.

But I'm glad to hear that it works. :D
 
Status
Not open for further replies.
Top