Jump to content

Has my hoopla ring landed on a post?


Anton Catesby
 Share

You are about to reply to a thread that has been inactive for 473 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

How do I calculate this, please?   If the hoop is lying flat on the ground it's easy enough -- just calculate if the distance between the hoop's centre and that of the post at the ring's z coordinate is < the ring's radius -- but what if it's at an angle?   If the hoop is leaning against the post, the distance will (generally?) be less than the radius, but obviously it's not landed over the post.

I've tried translating the hoop's position by every permutation of rotations I can think of, but nothing seems to work, and I'm having difficulty conceptualising what I'm trying to calculate.   

I've also tried calling llCastRay repeatedly.  It seems to work,  but that's a horrible way to do it:

rotation r1;
rotation rStart = ZERO_ROTATION;
default
{
    state_entry()
    {
        r1 = llEuler2Rot(<1.0,0.0,0.0>*DEG_TO_RAD);
    }

    touch_end(integer num_detected)
    {
        llResetTime();

        integer iCounter =0;
        integer iMax = 360;

        vector vSize = llGetScale();
        vector vPos = llGetPos();
        rotation rRot = llGetRot();

        list lTemp;
        vector v = <0.0,(vSize.y*0.94)*0.5,0.0>;
        do{
            lTemp = llCastRay(vPos+v*rStart*rRot,vPos,[RC_MAX_HITS,2]);
            if(llList2Integer(lTemp, -1)>0){
            	lTemp = llDeleteSubList(lTemp,-1,-1);
            	list lKeys = llList2ListStrided(lTemp,0,-1,2);
            	integer max = -llGetListLength(lKeys);
            	do{
	        		key k = llList2Key(lKeys,max);
	        		if(k!=llGetKey()){
	        			llOwnerSay(llKey2Name(k));
	        		}
	            }
	            while(++max);
	        }
            rStart*=r1;    
        }
        while(++iCounter<iMax);
        llOwnerSay((string)llGetTime());
    }
}

Can anyone help me, please?

 

 

Edited by Anton Catesby
Link to comment
Share on other sites

I am imagining the problem in two dimensions. If a ring is touching the top of the post and the side of the post, it is making an acute angle, one side of which is the plane of the ring and the other of which is the center of the post. If you know the diameter of the ring and of the post, you should be able to calculate that angle easily. Now, if the ring is touching the top of the post and at (or really close to) that angle, it must be leaning.  So, is it touching the top of the post?  You know the height of the post, so compare it to the height of the leaning ring( the Z component of  llGetPos() ). Even with a bit of slop, you can tell whether it is both leaning and touching the top of the post. 

I know there's a little bit of uncertainty in my analysis, because I assume that the ring is touching the center of the top of the post.  Still, unless you have a really fat post, if the ring is slightly toward one side or the other of the top, the leaning angle ought to be pretty close to what I have suggested.  Close enough for any carny manager to yell "LEANING!" and disqualify the toss.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

There might be better ways of going about it, but I think this works as an example:

key post = "881a86be-f4a9-3faa-9b5d-bd828fc3ea08";
float RADIUS = 0.8;
default
{   state_entry()
    {   llSensorRepeat("",post,PASSIVE,5.0,PI,5.0);
    }

    sensor(integer n)
    {   vector posPost = llDetectedPos(0);
        vector posSelf = llGetPos();
        vector vDiff = posPost-posSelf;
        
        // if the post is more than radius away, it is definitely too far.
        if(llVecMag(vDiff)>RADIUS)
        {   llOwnerSay("Off (too far)");
            return;
        }
        rotation rotSelf = llGetRot();
        vector vNorm = llRot2Up(rotSelf); // z-axis. // a prim-torus would use the x-axis: llRot2Fwd(rotSelf);
        vector vLeft = vNorm%vDiff;
        vector vTarget = vLeft%vNorm; // vector pointing at the post, lying on the plane normal to the ring's z-axis.
     
        vDiff.z = 0; // ignore height difference: assume the post is infinitely tall.
        float theta = llRot2Angle(llRotBetween(vTarget,vDiff)); 
        float distFlat = llVecMag(vDiff);
        float distHyp = distFlat/llCos(theta);
        
        if(distHyp<RADIUS)
        {   llOwnerSay("On");
        }else
        {   llOwnerSay("Off");
        }
    }
}

I had a partial solution when @Rolig Loon posted and I realized I had made a minor mistake, and used her idea about the angle to fix it. There might be a way to do it with a bit less trig.

