Rolig Loon

A Bi-Swing Door that opens Away from you

12 posts in this topic

Builders sometimes ask for a door that will open away from you as you approach it -- think of a bi-swing door in a restaurant kitchen, for example.  There are several ways to write a script to detect where an av is, relative to a door or wall.  This script does it by locating the av relative to the door's "default" direction of swing, defined in its WhereAmI function. (The math is a little tricky, but it's worth studying as a problem in SL rotations and matrix algebra.)  As noted in embedded comments, you can use the script in a linked or a freestanding door.  If the door is in a linkset, just be sure that it is a child link and that the script is in the door itself.  As written, the door rotates on its Z axis and will determine for itself whether its X dimension is larger or smaller than the Y. Other possible geometries are left as a challenge for the reader.

Casual note: Scripters will recognize a genetic relationship to Void Singer's Simple Hinge Action script, which remains the most basic door script in SL. Some things are hard to beat.

// Open Other Way -- Rolig Loon -- April 2017

// This script always opens a door away from the person who touches it, then closes the door later automatically .

// The script may be used in a linked or unlinked door, but must be placed in the door itself. If the door is linked, it must be a child link.
// It was designed for a prim "cut" door (B:0.125, E:0.625 or B;0.375, E:0.875) but could be used for a mesh door hinged on one side.
// The script will detect whether the door's X dimension is larger or smaller than its Y dimension and adjust accordingly.
// When it is installed for the first time, be sure that the door is in its CLOSED rotation. NOTE: This is its LOCAL rotation, relative
//      to the root of the linkset, so it will not be affected if you move the entire linkset later.

// User parameters ===========

integer gIntSwing = 90; // Angular swing of the door, in degrees
float gfOpenTime = 5.0; // Amount of time before the door closes automatically, in seconds

// ===== Do not mess with anything below here unless you know what you are doing ============

rotation gHomeRot;
float gfHomeAngle;
integer giXisBigger;
rotation gRotSwing;
integer gDir;

integer IsClosed(rotation MyRot)    // Is the door closed?
{
    float MyAngle = llRot2Angle(MyRot);
    if (llFabs(MyAngle - gfHomeAngle) < 0.0523599) // Within 3 degrees of "closed"
    {
        llSetLocalRot(gHomeRot);    // Be sure it's closed now, just in case
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

integer WhereAmI (vector AvPos) // Where is the av, relative to the door's default swing direction?
{
    float dotP = llRot2Fwd(gHomeRot)*llVecNorm((AvPos - llGetPos())/llGetRot()- llGetLocalPos());
    if (giXisBigger)    // The door's X dimension is bigger than its Y dimension
    {
        return (RAD_TO_DEG*llAcos(dotP) < 90.0) ;   // TRUE or FALSE?
    }
    else    // The door's Y dimension is bigger than its X dimension 
    {
        return (RAD_TO_DEG*llAcos(dotP) > 90.0) ;   // TRUE or FALSE?
    }        
}

default
{
    state_entry()
    {
        // First, define the "closed" rotation for the door
        gHomeRot = llGetLocalRot();
        gfHomeAngle = llRot2Angle(gHomeRot);
        vector Size = llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_SIZE]),0);
        giXisBigger = (Size.x > Size.y);
        // and now, here's the default rotation to apply in swinging the door ....
        gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD> );
    }
    
    touch_end( integer mum )
    {
        if ( IsClosed(llGetLocalRot()) )  //If the door is closed ...
        {
            gDir = 0;        
            if ( WhereAmI(llDetectedPos(0)) ) // Where is the av, relative to the door's default swing direction?
            {
                gDir = 1;
                // Reverse the door's default opening direction
                gRotSwing.s *= -1;
            }
            llSetLocalRot( gRotSwing * llGetLocalRot() ); 
            gRotSwing.s *= -1;  // And reverse direction again, ready for the return swing
            llSetTimerEvent(gfOpenTime);         
        }
    }
    
    timer()
    {
        // Now reverse the direction of gRotSwing and apply it....
        llSetLocalRot( gRotSwing * llGetLocalRot() );
        if (!gDir)  // If the door just opened in the default direction, we don't need to reverse it yet again
        {
            gRotSwing.s *= -1;
        }
        llSetTimerEvent(0.0); 
    }
}

 

