Jump to content
Sign in to follow this  
CarlGustaffa

Quick way to test if point is inside marker

Recommended Posts

Hi

Is there any way to quickly test if a point is located anywhere within a marker? Rectangle or ellipse at any sizes and angle.

Share this post


Link to post
Share on other sites

You can create a trigger covering the same area, and use the list command.

It should be reasonably easy to create a script function that checks the given position against the marker's position, shape, angle and area, but I don't know about you, but my maths is a bit rusty smile_o.gif

Share this post


Link to post
Share on other sites

I have code to do this for rectangular and elliptical markers which I use for a minefield script. One annoying problem is that there is no way to detect whether a marker is rectangular or elliptical (ie there is no 'markerShape' function) so you need to know in advance which function you are going to call.

For a rectangle the basic principle is to get the relative position of the point of interest from the center of the rectangle, rotate the resulting point by -1 times the angle of the rectangle, then test the x and y coordinates against the a and b dimensions of the rectangle.

For ellipses, the quickest method is to precompute the position of the two focii. Do this by calculating the distance of the focii from the center point

d= sqrt (b^2 - a^2)

The focii (F1,F2) lie at points d away from the center, in the direction the ellipse is rotated.

From then on , a point is inside the ellipse if distance from P to F1 added to distance from P to F2 is less than 2a.

I'll post code here over the weekend if you are interested.

Share this post


Link to post
Share on other sites

Yes, I thought about using triggers. But then I'd have to create an object and check its existence (?) within the trigger. Seemed a way over the top smile_o.gif

I have managed to create random points within rectangular offsetted area at an angle, but still not a way to check. I guess the maths is similar, but yeah, maths skills deterioate quickly I guess biggrin_o.gif

Naturally I have the ups, I'll check that one. Thanks for pointing this one out.

Share this post


Link to post
Share on other sites

Since I didn't know how to check the ellipse, I found out, and did it. My maths is pretty bad these days and they have not been checked for either logic or scripting mistakes, but they seem to work in my testing tounge2.gif

Two functions, one for rectangles, one for elipses (elipsii?). They return true if given position is inside the marker area, otherwise false. Feel free to do anything with these, I'm sure they could be improved upon. Example of use:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">insideMarkerR = compile preprocessFile "insideMarkerR.sqf";

_inMarker = [getPos player, "testMarker"] call insideMarkerR;

insideMarkerR.sqf

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

//returns true if given position is within the given rectangular marker

//all angles are math style, cause I'm stupid :)

//rectangle version

private ["_posi","_markerName","_markerPos","_markerSize","_markerDir","_relDist","_relAngle","_markAngle"];

//_position is a 3d position array

_posi = _this select 0;

//marker name must be a string

_markerName = _this select 1;

//3d position array

_markerPos = markerPos _markerName;

//2d array, x-radius, y-radius

_markerSize = markerSize _markerName;

//change dir to maths dir

_markerDir = 90 -(markerDir _markerName);

//distance between marker center and position

_relDist = (_markerPos distance _posi);

//check if distance is greater than 1.42 (approx sqrt 2)

if

((_relDist > (1.42*(_markerSize select 0))) && (_relDist > (1.42*(_markerSize select 1))))

exitWith

{false};

//

if

((_relDist < _markerSize select 0) && (_relDist < _markerSize select 1))

exitWith

{true};

//angle between 0 and a line between marker and posi

_relAngle = (90 - ((_posi select 0) - (_markerPos select 0)) atan2 ((_posi select 1) - (_markerPos select 1)));

if

(_relAngle > 180)

then

{_relAngle = -(360 - _relAngle)};

//angle between marker's direction and a line between marker and posi

_markAngle = 90 - (_markerDir - _relAngle);

if

(_markAngle > 180)

then

{_markAngle = -(360 - _markAngle)};