Edited by Quistess Alpha
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

I think we converged on similar paths. In the end, there's enough slop in things that the trig doesn't have to be spot on. In fact, I suspect that you can make the simplifying assumption that if the ring is not moving and is more than a ring diameter above the ground, it must be somehow hung up on the top of the pole.  If its center is less than half a ring radius from the pole and it is closer to the bottom of the pole than the top, it must be leaning. If you make those assumptions, then you can toss the trig out completely.

Edited by Rolig Loon
typos. as always.
  • Like 1
Link to comment
Share on other sites

Actually, no simplifying assumption: if the projection of llVecNorm(vTarget)*RADIUS onto the x,y plane is longer than the projection of the vector to the pole, then the ring is over the pole.

// same up to this line:
vector vTarget = vLeft%vNorm; // vector pointing at the post, lying on the plane normal to the ring's z-axis.

vTarget=llVecNorm(vTarget)*RADIUS; // set the length of the vector to the radius of the ring.
vTarget.z=0;
vDiff.z=0;
if(vTarget*vTarget > vDiff*vDiff) // vector*itself == its magnitude squared.
{   llOwnerSay("on");
}else
{   llOwnerSay("off");
}

/me goes back in-world to check. . . then adds a missing llVecNorm().

Edited by Quistess Alpha
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Thanks, @Rolig Loon and @Quistess Alpha

Unfortunately, while this solution works most of the time, I'm getting false positives when the hoop is right up against the post -- for example:

c18a3292d9ff144bfdd5e348da56298b.png

 

This is the script I'm using (the radius is half the diameter, as measured with a prim):

float RADIUS = 0.222;
default
{   


    touch_end(integer num_detected)
    {
        llSensor("My Post","",PASSIVE,5.0,PI);
    }

    sensor(integer n)
    {   vector posPost = llDetectedPos(0);
        vector posSelf = llGetPos();

        posPost.z = posSelf.z;
        vector vDiff = posPost-posSelf;
        
        // if the post is more than radius away, it is definitely too far.
        if(llVecMag(vDiff)>RADIUS)
        {   llOwnerSay("Off (too far)");
            return;
        }
        rotation rotSelf = llGetRot();
        vector vNorm = llRot2Fwd(rotSelf); // z-axis. // a prim-torus would use the x-axis: llRot2Fwd(rotSelf);
        vector vLeft = vNorm%vDiff;
        // same up to this line:
        vector vTarget = vLeft%vNorm; // vector pointing at the post, lying on the plane normal to the ring's z-axis.

        vTarget=llVecNorm(vTarget)*RADIUS; // set the length of the vector to the radius of the ring.
        vTarget.z=0;
        vDiff.z=0;
            llOwnerSay("vTarget: "+(string)vTarget+", vDiff: "+(string)vDiff);
            llOwnerSay("vTarget*vTarget is "+(string)(vTarget*vTarget));
            llOwnerSay("vDiff*vDiff is "+(string)(vDiff*vDiff));
        if(vTarget*vTarget > vDiff*vDiff) // vector*itself == its magnitude squared.
        {   llOwnerSay("on");
        }else
        {   llOwnerSay("off");
        }
    }
}

and this is what it's saying:
 

vTarget: <-0.03092, 0.14075, 0.00000>, vDiff: <-0.11945, 0.03651, 0.00000>
[16:45] Object: vTarget*vTarget is 0.020767
[16:45] Object: vDiff*vDiff is 0.015601
[16:45] Object: on

I'd be very grateful for any suggestions.

Edited by Anton Catesby
Link to comment
Share on other sites

Adding some vector visualizations helped me figure out an interesting 3-d error I had been making. for my own edification I might try figuring out a more 'correct' solution, but an easy hack is

posPost.z = posSelf.z+RADIUS;

on line 14. ETA: that can give you some false negatives though.

A pretty rough-and-ready vector visualizer to put in a 1-1 taper, 0.5,1.0 slice cylinder:

default
{   state_entry()
    {   llListen(46,"","","");
    }
    listen(integer Channel, string Name, key ID, string Text)
    {   llSetPos(llList2Vector(llGetObjectDetails(ID,[OBJECT_POS]),0));
        vector v = (vector)Text;
        llSetRot(llRotBetween(<0,0,1>,(vector)Text));
        llSetScale(<0.05,0.05,2*llVecMag(v)>);
    }
}

 

