HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Random Point In Trapezium

12-10-2007, 09:08 AM#1
PandaMine
Since I managed to derive (myself, seems like no one was up to the challange that I specified here http://www.wc3campaigns.net/showthread.php?t=98175, it was quite difficult I must say, it took me 5 hours to do) the 4 points that form a trapezium of the cameras current view for a player, I now need to find a random point inside this trapazoid.

Firstly here is the code if anyone is intereste, x1,y1,x2,y2,x3,y3 and x4,y4 are the 4 points that will form a trapezium of the current cameras view, it isn't 100% accurate (you can play around with the constants) but accurate enough, and it is compatible with rotations done by insert/delete and pitch through mouse scroll (or pageup/pagedown)
Collapse JASS:
    local real rotation =  GetCameraField(CAMERA_FIELD_ROTATION)
    local real distance = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
    local real aoa = GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK)
    local real eye = GetCameraEyePositionZ()
    local real topbound = 11/distance * 180000
    local real midbound = distance/11 * 6
    local real lowbound = distance/11 * 5
    local real highboundmodifier = 957481
    local real verticalhighbound = highboundmodifier * 1/eye
    local real verticallowbound = 100 *aoa 
    local real base = Atan2(verticalhighbound,topbound)
    local real base2 = Atan2(verticallowbound,lowbound)
    local real angle = base - bj_PI/2 + rotation
    local real angle2 = base + bj_PI/2 - rotation
    local real angle3 = base2 - bj_PI/2 + rotation
    local real angle4 = base2 + bj_PI/2 - rotation
    local real dist1 = SquareRoot((topbound*topbound) + (verticalhighbound*verticalhighbound))
    local real dist2 = SquareRoot((verticallowbound*verticallowbound) + (lowbound * lowbound))
    local real x =GetCameraTargetPositionX()
    local real y = GetCameraTargetPositionY()
    //Point at top right
    local real x1 = x+dist1 * Cos(angle)
    local real y1 = y +dist1 * Sin(angle)
    //Point at top left
    local real x2 = x+dist1 * Cos(bj_PI - angle2)
    local real y2 = y +dist1 * Sin(bj_PI - angle2)
    //Point at bottom right
    local real x3 = x+dist2 * Cos(-angle4)
    local real y3 = y +dist2 * Sin(-angle2)
    //Point at bottom left
    local real x4 = x+dist2 * Cos(bj_PI + angle3)
    local real y4 = y +dist2 * Sin(bj_PI + angle)
Note I am aware this will desync in multiplayer, I know how to fix that easily, I am now mainly concerned about finding a random point in this trapezium


Basically what I need to do now is to find the most efficient way of finding a random point inside this trapezium. Note that the 4 points specified will always form a polygon that is a trapezium, and the trapezium will always be shorter at the bottom and longer at the top, the changing values of the points will only rotate the trapeziuem (never past 180 or pi degrees) and will only skew it, i.e. refer to this diagram
Zoom (requires log in)
NOTE: When I mean efficient, I really do mean efficient, I want the minimum amount of calculations done. This will be done within a large loop so I need as little opcode operations as possible

as usual rep for anyone who helps
Attached Images
File type: jpgtrapezium.JPG (3.7 KB)
12-10-2007, 11:42 AM#2
Fireeye
Well, i don't have WE atm, but this is the code i figured out.
Collapse JASS:
struct RPTrap
    real x
    real y
endstruct

function RandomTrap takes real x, real y, real angle, real d0, real d1, real d2, real h returns RPTrap
    local RPTrap dat = RPTrap.create()
    local real rv
    local real cv1 = GetRandomReal(0,d0)
    local real cv2
    if cv1 < d1 then
        set rv = cv1/d1
        set cv2 = GetRandomReal(0,rv) * h * -1
    elseif cv1 > d0-d2 then
        set rv = 1-((cv-(d0-d2))/d2)
        set cv2 = GetRandomReal(0,rv) * h * -1
    elseif
        set cv2 = GetRandomReal(0,h)
    endif
    set dat.x = cv1 * Cos(angle) + cv1 * Cos(angle-(bj_PI/2)) + x
    set dat.y = cv2 * Sin(angle) + cv2 * Sin(angle-(bj_PI/2)) + y
    return dat
