POV-Ray : Newsgroups : povray.off-topic : Math question (inside box) : Re: Math question (inside box) Server Time
28 Jul 2024 16:29:25 EDT (-0400)
  Re: Math question (inside box)  
From: Patrick Elliott
Date: 5 Aug 2013 05:15:48
Message: <51ff6d44$1@news.povray.org>
On 8/5/2013 12:52 AM, Le_Forgeron wrote:
> Le 04/08/2013 23:50, Patrick Elliott a écrit :
>> Hunted around on the net and found something for 2D, but I think I got
>> something wrong trying to do the 3D. Actually, I am semi-sure I know
>> what I screwed up, but not how to fix it. lol But, I figured I would
>> maybe, instead, ask here instead, on the chance there is a better solution.
>>
>> Basically though, I have an object, its position, and its rotation, and
>> I want to create a "test box" in which to work out where someone is, but
>> I want it to still work, regardless of whether or not the object is say,
>> rotated 35 degrees in all directions, placing my "test box" some place
>> other than at nice 90 angles from the normal axis.
>
> Why would you want to handle such box, when the interest of such code is
> precisely to reduce the workload by looking only at the axes.
>
>
Yeah, well. I kind of thought maybe there was some way that I just 
wasn't seeing.

>>
>> Now the method I had tried was:
>>
>> main(){
>> integer left = 0;
>> integer right = 2;
>> integer length = 5;
>> integer top = 1.5;
>> integer bottom = 1.5;
>>
>> //Assuming that the "front" is in the Y direction.
>>   integer boxlen = llGetScale().y / 2;
>>   vector bbox1 = <pos.x - left, pos.y + boxlen, pos.z - bottom>;
>>   vector bbox2 = <pos.x + right, pos.y + boxlen, pos.z + top>;
>>   vector bbox3 = <pos.x - left, pos.y + boxlen + length, pos.z - bottom>;
>>   vector bbox4 = <pos.x - right, pos.y + boxlen + length, pos.z + top>;
>>   if (isInsideBox(bbox1, bbox2, bbox3, bbox4))
>>     //do other stuff, or, else, the stuff you do if they are "not" in the
>> box.
>> }
>>
>> integer triangleArea(vector A, vector B, vector C)
>> {
>>    //This is where I am screwing up.. I need to test A.z, B.z and C.z,
>>    //for one of the planes, but I am testing x and y in both cases, which
>>    //won't work.
>>    return(C.x*B.y-B.x*C.y)-(C.x*A.y-A.x*C.y)+(B.x*A.y-A.x*B.y);
>> }
>>
>> integer isInsideSquare(vector A, vector B, vector C, vector D, vector P)
>> {
>>    if(triangleArea(A,B,P)>0 || triangleArea(B,C,P)>0 ||
>> triangleArea(C,D,P)>0 || triangleArea(D,A,P)>0)
>>        return FALSE;
>>      else
>>        return TRUE;
>> }
>>
>
> Did you understand how it is supposed to work in 2D ? I mean the
> previous two functions are using oriented triangles and area computation
> (signed result) to know if P is inside ABCD.
>
> When P is inside ABCD, ABP, BCP, CDP, DAP all have the same sign for
> their area. As soon as P is outside the square, one area at least has a
> negative result.
>
> The nice thing about it is that the four points A,B,C & D only need to
> be ordered in the rotating order and can be anywhere in the plane (it
> does not have to be an axis-aligned square).
>
> But it only works in 2D.
>
Umm. Not sure how to explain this, but, yeah, I did. I just.. screwed up 
on the coordinates. lol Umm. Let me put it this way. You are looking at 
two boxes one is laying flat, along the XY, the other is lying flat on 
the XZ (or the YZ, which I don't think necessarily matters). So.. in one 
case if the location of the thing being tested was <1,2,3>, then P 
"should be" <1,2>, and for the other plane, it should be <1,3>, with the 
corners of the two boxes, on those planes, taken from the XY, or the XZ, 
as needed.

Or, that was what I envisioned in my own head. lol Obviously, I screwed 
up from the very start.

>
>> integer isInsideBox(vector bbox1, vector bbox2, vector bbox3, vector bbox4)
>> {
>>    vector P = llDectectedPos(0);
>>    vector A1 = <bbox1.x,bbox2.y,bbox1.z>;
>>    vector B1 = <bbox2.x,bbox2.y,bbox1.z>;
>>    vector C1 = <bbox2.x,bbox1.y,bbox1.z>;
>>    vector D1 = <bbox1.x,bbox1.y,bbox1.z>;
>
>>    vector A2 = <bbox3.x,bbox4.y,bbox3.z>;
>>    vector B2 = <bbox4.x,bbox4.y,bbox3.z>;
>>    vector C2 = <bbox4.x,bbox3.y,bbox3.z>;
>>    vector D2 = <bbox3.x,bbox3.y,bbox3.z>;
>
>>    return (isIntegerSquare(A1, B1, C1, D1, P) & isIntegerSquare(A2, B2,
>> C2, D2));
>> }
>>
>
> I do not understand the expectation here. You seems to transform the box
> as two parallel to Z plane squares (axis-aligned), and then check if the
> projection of P is inside the projections of both these squares.
>
> There is plenty of situations where it will provide false positives, as
> well as false negatives.
>
Yeah, as I said, I fowled up. In actuality, what happens, due to the 
code being wrong, is that P is *never* inside the box.

>>
>> I am 99% sure that what I failed to think about is that since one of the
>> "sides" is vertical, I am testing its x and y in both cases, and thus,
>> stupidly, not testing the z. Otherwise, the code works, supposedly,
>> because, if your test point isn't "inside the box", one or more of the
>> area calculations will end up with a negative sign.
>
> signed area calculation is only good for 2D. The extension in 3D would
> need to compute the volume of a pyramid (with a triangle base) and the
> maths are not to be friendly
>
No doubt.

>>
>> In any case, I need to redo the code, if I want to do this, and simplify
>> things a lot at well.
>>
>> But, what I was wondering is.. is there some other way to do this? Some
>> way that takes into account the rotation, and what amounts to a sort of
>> "is this inside of the bounding box" calculation, without having to
>> rotation/unrotate various things, to get the same result? Because, as
>> things stand, either I need to reposition the object I am testing, or I
>> need to reposition the corner of my invisible box, which I am testing
>> for them to be in. And, while one is less annoying than the other.. they
>> are still both annoying. lol
>
> If you do not intend to limit yourself to a axis-aligned box, why not
> instead use a sphere ?
>
The reason is that I need the specific shape. Ok, I will attach an 
example. There is a safe, against a wall, and a counter, which is green, 
the transparent box is the "valid" area for someone to be able to access 
the safe, with the guy inside it being "allowed", and the two "red" 
figures not. There is no way to use a sphere, without detecting as 
"valid" people standing in the wrong places. Its the precise reason why 
I didn't just use the simpler method of figuring out, "Is this person 
standing in the +X direction, and within N meters of the object. That 
method would have failed to detect people, in the safe where, instead, a 
garage door, for example, if they stood at the "edge" of the door, since 
they might not be "close enough", without making the detection range 
much larger than I wanted (i.e., a 15 meter door, should detect 5 meters 
"in front of" the door, no matter where on the door, but since is using 
"center of the door", it would fail to detect someone standing against 
it, but 7 meters from the center).

However... I occurs to me that I might be able to use one plane, and a 
distance.. So, as long as the position was rotated, to match a plane 
that is align to XY (or, actually, due to how the world works, XZ), then 
I can test if its in "that" box, and then merely do:

float dist = llVecDist(llGetPos(), P);
if (dist < maxdist & dist > mindist)
{
   //Rest of the code.
}

Thus, only testing "one" box, and only on that single plane.

Then again, I screwed up the last idea so badly... lol


Post a reply to this message


Attachments:
Download 'example.png' (22 KB)

Preview of image 'example.png'
example.png


 

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.