Edited by Quistess Alpha
  • Thanks 1
Link to comment
Share on other sites

More, better math! TL;DR; find the line from the center of the hoop, that passes through its edge (lies along the plane of the circle) and also touches the (hypothetical, infinitely tall) post. if that line is longer than the radius of the hoop, the hoop is not 'on' the post.

float RADIUS = 0.222;
default
{   state_entry()
    {   RADIUS = RADIUS*RADIUS; // computation enhancement.
    }
    touch_end(integer num_detected)
    {   llSensor("My Post","",PASSIVE,5.0,PI);
    }
    sensor(integer n)
    {   vector posPost = llDetectedPos(0);
        vector posSelf = llGetPos();

        vector vDiff = posPost-posSelf;
        vector vNorm = llRot2Fwd(llGetRot()); // assuming a torus prim.
        vDiff.z = (-(vNorm.x*vDiff.x)-(vNorm.y*vDiff.y) )/vNorm.z; // solve vNorm*vDiff == 0 (perpendicularity condition) for vDiff.z
        llSay(45,(string)vDiff); // optionally send a message to a 'vector visualizer' for sanity check.
        
        if(vDiff*vDiff < RADIUS)
        {   llOwnerSay("On");
        }else
        {   llOwnerSay("Off");
        }
    }
}

ETA: Depending on your use-case, you could also check the difference between vDiff.z before the re-calculation and after. if the hoop is otherwise "on" the post, but vDiff.z increases by more than the distance from the center of the pole to the top (half its height) then the hoop is probably 'too high up'. A normal distance check would probably work just as well in practice though.

Edited by Quistess Alpha
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

4 hours ago, Quistess Alpha said:

find the line from the center of the hoop, that passes through its edge (lies along the plane of the circle) and also touches the (hypothetical, infinitely tall) post

Nice. That's a tidy way of expressing what I've been supposing to be the definition of the problem: does the intersection of the post's line with the hoop's plane fall within the hoop circle? (I'm far too lazy to even try to get that math right myself, though.)

  • Like 2
Link to comment
Share on other sites

I'd do something silly like trying to sense if anything named "post" was within a phantom prim inside the ring, but then I'm probably thinking like a n00b. If it was that simple, it would have been solved already, probably.

I'd test it inworld, but that would involve doing more than hovering and staring at the build. And I'd probably just feel foolish, anyway. Ah yes, now it dawns on me: can't make one prim phantom and the other physical. It would have to be a flexi, and it would be a nightmare trying to keep it from flopping around.

This thread is fascinating, though. I really enjoy getting to see other people's problem solving skills unfold in front of me. It proves that people think, and that utterly thrills me. Yeah, I'm pretty easy to please. XD

Edit: I'm stubborn so I tried it anyway. A flexi disc (cylinder at 0.01 thick on z) linked to a physical ring stayed phantom despite the ring being solid, as I suspected was going to happen because I can stick flapping bits on moving objects. The ring, once over the post however, quivers, shimmies, and then hops like a frog off of the pole. Maybe it's because I used a torus, or something. Oh well, at least I satisfied my curiosity. I'll be watching this one for an answer, this is exciting.

Edited by PheebyKatz
  • Like 1
Link to comment
Share on other sites

7 hours ago, Qie Niangao said:

I'm far too lazy to even try to get that math right myself, though.

The post being parallel to the z axis means it's a single equation in one (easy to extract) variable, if the post were at an arbitrary angle. . . the vector math might get a bit annoying.

roughly, solve for scalar (float) 'S':

vNormSelf*((S*vAxisPole)+vPosPole) == 0; // after expanding definitions, will be a single equation in a single unknown.

where vNormSelf is the normal to the hoop, vAxisPole is the long dimension of the post, vPosPole is (the position of the pole - the position of the hoop).

then ((S*vAxisPole)+vPosPole) would be the vector who's length gets checked against the radius.

ETA: actually, dot product is distributive and associates with scalar multiplication, so it's not too bad:

  • vNormSelf*((S*vAxisPole)+vPosPole) == 0;
  • S*vNormSelf*vAxisPole + vNormSellf*vPosPole == 0;
  • S = -((vNormSelf*vPosPole)/(vNormSelf*vAxisPole));
  • (I don't think vector division is a thing, so can't factor out vNormSelf)
Edited by Quistess Alpha
  • Like 2
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 473 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...