Have a look to this high quality video showing you how you can make use of it.
Note that to appreciate this tool you should enable Axis in advanced menu to be sure where x, y are growing so you understand better the meaning of X+ X- and similar :)
Yes, I know that many of you do prefer doing manual alignment, but I developed this piece of software in opensim, and wanted to share.
In SL they might ask you for 400-2000L$ for (yes, better pieces of software), but this can be quite useful for quickly building some structures.
How it works.
You just have this script named SalAligner: Put it on all the PRIMS you want to be helped in alignment. (It's enough moving from the inventory).
Clicking on a "scripted prim" will send you a menu which is:
NUDGE moving the object on x,y,z axis of 0.0001 meters (not normally achievable with UI),
OPTIONS not implemented yet
FINISH shouts to all prims to remove the script
SIZE modify sizex, sizey, sizez of this object copying it from the "pivot" object
TOUCH makes the touched object "touch" pivot object on the x, y, z axis (you can choos x+ or x- meaning touching on the growing x or on the decreasing x).
ROTATE allow to copy rotation or to move each axis 45 degrees
SET shouts this object position, size, rotation to all other objects that then can copy or adapt to it
MOVE move object to have the same x,y,z coordinates on their EXTERNAL bounds. (x+ means bounding on the max x, x- means bounding on the min x)
CENTER makes the center x,y, or z to match the pivot center
clicking on that except for FINISH, SET, OPTIONS (not implemented yet), you go to a submenu and you can keep in moving that object.
I'll try to make a video to explain visually how this is working.
You MUST click on a starting object and select SET to have it as a reference!!!
When finished you can click on FINISH on whatever prim and it will remove all the prims.
If you use this script for multiple USERS in the same sim, please change the iBROADCAST channel to different number.
This is just beta software prepared in a couple of hours, so some bugs might be there :)))) Feedback to me.
Lastly, this tool works also on SL grid so I will also distribute it on that grid (but openlife gets the first delivery!!!!)
Meanwhile, here is the script: Feel free to adapt it if you find it useful and to give me your copy...
vector pivotCenter;
vector pivotScale;
vector pivotScaleHalf;
vector pivotMinCorner;
vector pivotMaxCorner;
rotation pivotRotation;
integer iCHANNEL;
integer iBROADCAST=100;
list MOVEMENU=["M+X","M-X","M+Y","M-Y","M+Z","M-Z","BACK"]; // menu 1
list CENTERMENU=["CX","CY","CZ","BACK" ]; // menu 2
list TOUCHMENU=["T+X","T-X","T+Y","T-Y","T+Z","T-Z","BACK" ]; // menu 3
list SIZEMENU=["SX","SY","SZ","BACK"]; // menu 4
list ROTATEMENU=["RSAME","RX","RY","RZ","BACK" ]; // menu 5 various rotations
list MAINMENU=["SET","MOVE","CENTER","SIZE","TOUCH","ROTATE","NUDGE","OPTIONS","FINISH" ]; // menu 0
// NOT YET IMPLEMENTED
list NUDGEMENU=["X+0.0001","X-0.0001","Y+0.0001","Y-0.0001","Z+0.0001","Z-0.0001","BACK"]; // menu 6
integer iMOVEMENU=1;
integer iCENTERMENU=2;
integer iTOUCHMENU=3;
integer iSIZEMENU=4;
integer iMAINMENU=0;
integer iROTATEMENU=5;
integer iNUDGEMENU=6;
menu(key id,integer nextmenu)
{
if(nextmenu==iMOVEMENU) llDialog(id,"MoveMenu:",MOVEMENU,iCHANNEL);
if(nextmenu==iCENTERMENU) llDialog(id,"CenterMenu:",CENTERMENU,iCHANNEL);
if(nextmenu==iTOUCHMENU) llDialog(id,"TouchMenu:",TOUCHMENU,iCHANNEL);
if(nextmenu==iSIZEMENU) llDialog(id,"SizeMenu:",SIZEMENU,iCHANNEL);
if(nextmenu==iROTATEMENU) llDialog(id,"RotateMenu:",ROTATEMENU,iCHANNEL);
if(nextmenu==iNUDGEMENU) llDialog(id,"NudgeMenu:",NUDGEMENU,iCHANNEL);
if(nextmenu==iMAINMENU) llDialog(id,"Choose\nSET: set this obj as pivot\nCENTER: move to pivot center\nMOVE: move to pivot coord\nSIZE: same size as pivot\nTOUCH: go touching pivot",MAINMENU,iCHANNEL);
}
move(vector x, key id, integer nextmenu)
{
llSetPos(x);
menu(id,nextmenu);
}
default
{
state_entry()
{
llOwnerSay("Restarted");
// llListen(0,"",NULL_KEY,"");
llListen(iBROADCAST,"",NULL_KEY,"");
iCHANNEL=(integer)llFrand(10000000);
llListen(iCHANNEL,"",NULL_KEY,"");
}
listen(integer chan,string name,key id,string str)
{
// llOwnerSay("channel: "+(string)chan+" name: "+name+" key: "+(string)id+" str: "+str);
// be careful with FINISH
if(str=="FINISH")
{
llShout(iBROADCAST,str);
llRemoveInventory(llGetScriptName());
return;
}
if(chan==iCHANNEL)
{
if(str=="SET")
{
llShout(100,"SET"+(string)llGetPos()+"|"+(string)llGetScale()+"|"+(string)llGetRot());
llOwnerSay("Launched SET command");
return;
}
if(str=="BACK") menu(id,iMAINMENU);
if(str=="MOVE")
{
menu(id,iMOVEMENU);
return;
}
vector myCenter=llGetPos();
vector myScale=llGetScale();
vector myScaleHalf=myScale/2;
vector mymincorner=myCenter-myScaleHalf;
vector mymaxcorner=myCenter+myScaleHalf;
if(str=="M+X") move(<pivotMaxCorner.x-myScaleHalf.x,myCenter.y,myCenter.z>,id,iMOVEMENU);
if(str=="M-X") move(<pivotMinCorner.x+myScaleHalf.x,myCenter.y,myCenter.z>,id,iMOVEMENU);
if(str=="M+Y") move(<myCenter.x,pivotMaxCorner.y-myScaleHalf.y,myCenter.z>,id,iMOVEMENU);
if(str=="M-Y") move(<myCenter.x,pivotMinCorner.y+myScaleHalf.y,myCenter.z>,id,iMOVEMENU);
if(str=="M+Z") move(<myCenter.x,myCenter.y,pivotMaxCorner.z-myScaleHalf.z>,id,iMOVEMENU);
if(str=="M-Z") move(<myCenter.x,myCenter.y,pivotMinCorner.z+myScaleHalf.z>,id,iMOVEMENU);
if(str=="CENTER")
{
menu(id,iCENTERMENU);
return;
}
if(str=="CX") move(<pivotCenter.x,myCenter.y,myCenter.z>,id,iCENTERMENU);
if(str=="CY") move(<myCenter.x,pivotCenter.y,myCenter.z>,id,iCENTERMENU);
if(str=="CZ") move(<myCenter.x,myCenter.y,pivotCenter.z>,id,iCENTERMENU);
if(str=="SIZE")
{
menu(id,iSIZEMENU);
return;
}
if(str=="SX") {
llSetScale(<pivotScale.x,myScale.y,myScale.z>);
menu(id,iSIZEMENU);
return;
}
if(str=="SY") {
llSetScale(<myScale.x,pivotScale.y,myScale.z>);
menu(id,iSIZEMENU);
return;
}
if(str=="SZ") {
llSetScale(<myScale.x,myScale.y,pivotScale.z>);
menu(id,iSIZEMENU);
return;
}
if(str=="TOUCH")
{
menu(id,iTOUCHMENU);
return;
}
if(str=="T+X") move(<pivotMaxCorner.x+myScaleHalf.x,myCenter.y,myCenter.z>,id,iTOUCHMENU);
if(str=="T-X") move(<pivotMinCorner.x-myScaleHalf.x,myCenter.y,myCenter.z>,id,iTOUCHMENU);
if(str=="T+Y") move(<myCenter.x,pivotMaxCorner.y+myScaleHalf.y,myCenter.z>,id,iTOUCHMENU);
if(str=="T-Y") move(<myCenter.x,pivotMinCorner.y-myScaleHalf.y,myCenter.z>,id,iTOUCHMENU);
if(str=="T+Z") move(<myCenter.x,myCenter.y,pivotMaxCorner.z+myScaleHalf.z>,id,iTOUCHMENU);
if(str=="T-Z") move(<myCenter.x,myCenter.y,pivotMinCorner.z-myScaleHalf.z>,id,iTOUCHMENU);
if(str=="ROTATE") menu(id,iROTATEMENU);
if(str=="RSAME") llSetRot(pivotRotation);
if(str=="RX"){
rotation x_45 = llEuler2Rot( <45 * DEG_TO_RAD, 0, 0> );
rotation new_rot = llGetRot() * x_45; // compute global rotation
llSetRot(new_rot);
return;
}
if(str=="RY"){
rotation y_45 = llEuler2Rot( <0,45 * DEG_TO_RAD, 0> );
rotation new_rot = llGetRot() * y_45; // compute global rotation
llSetRot(new_rot);
return;
}
if(str=="RZ"){
rotation z_45 = llEuler2Rot( <0,0,45 * DEG_TO_RAD> );
rotation new_rot = llGetRot() * z_45; // compute global rotation
llSetRot(new_rot);
return;
}
if(str=="NUDGE") menu(id,iNUDGEMENU);
if(str=="X+0.0001") move(<myCenter.x+0.0001,myCenter.y,myCenter.z>,id,iNUDGEMENU);
if(str=="X-0.0001") move(<myCenter.x-0.0001,myCenter.y,myCenter.z>,id,iNUDGEMENU);
if(str=="Y+0.0001") move(<myCenter.x,myCenter.y+0.0001,myCenter.z>,id,iNUDGEMENU);
if(str=="Y-0.0001") move(<myCenter.x,myCenter.y-0.0001,myCenter.z>,id,iNUDGEMENU);
if(str=="Z+0.0001") move(<myCenter.x,myCenter.y,myCenter.z+0.0001>,id,iNUDGEMENU);
if(str=="Z-0.0001") move(<myCenter.x,myCenter.y,myCenter.z-0.0001>,id,iNUDGEMENU);
return;
}
if(chan==iBROADCAST)
{
list rest=llParseStringKeepNulls(llGetSubString(str,3,-1),["|"],[]);
pivotCenter=(vector)llList2String(rest,0);
pivotScale=(vector)llList2String(rest,1);
pivotRotation=(rotation)llList2String(rest,2);
pivotScaleHalf=pivotScale/2;
pivotMinCorner=pivotCenter-pivotScaleHalf;
pivotMaxCorner=pivotCenter+pivotScaleHalf;
return;
}
}
// when touched set the position
touch_start(integer count)
{
key id=llDetectedKey(0);
menu(id,iMAINMENU);
// llDialog(id,"Choose",["SET","X","Y","Z" ],iCHANNEL);
}
}