4 people like this

Share this post


Link to post
Share on other sites

I'm not sure what I'm doing wrong. I didn't change anything in this script. I just installed it in my closed door. I tested it by clicking, walking through, letting it close. Then clicking it again. It opens in the same direction no matter which side of the door I'm on

Share this post


Link to post
Share on other sites

@Ruthven Willenov  I am not a script writer (only a tinkerer) but every door I have acts that way. If you THINK about it, the real life doors do too. The ONLY open in one direction *wink*. 

Share this post


Link to post
Share on other sites
Just now, Chic Aeon said:

@Ruthven Willenov  I am not a script writer (only a tinkerer) but every door I have acts that way. If you THINK about it, the real life doors do too. The ONLY open in one direction *wink*. 

The point of this one is that it is supposed to be bi-swing, a door that swings in both directions, as mentioned in the description above. A bar/saloon door, or a restaurant kitchen door for examples

Share this post


Link to post
Share on other sites

Ah OK. Sorry. Too late :D. When I have seen those they swung to and fro but they still didn't change direction. Rolig will answer your question when she is on no doubt. Good luck.

Share this post


Link to post
Share on other sites

I'm on vacation far from home, so I can't log in to SL from a motel's Internet connection to see exactly what you are doing.  My best guess, though, is that your door is not hinged where the script expects it to be.  With a cut prim door, there are two possible choices, as the notes indicate.  The door is either flattened on its X axis or its Y axis, and the hinge is always its Z axis.  The script can distinguish between those two possibilities.  It can't guess correctly if you have a door built some other way, as a mesh door might be.

Also, once you get your door set up, be sure that the door is closed and then reset the script so that it knows what "closed" means.

Share this post


Link to post
Share on other sites

Yep, I used it on both. I also put in an owner say to see what WhereAmI was returning. Unlinked, it was always returning 0. Linked (yes as a child), is was always returning 1

Share this post


Link to post
Share on other sites

That's odd.  Until I am back in the land of reliable Internet, I can only speculate, and I'm not speculating well so far.

Share this post


Link to post
Share on other sites

Posted (edited)

I figured out another solution by reversing the logic in this comment 

what I have now is:

integer isFacing(vector avpos)
{
    vector myPos = llGetPos();
    rotation myRot = llGetRot();
    vector facing;
    vector target = llVecNorm( avpos - myPos);
    float dp;
    if(giXisBigger)
    {
        facing = llRot2Left(myRot);
        dp = facing*target;
    }
    else
    {
        facing = llRot2Fwd( myRot);
        dp = -(facing*target);//had to reverse the dp when Y axis is bigger to make door swing the right direction
    }
    return ( dp > 0 );
}

and I use it in place of WhereAmI

Edited by Ruthven Willenov
cleaned up the math and if logic a bit

Share this post


Link to post
Share on other sites

Well, that's certainly simpler than my math, although I think the two should be equivalent. Dora and I seem to be using the same approach.  The bottom line, though, is that if the simpler math works, use it!  Simpler is always preferable.  Thanks, @Ruthven Willenov

Share this post


Link to post
Share on other sites

I wanted to play with slowing down the rotation so it looked more realistic than just snapping into open/close position. So I added in a steps variable, divided the rotation by that number of steps, and added a for loop to handle the stepped rotation. I may play with a target omega version

// Open Other Way -- Rolig Loon -- April 2017

// This script always opens a door away from the person who touches it, then closes the door later automatically .

// The script may be used in a linked or unlinked door, but must be placed in the door itself. If the door is linked, it must be a child link.
// It was designed for a prim "cut" door (B:0.125, E:0.625 or B;0.375, E:0.875) but could be used for a mesh door hinged on one side.
// The script will detect whether the door's X dimension is larger or smaller than its Y dimension and adjust accordingly.
// When it is installed for the first time, be sure that the door is in its CLOSED rotation. NOTE: This is its LOCAL rotation, relative
//      to the root of the linkset, so it will not be affected if you move the entire linkset later.