/*//sidechat feedback used in testing

player sideChat format ["rel angle is %1",_relAngle];

player sideChat format ["mark angle is %1",_markAngle];

player sideChat format ["relX is %1, relY is %2",(_relDist*(cos _markAngle)), (_relDist*(sin _markAngle))];*/

if

((abs (_relDist*(cos _markAngle)) < _markerSize select 0) && (abs (_relDist*(sin _markAngle)) < _markerSize select 1) )

exitWith

{true};

//if not inside, must be outside!

false

insideMarkerR.sqf

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

//returns true if given position is within the given eliptical marker

//all angles are math style (north = +90), cause I'm stupid :)

//elipse version

private ["_posi","_markerName","_markerPos","_markerSize","_markerDir","_relDist","_relAngle","_markAngle"];

//_position is a 3d position array

_posi = _this select 0;

//marker name must be a string

_markerName = _this select 1;

//3d position array

_markerPos = markerPos _markerName;

//2d array, x-radius, y-radius

_markerSize = markerSize _markerName;

//change dir to maths dir

_markerDir = 90 -(markerDir _markerName);

//distance between marker center and position

_relDist = (_markerPos distance _posi);

//check if distance is greater than large axis

if

(_relDist > ((_markerSize select 0) max (_markerSize select 1)))

exitWith

{false};

//check if distance is less than smaller axis

if

(_relDist < ((_markerSize select 0) min (_markerSize select 1)))

exitWith

{true};

//angle between 0 and a line between marker and posi

_relAngle = (90 - ((_posi select 0) - (_markerPos select 0)) atan2 ((_posi select 1) - (_markerPos select 1)));

if

(_relAngle > 180)

then

{_relAngle = -(360 - _relAngle)};

//angle between marker's direction and a line between marker and posi

_markAngle = 90 - (_markerDir - _relAngle);

if

(_markAngle > 180)

then

{_markAngle = -(360 - _markAngle)};

/*sidechat feedback used in testing

player sideChat format ["rel angle is %1",_relAngle];

player sideChat format ["mark angle is %1",_markAngle];

player sideChat format ["relX is %1, relY is %2",(_relDist*(cos _markAngle)), (_relDist*(sin _markAngle))];

player sideChat format["checkSum is %1", (((_relDist*(cos _markAngle))*(_relDist*(cos _markAngle)))/((_markerSize select 0)*(_markerSize select 0))) + (((_relDist*(sin _markAngle))*(_relDist*(sin _markAngle)))/((_markerSize select 1)*(_markerSize select 1)))]; */

//check if posi is in elipse. equation was found on wikipedia

if

((((_relDist*(cos _markAngle))*(_relDist*(cos _markAngle)))/((_markerSize select 0)*(_markerSize select 0))) + (((_relDist*(sin _markAngle))*(_relDist*(sin _markAngle)))/((_markerSize select 1)*(_markerSize select 1))) < 1)

exitWith

{true};

//if not inside, must be outside!

false

'love those brackets smile_o.gif

Share this post


Link to post
Share on other sites

Thanks for the reply. But I've spent most of my working day with excel today, and I came up with this. It does appear to work just from quick testing in init.sqf on the mission. Easy to rewrite for more global use though I think. Here is the result:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

sleep 0.1;

//Begin Script

_px = position player select 0;

_py = position player select 1;

_mpx = getMarkerPos "mTest" select 0;

_mpy = getMarkerPos "mTest" select 1;

_msx = getMarkerSize "mTest" select 0;

_msy = getMarkerSize "mTest" select 1;

_ma = -markerDir "mTest";

_xmin = _mpx - _msx;

_xmax = _mpx + _msx;

_ymin = _mpy - _msy;

_ymax = _mpy + _msy;

//Now, rotate point to investigate around markers center in order to check against a nonrotated marker

_rpx =  ( (_px - _mpx) * cos(_ma) ) + ( (_py - _mpy) * sin(_ma) ) + _mpx;

