POV-Ray : Newsgroups : povray.off-topic : Math question (inside box) : Re: Math question (inside box) Server Time
28 Jul 2024 16:30:50 EDT (-0400)
  Re: Math question (inside box)  
From: Le Forgeron
Date: 5 Aug 2013 03:52:55
Message: <51ff59d7$1@news.povray.org>
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.


> 
> 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.


> 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.

> 
> 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

> 
> 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 ?

you transform only 1 point (the center)(if you only have rotation and
translation), and then just compute the distance of the center to P (to
compare against the radius). And to avoid slow squared root, compare the
squared distance (euclidian) to the squared radius.

If you have more than rotation & translation (such as scaling and
shearing), you might need to transform the radius too (at which point,
it's better to consider 1 center and the 8 corners of the box, to
finally only kept as radius the distance from the center to the most
faraway corner)
(the box is originally the box that encloses the minimal sphere. at the
end, the radius is the radius of the sphere that encloses the
transformed box. Thus, it is bigger than the strict covering sphere, but
it is safe)

-- 
Just because nobody complains does not mean all parachutes are perfect.


Post a reply to this message

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