// User parameters ===========

integer gIntSwing = 90; // Angular swing of the door, in degrees
float gfOpenTime = 5.0; // Amount of time before the door closes automatically, in seconds

// ===== Do not mess with anything below here unless you know what you are doing ============

integer steps = 6;//How many steps it will take to open/close the door to give a more realistic swinging action
integer isFacing(vector avpos)
{
    vector myPos = llGetPos();
    rotation myRot = llGetRot();
    vector facing;
    vector target = llVecNorm( avpos - myPos);
    float dp;
    if(giXisBigger)
    {
        facing = llRot2Left(myRot);
        dp = facing*target;
    }
    else
    {
        facing = llRot2Fwd( myRot);
        dp = -(facing*target);//had to reverse the dp when Y axis is bigger to make door swing the right direction
    }
    return ( dp > 0 );
}

rotation gHomeRot;
float gfHomeAngle;
integer giXisBigger;
rotation gRotSwing;
integer gDir;

integer IsClosed(rotation MyRot)    // Is the door closed?
{
    float MyAngle = llRot2Angle(MyRot);
    if (llFabs(MyAngle - gfHomeAngle) < 0.0523599) // Within 3 degrees of "closed"
    {
        llSetLocalRot(gHomeRot);    // Be sure it's closed now, just in case
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

integer WhereAmI (vector AvPos) // Where is the av, relative to the door's default swing direction?
{
    float dotP = llRot2Fwd(gHomeRot)*llVecNorm((AvPos - llGetPos())/llGetRot()- llGetLocalPos());
    llSay(0,(string)dotP);
    if (giXisBigger)    // The door's X dimension is bigger than its Y dimension
    {
        return (RAD_TO_DEG*llAcos(dotP) < 0.0) ;   // TRUE or FALSE?
    }
    else    // The door's Y dimension is bigger than its X dimension 
    {
        return (RAD_TO_DEG*llAcos(dotP) > 0.0) ;   // TRUE or FALSE?
    }        
}

default
{
    state_entry()
    {
        // First, define the "closed" rotation for the door
        gHomeRot = llGetLocalRot();
        gfHomeAngle = llRot2Angle(gHomeRot);
        vector Size = llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_SIZE]),0);
        giXisBigger = (Size.x > Size.y);
        // and now, here's the default rotation to apply in swinging the door ....
        gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD>/steps );
    }
    
    touch_start( integer mum )
    {
        if ( IsClosed(llGetLocalRot()) )  //If the door is closed ...
        {
            gDir = 0;        
            if ( isFacing(llDetectedPos(0)) ) // Where is the av, relative to the door's default swing direction?
            {
                llSay(0,"other way");
                gDir = 1;
                // Reverse the door's default opening direction
                gRotSwing.s *= -1;
            }
            integer i;
            for(i = 0; i< steps;i++)
            {
                llSetLocalRot( gRotSwing * llGetLocalRot() ); 
            }
            gRotSwing.s *= -1;  // And reverse direction again, ready for the return swing
            llSetTimerEvent(gfOpenTime);         
        }
        else
        {
            integer i;
            for(i = 0; i< steps;i++)
            {
                llSetLocalRot( gRotSwing * llGetLocalRot() ); 
            }
        if (!gDir)  // If the door just opened in the default direction, we don't need to reverse it yet again
        {
            gRotSwing.s *= -1;
        }
        llSetTimerEvent(0.0); 
        }
    }
    
    timer()
    {
        // Now reverse the direction of gRotSwing and apply it....
        integer i;
            for(i = 0; i< steps;i++)
            {
                llSetLocalRot( gRotSwing * llGetLocalRot() ); 
            }
        if (!gDir)  // If the door just opened in the default direction, we don't need to reverse it yet again
        {
            gRotSwing.s *= -1;
        }
        llSetTimerEvent(0.0); 
    }
}

 

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