_rpy = (-(_px - _mpx) * sin(_ma) ) + ( (_py - _mpy) * cos(_ma) ) + _mpy;

//Now for the actual test against markersize.

hint format ["px %1\npy %2\nmpx %3\nmpy %4\nmsx %5\nmsy %6\nma %7\nxmin %8\nxmax %9\nymin %10\nymax %11\nrpx %12\nrpy %13", _px, _py, _mpx, _mpy, _msx, _msy, _ma, _xmin, _xmax, _ymin, _ymax, _rpx, _rpy];

if (((_rpx > _xmin) && (_rpx < _xmax)) && ((_rpy > _ymin) && (_rpy < _ymax))) then

{

   player globalChat "player inside marker";

}

else

{

   player globalChat "player outside marker";

};

//End of Script

And here is the end of the script but for elliptical markers, after rotated points _rpx and _rpy has been calculated:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

_res = (((_rpx-_mpx)^2)/(_msx^2)) + (((_rpy-_mpy)^2)/(_msy^2));

if ( _res < 1 ) then

{

player globalChat "player inside marker";

}

else

{

player globalChat "player outside marker";

};

Not quite sure how much parantheses is really needed.

Share this post


Link to post
Share on other sites

I've written this into function form. Maybe someone could test if it works properly? Does *seem* to work for me though. Have included enough comments for newbies to understand what is going on.

The point of it all is to check if a point; object or an icon  marker, lies inside a rectangular or elliptical area marker of any size and angle. In order to reduce the complexity of the angle maths, I rotate the point to inventigate the oposite amount of degrees the marker is rotated, about the markers center point. I needed this because I need No-Fire-Zones for certain types of munitions for my artillery in my mission, and these zones are marked with, well, area markers biggrin_o.gif

The function:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

// call with check = ["markerpoint", "markertocheckagainst", "type"] call markerCheck; for markers

// call with check = [object, "markertocheckagainst", "type"] call markerCheck; for objects

// object is an object, i.e. player or uTankNumber3. "markerpoint" can be used for automatically generated markers, such as "mTargetMarker"

// "markertocheckagainst" is the name of the marker as a string that is the area you want to check against.

// Type is a string indicating "R" or "E" to enable rectangular or elliptical checks respectively.

//variables needs to be set private for function to work

private ["_p","_m", "_t", "_px", "_py", "_mpx", "_mpy", "_msx", "_msy", "_rpx", "_rpy", "_xmin", "_xmax", "_ymin", "_ymax", "_ma", "_res", "_ret"];

//description of variable names

//_p    point to investigate, typically an object or marker with a position

//_m    marker to check against

//_t    marker type, string "R" or "E" for rectangular or elliptical markers respectively

//_px   x value of point

//_py   y value of point

//_mpx  markerpos x

//_mpy  markerpos y

//_msx  markersize x

//_msy  markersize y

//_rpx  rotated position point x

//_rpy  rotated position point y

//_xmin minimum point x in a rectangular marker

//_xmax maximum point x in a rectangular marker

//_ymin minimum point y in a rectangular marker

//_ymax maximum point y in a rectangular marker

//_ma   marker angle

//_res  result carrier in elliptic marker

//_ret  return value

_p = _this select 0; //object

_m = _this select 1; //always a marker

_t = _this select 2; //marker shape, "E" or "R"

if (typeName _p == "OBJECT") then

{

   _px = position _p select 0;

   _py = position _p select 1;

}

else

{

   _px = getMarkerPos _p select 0;

   _py = getMarkerPos _p select 1;

};

_mpx = getMarkerPos _m select 0;

_mpy = getMarkerPos _m select 1;

_msx = getMarkerSize _m select 0;

_msy = getMarkerSize _m select 1;

_ma = -markerDir _m;

_rpx = ( (_px - _mpx) * cos(_ma) ) + ( (_py - _mpy) * sin(_ma) ) + _mpx;

_rpy = (-(_px - _mpx) * sin(_ma) ) + ( (_py - _mpy) * cos(_ma) ) + _mpy;