endfunction
---Edit---
Sorry, i forgot to mention that x and y are the x and y coordinates of the x2,y2 point.
---Edit2---
oh man i wrote some crap at the end... fixed it hopefully ...
12-10-2007, 10:29 PM#3
PandaMine
Quote:
Originally Posted by Fireeye
Well, i don't have WE atm, but this is the code i figured out.
Collapse JASS:
struct RPTrap
    real x
    real y
endstruct

function RandomTrap takes real x, real y, real angle, real d0, real d1, real d2, real h returns RPTrap
    local RPTrap dat = RPTrap.create()
    local real rv
    local real cv1 = GetRandomReal(0,d0)
    local real cv2
    if cv1 < d1 then
        set rv = cv1/d1
        set cv2 = GetRandomReal(0,rv) * h
    elseif cv1 > d0-d2 then
        set rv = 1-((cv-(d0-d2))/d2)
        set cv2 = GetRandomReal(0,rv) * h
    elseif
        set cv2 = GetRandomReal(0,h)
    endif
    set dat.x = cv1 * Sin(angle) + x
    set dat.y = cv2 * Sin(angle-(bj_PI/2)) + y
    return dat
endfunction
---Edit---
Sorry, i forgot to mention that x and y are the x and y coordinates of the x2,y2 point.

Thanks for your help but Im unsre about the arguments that are being fed into your function. What I created will return 4 points that will always form a trapezium however your function has angles, one x/y point (this one I know is x2,y2), 3 distance reals and a h (assuming its height). Would you be able to rewrite the function so It uses the 4 points or explain how those arguments relate to the trapezium

I am going to rep you for your help though, thx
12-10-2007, 11:38 PM#4
MaD[Lion]
http://www.cgafaq.info/wiki/Random_Point_In_Triangle

here is the formula, have fun :)

TIP: a trapezium is formed by 2 triangles
12-11-2007, 12:06 AM#5
cohadar
Quote:
Originally Posted by MaD[Lion]
TIP: a trapezium is formed by 2 triangles

You can also use 4 triangles if you want to be sadistic :D
12-11-2007, 12:13 AM#6
PandaMine
Thanks heaps Mad Lion, just the help I needed (got it now)
12-11-2007, 01:19 AM#7
cohadar
This is not over it seems.
12-11-2007, 01:22 AM#8
PandaMine
Quote:
Originally Posted by cohadar
This is not over it seems.

Yeah it sure as hell isnt, I have a problem where sometimes the point is above the trapezium, not sure how or why it happens. Here is a screenshot, the pings are the points and as you can see it is well above the trapezium in some instances

Zoom (requires log in)
Attached Images
File type: jpgtrapezium.JPG (3.7 KB)
File type: jpgprob.JPG (68.6 KB)
12-11-2007, 01:25 AM#9
cohadar
Will you be so kind to also make pings at four corners of trapezium at the same time you ping a random point so we actually see that you got the right thing?
12-11-2007, 01:31 AM#10
PandaMine
Here it is, the red pings are the 4 corner points of the trapezium, the code is posted as well Zoom (requires log in)