if (_t == "R") then

{

   _xmin = _mpx - _msx;

   _xmax = _mpx + _msx;

   _ymin = _mpy - _msy;

   _ymax = _mpy + _msy;

   if (((_rpx > _xmin) && (_rpx < _xmax)) && ((_rpy > _ymin) && (_rpy < _ymax))) then

   {

       _ret=true;

   }

   else

   {

       _ret=false;

   };

}

else

{

   _res = (((_rpx-_mpx)^2)/(_msx^2)) + (((_rpy-_mpy)^2)/(_msy^2));

   if ( _res < 1 ) then

   {

       _ret=true;

   }

   else

   {

       _ret=false;

   };

};

_ret;

In the init.sqf:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

markerCheck = compile preprocessFile "checkinsidemarker.sqf";

Check with following:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

check = ["mTest", "mR001_AB", "E"] call markerCheck; //check if marker lies inside an elliptical marker called mR001_AB

check = [player, "mR001_AB", "R"] call markerCheck; //check if player lies inside a rectangular marker called mR001_AB

Function returns true or false. Yippi, my first ever function  yay.gif

Share this post


Link to post
Share on other sites

I know that this thread is very old but it's still relevant and Nr. 1 displayed in google :)

The above code snippets can't be read and are outdated. Here a new improved version of it:

  // call with check = ["markerpoint", "markertocheckagainst"] call fnc_isInMarker; for markers
 // call with check = [object, "markertocheckagainst"] call fnc_isInMarker; for objects
 fnc_isInMarker = {
   private ["_p","_m", "_px", "_py", "_mpx", "_mpy", "_msx", "_msy", "_rpx", "_rpy", "_xmin", "_xmax", "_ymin", "_ymax", "_ma", "_res", "_ret"];

   _p = _this select 0; // object
   _m = _this select 1; // marker

   if (typeName _p == "OBJECT") then {
     _px = position _p select 0;
     _py = position _p select 1;
   } else {
     _px = getMarkerPos _p select 0;
     _py = getMarkerPos _p select 1;
   };

   _mpx = getMarkerPos _m select 0;
   _mpy = getMarkerPos _m select 1;
   _msx = getMarkerSize _m select 0;
   _msy = getMarkerSize _m select 1;
   _ma = -markerDir _m;
   _rpx = ( (_px - _mpx) * cos(_ma) ) + ( (_py - _mpy) * sin(_ma) ) + _mpx;
   _rpy = (-(_px - _mpx) * sin(_ma) ) + ( (_py - _mpy) * cos(_ma) ) + _mpy;
   if ((markerShape _m) == "RECTANGLE") then {
     _xmin = _mpx - _msx;_xmax = _mpx + _msx;_ymin = _mpy - _msy;_ymax = _mpy + _msy;
     if (((_rpx > _xmin) && (_rpx < _xmax)) && ((_rpy > _ymin) && (_rpy < _ymax))) then { _ret=true; } else { _ret=false; };
   } else {
     _res = (((_rpx-_mpx)^2)/(_msx^2)) + (((_rpy-_mpy)^2)/(_msy^2));
     if ( _res < 1 ) then{ _ret=true; }else{ _ret=false; };
   };
   _ret;
 };

Cheers and happy X-Mas

Edited by Armitxes

Share this post


Link to post
Share on other sites

Here's a quick method using locations (call as func):

private ["_pos","_mark","_inside","_shape","_loc"];
_pos = _this select 0; _mark = _this select 1;
_inside = false;
_shape = markerShape _mark;
if (! (_shape == "ICON")) then {
_loc = createLocation (["Name", markerPos _mark] + (markerSize _mark));
if (_shape == "RECTANGLE") then { _loc setRectangular true };
_loc setDirection (markerDir _mark);
if (_pos in _loc) then { _inside = true };
deleteLocation _loc;
};
_inside

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×