Collapse JASS:
local real ax = GetRandomReal(0,1)
local real ay = GetRandomReal(0,1)
local real bx = GetRandomReal(0,1)
local real by = GetRandomReal(0,1)
local real cx = 1-ax-bx
local real cy = 1-ay-by
local real a2x = GetRandomReal(0,1)
local real a2y = GetRandomReal(0,1)
local real b2x = GetRandomReal(0,1)
local real b2y = GetRandomReal(0,1)
local real c2x = 1-a2x-b2x
local real c2y = 1-a2y-b2y
local integer tri = GetRandomInt(1,2)
    loop
        exitwhen counter > 12
        if GetPlayerSlotState(Player(counter -1)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(counter - 1)) == MAP_CONTROL_USER then
            if GetLocalPlayer() == Player(counter-1) then
                //Get and set all camera data
                set camerax = GetCameraTargetPositionX()
                set cameray = GetCameraTargetPositionY()
                set rotation =  GetCameraField(CAMERA_FIELD_ROTATION)
                set distance = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
                set aoa = GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK)
                set eye = GetCameraEyePositionZ()
                set topbound = 11/distance * 180000
                set midbound = distance/11 * 6
                set lowbound = distance/11 * 5
                set highboundmodifier = 957481
                set verticalhighbound = highboundmodifier * 1/eye
                set verticallowbound = 100 *aoa 
                set base = Atan2(verticalhighbound,topbound)
                set base2 = Atan2(verticallowbound,lowbound)
                set angle = base - bj_PI/2 + rotation
                set angle2 = base + bj_PI/2 - rotation
                set angle3 = base2 - bj_PI/2 + rotation
                set angle4 = base2 + bj_PI/2 - rotation
                set dist1 = SquareRoot((topbound*topbound) + (verticalhighbound*verticalhighbound))
                set dist2 = SquareRoot((verticallowbound*verticallowbound) + (lowbound * lowbound))
                //Point at top right
                set x1 = camerax+dist1 * Cos(angle)
                set y1 = cameray +dist1 * Sin(angle)
                //Point at top left
                set x2 = camerax+dist1 * Cos(bj_PI - angle2)
                set y2 = cameray +dist1 * Sin(bj_PI - angle2)
                //Point at bottom right
                set x3 = camerax+dist2 * Cos(-angle4)
                set y3 = cameray +dist2 * Sin(-angle2)
                //Point at bottom left
                set x4 = camerax+dist2 * Cos(bj_PI + angle3)
                set y4 = cameray +dist2 * Sin(bj_PI + angle)
            endif
                if tri == 1 then
                    if GetLocalPlayer() == Player(counter-1) then
                        set x = ax * x2 + bx * x1 + cx * x3
                        set y = ay * y2 + by * y1 + cy * y3
                    endif
                else
                    if GetLocalPlayer() == Player(counter-1) then
                        set x = a2x * x2 + b2x * x3 + c2x * x4
                        set y = a2y * y2 + b2y * y3 + c2y * y4
                    endif
                endif
                loop
                    exitwhen counter2 > udg_AMHS_FogBuffer
                    if GetLocalPlayer() == Player(counter-1) then
                        if IsVisibleToPlayer(x,y,Player(counter-1)) then
                            set check = false
                        else
                            set check = true
                            set counter2 = udg_AMHS_FogBuffer + 1
                        endif
                    endif
                    set counter2 = counter2 + 1
                endloop
                if GetLocalPlayer() == Player(counter-1) then
                    //if check then
                        call PingMinimap(x,y,0.5)
                        call PingMinimapEx(x1,y1,0.5,255,0,0,false)
                        call PingMinimapEx(x2,y2,0.5,255,0,0,false)
                        call PingMinimapEx(x3,y3,0.5,255,0,0,false)
                        call PingMinimapEx(x4,y4,0.5,255,0,0,false)
                        set e = AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl",x,y)
                        call DestroyEffect(e)
                    //endif
                endif
        endif
        set counter = counter + 1
    endloop
Attached Images
File type: jpgprob2.JPG (38.1 KB)
12-11-2007, 01:35 AM#11
cohadar
Collapse JASS:
local real ax = GetRandomReal(0,1)
local real ay = GetRandomReal(0,1)
local real bx = GetRandomReal(0,1)
local real by = GetRandomReal(0,1)
local real cx = 1-ax-bx
local real cy = 1-ay-by
local real a2x = GetRandomReal(0,1)
local real a2y = GetRandomReal(0,1)
local real b2x = GetRandomReal(0,1)
local real b2y = GetRandomReal(0,1)
local real c2x = 1-a2x-b2x
local real c2y = 1-a2y-b2y

You implemented that algorithm bad.
a+b+c should be 1

EDIT: (ups)
Collapse JASS:
set a = GetRandomReal(0, 1)
set b = 1-GetRandomReal(a, 1)
set c = 1-a-b
12-11-2007, 01:47 AM#12
PandaMine
Working <3 Cohadar
12-11-2007, 01:57 AM#13
cohadar
Btw what is <3 ?
12-11-2007, 08:43 AM#14
PandaMine
Quote:
Originally Posted by cohadar
Btw what is <3 ?

Turn your head sideways and look harder

There was another problem with the method, when the trapezium was skewed (by pitching with mouse scroll) it sometimes specified an invalid point over the left hand side and the points werent as random as they should be. However when I split the trapezium into 3 triangles, (5th points was midpoint of 1st and 2nd point) then the problem stopped occuring
12-11-2007, 09:18 AM#15
cohadar
The points were "not random as they should be"
because this is not uniform distribution:
Collapse JASS:
set a = GetRandomReal(0, 1)
set b = 1-GetRandomReal(a, 1)
set c = 1-a-b

I just optimized it at the cost of absolute "randomness"

uniform distribution:
Collapse JASS:
set a = GetRandomReal(0, 1)
set b = GetRandomReal(0, 1)
if a+b > 1 then
    set a = 1 - a
    set b = 1 - b
endif
set c = 1-a-b