tag:blogger.com,1999:blog-67174999557490031912024-03-05T02:10:16.015-08:00The Aetherial PlaneDesdemona describes her virtual world scripting techniques and
the design reasoning and methodologies on which they are based.desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-6717499955749003191.post-65928753158677475322014-02-15T12:32:00.002-08:002014-03-07T11:57:18.572-08:00Rotation: a one prim door (more)<span style="font-family: Times,"Times New Roman",serif;">In the <a href="http://aetherialplane.blogspot.com/2014/02/rotation-one-prim-door.html">previous posting on this topic</a>, I mentioned in its Note 2 that a single call to llSetPrimitiveParams() would create a visual flaw in which the hinge wobbles. The flaw is caused by moving the center of the door in a straight line as it rotates. It is corrected by moving the center of the door in an arc around the hinge point.</span><br />
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<span style="font-family: Times,"Times New Roman",serif;">This drop-in replacement code for shiftTo() performs the interpolation.</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">shiftTo( vector pEnd, rotation rEnd ) {<br /> float swingDuration = 5; // seconds<br /> integer nSteps = 50; // must be positive. <br /> <br /> // start at the current location<br /> vector pStart = llGetPos();<br /> rotation rStart = llGetRot();<br /> <br /> // Find the hinge point, get the vector that will swing in an arc<br /> vector pHinge = pStart + lPhingePoint * rStart;<br /> vector vecToCenter = pStart - pHinge;<br /> <br /> // Get the angle and axis of the global rotation from start to end<br /> // Since rEnd = rStart * rDelta, left multiply by the inverse </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> // of rStart to isolate rDelta <span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><i><b>(note 1)</b></i></span></span><br /> rotation rDiff = (ZERO_ROTATION / rStart) * rEnd;<br /> float angle = llRot2Angle(rDiff);<br /> vector axis = llRot2Axis(rDiff);<br /> <br /> integer k; for ( k=0; k<nsteps br="" k=""> < nSteps; k++ ) {</nsteps></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><nsteps br="" k=""> // for each step, calculate an intermediate rotation difference<br /> // by interpolating the angle and applying it to the fixed axis<br /> float angleDelta = k * angle / (nSteps-1);<br /> rotation rDelta = llAxisAngle2Rot(axis,angleDelta);</nsteps></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><br /> // Use the intermediate rotation to rotate the hinge to center vector<br /> // Use the intermediate rotation to turn the object<br /> vector p = pHinge + vecToCenter * rDelta;<br /> rotation r = rStart * rDelta; // <span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><i><b>(note 2)</b></i></span></span><br /> llSetLinkPrimitiveParamsFast( LINK_THIS, </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> [ PRIM_POSITION, p, PRIM_ROTATION, r]);<br /> llSleep( swingDuration/nSteps );<br /> }<br />}</span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<span style="font-family: Times,"Times New Roman",serif;">As a bonus the door will slowly open and close. </span><i><b>(note 3)</b></i><br />
<br />
__________________<br />
<span style="font-family: Times,"Times New Roman",serif;"><i><b>Note 1</b></i></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">I discuss the algebraic manipulation of rotations and inverse rotations in <a href="http://aetherialplane.blogspot.com/2012/06/rotation-algebra.html">Rotation: Algebra</a>.</span></span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><i><b>Note 2</b></i></span><br />
<span style="font-family: Times,"Times New Roman",serif;">You may have noticed that in contrast to start_entry() (cf. note 3 in the prior post) the order of rotation multiplication in shiftTo() is reversed, that is, the change in rotation is right multiplied against the starting rotation.</span><br />
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<span style="font-family: Times,"Times New Roman",serif;">The order is reversed because both of these rotations have values in the global (region) coordinates.</span><br />
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<span style="font-family: Times,"Times New Roman",serif;">The difference between A*B and B*A is that one ordering corresponds to each rotation occurring in progressively rotated coordinates (as in start_entry()), whereas the other ordering corresponds to all rotations being in the same coordinates (as in shiftTo()).</span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><i><b>Note 3</b></i></span><br />
<span style="font-family: Times,"Times New Roman",serif;">If you wish to add sound effects, I recommend adding calls to llPlaySound() in touch_start(). Place them before and after the appropriate calls to ShiftTo().</span><br />
<br />
[end]<br />
<br />
<br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-71313690149467270792014-02-14T11:45:00.001-08:002014-02-19T13:31:24.425-08:003D Vision II: at ACC AlphaWith the permission of Haveit Neox, the creator of the<a href="http://maps.secondlife.com/secondlife/ACC%20Alpha/32/213/23"> region ACC Alpha</a>, here are a series of convergent (cross-eyed) viewable stereograms of that region. <br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3V4A8qnv0h-x2FqRxtqoDIz7glizEAqaeCmFb96e8iqDOMmHttQg-KCIcDMIap42W40eLDYQGGmKy5EmavvUgmQ_gwnRaQdjB7J5KOXatlSFjY8x9XjFXZp8bSbzt4YTf8kEpyqg6WE3M/s1600/lr_chess2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3V4A8qnv0h-x2FqRxtqoDIz7glizEAqaeCmFb96e8iqDOMmHttQg-KCIcDMIap42W40eLDYQGGmKy5EmavvUgmQ_gwnRaQdjB7J5KOXatlSFjY8x9XjFXZp8bSbzt4YTf8kEpyqg6WE3M/s1600/lr_chess2.jpg" height="138" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Chess sets are a traditional subject for 3D rendering</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLAtGjr7Bwuji4zKGAV6PMrS5M__TFNbwd28VnLgEBcTfVK8qguMHUYppdszfhvsXe-4fWP67kTRq40yvz1t8CKsJwOhi8WZNQSridRZojI-UamzI6t5V6s0UU6666pzJ_dTmQP-fduKaU/s1600/lr_screen.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLAtGjr7Bwuji4zKGAV6PMrS5M__TFNbwd28VnLgEBcTfVK8qguMHUYppdszfhvsXe-4fWP67kTRq40yvz1t8CKsJwOhi8WZNQSridRZojI-UamzI6t5V6s0UU6666pzJ_dTmQP-fduKaU/s1600/lr_screen.jpg" height="139" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Through a screen darkly. Do visit the Tower</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSQDOYs-xsd27MS77Jn6jqVlYs8tMBAGSRGPNdl0GpDfRHg7NUoLszGR9ZE1Dho1BDDuEoLQ_dHKBFvKKtTdE896bDvkQjD_Wvke9UKIkBvgdXnEYV9sVKAIrokhtWxTCfBdcTumou3cJS/s1600/lr_tower.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSQDOYs-xsd27MS77Jn6jqVlYs8tMBAGSRGPNdl0GpDfRHg7NUoLszGR9ZE1Dho1BDDuEoLQ_dHKBFvKKtTdE896bDvkQjD_Wvke9UKIkBvgdXnEYV9sVKAIrokhtWxTCfBdcTumou3cJS/s1600/lr_tower.jpg" height="139" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The Tower has many levels and multiple subtexts</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ7WDtNUWJA7J3zOklWWPQDtDqRnJzcl0TKQe_BaVE8BELzC2UBRXjf_LLOJbtYP_uWRK20Jjqwd45g4GAbOrLG_-pvr1T_VlJ1D6q3deU6xGHfi6G7Z99U5bX3swZXCnRtbcAhRPdhBjA/s1600/lr_village.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ7WDtNUWJA7J3zOklWWPQDtDqRnJzcl0TKQe_BaVE8BELzC2UBRXjf_LLOJbtYP_uWRK20Jjqwd45g4GAbOrLG_-pvr1T_VlJ1D6q3deU6xGHfi6G7Z99U5bX3swZXCnRtbcAhRPdhBjA/s1600/lr_village.jpg" height="139" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Walk the streets of the paper village</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi98AkRtpZXVGjTulSbbTi8WAAWPuCrUP5IBGzSLlUNlOy5d1bzXr012nFbCMpGdKsjs8KqN4OQx2xPAzgMXT2HKIF-83S3NvgJFjsKXPw69PhkI0oAofzMeMiqITOEGgP08cKdT_C3mNxC/s1600/lr_gallery.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi98AkRtpZXVGjTulSbbTi8WAAWPuCrUP5IBGzSLlUNlOy5d1bzXr012nFbCMpGdKsjs8KqN4OQx2xPAzgMXT2HKIF-83S3NvgJFjsKXPw69PhkI0oAofzMeMiqITOEGgP08cKdT_C3mNxC/s1600/lr_gallery.jpg" height="138" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Tour the fine galleries</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHe1ejVJjGvw1zjQhxGm1R45_TJhs7vBcpNh2Xd6RX8_EuXXuJfdhNwzaZXgNlqg3wtC_crP8i1Bff0TTOEL4jDshGD48upjLticE16m8v5IlxSJtB4bA8JmRJ2CEk7DuScq2yd0nyeLmX/s1600/lr_cafe.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHe1ejVJjGvw1zjQhxGm1R45_TJhs7vBcpNh2Xd6RX8_EuXXuJfdhNwzaZXgNlqg3wtC_crP8i1Bff0TTOEL4jDshGD48upjLticE16m8v5IlxSJtB4bA8JmRJ2CEk7DuScq2yd0nyeLmX/s1600/lr_cafe.jpg" height="139" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Relax in a cafe at in the shopping/gallery district</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
You may these easier to view of you download them and view them at a smaller scale.<br />
<br />
My preceding post on <a href="http://aetherialplane.blogspot.com/2014/02/3d-vision-i-stereoscopic-rendering.html">stereoscopic imaging</a> my be of interest.<br />
<br />
<br />
[end] desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-73584336800319475652014-02-13T05:11:00.003-08:002014-02-15T12:47:54.275-08:00Rotation: a one prim door<br />
The simplest method to make a swinging door is to use a box prim that has half of its volume cut away. The remaining visible section has its local Z axis on an edge. You can swing the door with<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> vector doorRot = llEuler2Rot( < 0, delta, 0 > ); </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> llSetRot( doorRot * llGetRot() );</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><!--0--><!--0--><!--0--><!--0--><!--0--><!--0--><!--0--><!--0--><!--0--></span></span><br />
where 'delta' is an angle (radians) that alternates positive and negative on each touch.<br />
<br />
However, if you wish to make a Hobbit door from, say, a cylinder, you can still get the edge hinge effect without cutting the prim. The trick is to move the center of the door as you rotate it so as to keep the global (region) position of the edge in the same place.<br />
<br />
<div class="" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVmyb9ZzAYNeHtE4yeT6G5-tWhvgVmhUqfamQOeHp4s1FHB78iPpxczq2XclGEfiVmYO1tn0LF-SYEVl4Mohi0oNuQi2mry5RNqjaDfyFbnyKPtGgT-rm5OdKmXMFYKpo42YWzLVW5_IdH/s1600/20140213+-+Hobbit+Door.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVmyb9ZzAYNeHtE4yeT6G5-tWhvgVmhUqfamQOeHp4s1FHB78iPpxczq2XclGEfiVmYO1tn0LF-SYEVl4Mohi0oNuQi2mry5RNqjaDfyFbnyKPtGgT-rm5OdKmXMFYKpo42YWzLVW5_IdH/s1600/20140213+-+Hobbit+Door.JPG" height="200" width="195" /></a>For this discussion, imagine a cylinder with Z sized down to make a disk. Orient this with its local Y+ axis upward. The hinge point will be where the prim local X+ axis intercepts the edge of the cylinder. The prim will rotate around a vertical axis.</div>
<br />
Place this script in the prim. Then touch the prim.<br />
<br />
<br />
<br />
<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">integer isOpen = 0;<br />float swingAngleDeg = -80;<br /><br />vector gPdoorOpen; // values in global (region) coordinates<br />vector gPdoorShut; // (note 1)<br />rotation gRdoorOpen; <br />rotation gRdoorShut;<br /><br />vector lPhingePoint; // value in local (cylinder) coordinates<br /><br />shiftTo( vector p, rotation r ) {</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> // There will be a visual problem with this method (note 2) </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> llSetPrimitiveParams([PRIM_POSITION,p,PRIM_ROTATION,r]);<br />}<br /> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">////////////////////////////////////////////////////////////////////<br />default {<br />state_entry() {<br /> // The closed position is determined by reset<br /> gPdoorShut = llGetPos();<br /> gRdoorShut = llGetRot();<br /><br /> // The open rotation is an additional local Y axis rotation (note 3)</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> vector eulerRot = < </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">0, DEG_TO_RAD*swingAngleDeg, 0 ></span>;</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> gRdoorOpen = llEuler2Rot(</span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">eulerRot</span></span>) * gRdoorShut;<br /><br /> // Calculate the open position (note 4)<br /> vector size = llGetScale();<br /> lPhingePoint = <<size .x=""> size.x/2, 0, 0 >;<br /> gPdoorOpen = gPdoorShut + (lPhingePoint * gRdoorShut) </size><!--0--><!--0--></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> - (lPhingePoint * gRdoorOpen);<br />}<br /><br />touch_start(integer nTouch) {<br /> isOpen = !isOpen;<br /> if ( isOpen ) {</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">shiftTo(</span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">gPdoorOpen,</span></span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">gRdoorOpen);</span></span></span></span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> } else {<br /> shiftTo(</span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">gPdoorShut,</span></span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">gRdoorShut);</span></span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> } </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"></span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">}</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;">}</span></span><br />
<br />
This script will work for any prim size or orientation. Just remember to reset the script if you change the prim position, rotation, or size.<br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">_____________________________ </span></span><br />
<i><b><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">Note 1:</span></span></b></i><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">In this notation, the first letter is l or g and indicates local or global coordinates. The second letter is P or R and indicates position or rotation. The remaining letters describe which specific point. </span></span><br />
<br />
<i><b><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">Note 2:</span></span></b></i><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">While rotating the center of the prim is moving in a straight line. The result is
that the hinge will wobble. The correct movement is rotating
the prim while moving the center of the prim in an arc about the hinge point.</span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">There are two methods to do this: </span></span><br />
<ul>
<li><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">shiftTo() can be a loop that performs a series of small calculated rotations, or </span></span></li>
<li><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">shiftTo() can create a list of incremental positions along an arc and corresponding rotations and pass this list to <a href="http://wiki.secondlife.com/wiki/LlSetKeyframedMotion">llKeyFramedMotion()</a>. </span></span></li>
</ul>
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">However,
llKeyFrameMotion() is a flawed implementation that drifts. You will
have to apply corrections when the motion completes, that is, if it completes. <a href="http://wiki.secondlife.com/wiki/LlSetKeyframedMotion">The irksome details are documented in the caveats here</a>.</span></span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">See <a href="http://aetherialplane.blogspot.com/2014/02/rotation-one-prim-door-more.html">this future posting</a> for the loop series fix. </span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><br /></span></span><i><b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">Note 3:</span></span></span></span></b></i><br />
Why A*B and not B*A? First, for two combined rotations the order matters. Second, this problem has two rotation: B = the prim rotation with respect to the region when closed (gRdoorShut = llGetPos()), and A = the addition rotation needed to turn the door from closed to open<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"> (llEuler2Rot(eulerRot)).</span></span><br />
<br />
A is a rotation that is expressed in terms of the local coordinates of the prim that has already been rotated by B. A is specifically a rotation about the prim local Y+ <span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">axis (swingAngleDeg)</span></span>. In this case, where A is relative to B local coordinates, the multiplication order is A*B.<i><b><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"></span></span></b></i><br />
<i><b><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><br /></span></span></b></i>
<i><b><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">Note 4:</span></span></b></i><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"> </span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">The hinge point has both a global (region coordinates) and local (prim coordinates) position value. By
definition a prim rotation converts a vector in a the prim local
coordinates to a vector in the global coordinates relative to the prim center. Therefore the global
position of the hinge point is its rotated local vector added to the
prim global position.</span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">When the door is open</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> gPhingePointOpen = gPdoorOpen + lPhingePoint * gRdoorOpen</span></span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">and when the door closed is </span></span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> gPhingePointShut = gPdoorShut + lPhingePoint * gRdoorShut</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">However
the hinge does not change position, so the right hand
expressions have the same value. Now solve the equated right side expressions for
gPdoorOpen. Q.E.D.</span></span></span></span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-size: small;">[end]</span></span><br />
<br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-74051588862218262502014-02-02T12:01:00.003-08:002014-02-06T20:43:25.602-08:003D Vision I: stereoscopic imaging<span style="font-family: inherit;"></span>
<span style="font-family: inherit;">Human binocular vision allows people to directly perceive depth in their local environment (<span style="font-size: x-small;">note 1</span>). By using pairs of pictures created with slightly different camera viewpoints and letting each eye see only one of these pictures, this innate ability can be tricked into experiencing depth (<span style="font-size: x-small;">note 2</span>).</span><br />
<br />
<span style="font-family: inherit;">____________ </span><br />
<span style="font-family: inherit;">In this pair of images the right image camera viewpoint is slightly to the right of the left image camera viewpoint (look closely at the relationship of the blue arrow to one of the red balls). </span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6WSnV92X9Ffe2SAx_-pO7oq8kcYu9Tf3pvcRkTsgk_vmgtQCFKbvJ18xCir7HLJtPj_79p9IghCQBOpqLwfpZJnLhjABj3lILDdasqmpOyO-htAoEWYCG3dUINjAQFdQariktX7joUKpp/s1600/box_rr_ll.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6WSnV92X9Ffe2SAx_-pO7oq8kcYu9Tf3pvcRkTsgk_vmgtQCFKbvJ18xCir7HLJtPj_79p9IghCQBOpqLwfpZJnLhjABj3lILDdasqmpOyO-htAoEWYCG3dUINjAQFdQariktX7joUKpp/s1600/box_rr_ll.jpg" height="198" width="400" /></a></div>
<br />
If you could 'stare at infinity' in a way that causes your right eye to
gaze directly at the right image, and your left eye at the left, then
your doubled vision may see a third merged image in the center that has the
illusion of depth. Many people find this to be quite difficult. We do not have much practice in intentionally diverging our eyes while maintaining a close focal plan. (<span style="font-size: x-small;">note 3</span>)<br />
<br />
<span style="font-family: inherit;">____________</span><br />
More people are able to use the 'cross-eyed' viewing technique. This pair of images has been transposed left to right.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHQUu4go3wcbz8lJuKKpirPzD7OpUZse2reAyMoURy-6QTgqQa_RvlmkLeZK0bTbf6-9JcBlwTvpcpovxrsq2F4I5QOoiQWhWRoxfUlPEui7i28RMu0oFtBY1OxZCJakUCZXfvw7lTRzGc/s1600/box_rl_transposed.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHQUu4go3wcbz8lJuKKpirPzD7OpUZse2reAyMoURy-6QTgqQa_RvlmkLeZK0bTbf6-9JcBlwTvpcpovxrsq2F4I5QOoiQWhWRoxfUlPEui7i28RMu0oFtBY1OxZCJakUCZXfvw7lTRzGc/s1600/box_rl_transposed.jpg" height="197" width="400" /></a></div>
<br />
<span style="font-size: small;">If you can converge (cross) the lines of sight of your eyes while maintaining your focal plane on the images, then
your doubled vision may see a third merged image in the center that has the
illusion of depth.</span><br />
<span style="font-size: small;"><br /></span>
<span style="font-family: inherit; font-size: small;">____________</span> <br />
<span style="font-size: small;"><span style="font-family: inherit;">All systems that allow you to see 3D in virtual worlds use this technique to create the illusion of depth. They differ in the methods by which they allow each eye to see one of the images. They may</span></span><br />
<ul>
<li><span style="font-size: small;"><span style="font-family: inherit;">alternately flicker the two images while you wear glasses with alternating shutters <span style="font-size: x-small;">(note 4</span>)</span></span></li>
<li><span style="font-size: small;"><span style="font-family: inherit;">show both images but use goggle optics to diverge and focus your eyes to each image (<span style="font-size: x-small;">note 2</span>)</span></span></li>
<li><span style="font-size: small;"><span style="font-family: inherit;">merge images while tinting each with distinct colors while you wear color screening glasses (<span style="font-size: x-small;">note 5</span>)</span></span></li>
</ul>
<span style="font-size: small;"><span style="font-family: inherit;">The optic method allows the images to be placed much closer to the eyes. By distorting the images with wide view angle and barrel distortion to compensate for the optic effects, you see a more surrounding effect. (<span style="font-size: x-small;">note 2c</span>)</span></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm8K4JKPhIun61PYIqYC7k74r892cPBsfI2v70w4TqBdatayKyJsRIsMuPk8_ykQNrzWmFCumOeC7Q189oicY3_tEYK0zmmmkumRogxc5GwgKVWT7BpXWv9ux96NBgwlILywMaZxPe7KZe/s1600/20080207+-+desde+rl_transposed.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm8K4JKPhIun61PYIqYC7k74r892cPBsfI2v70w4TqBdatayKyJsRIsMuPk8_ykQNrzWmFCumOeC7Q189oicY3_tEYK0zmmmkumRogxc5GwgKVWT7BpXWv9ux96NBgwlILywMaZxPe7KZe/s1600/20080207+-+desde+rl_transposed.jpg" height="132" width="320" /></a></div>
<span style="font-size: x-small;"><span style="font-family: Arial,Helvetica,sans-serif;"><span style="font-size: x-small;"><span style="font-family: Arial,Helvetica,sans-serif;">_______________</span></span> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: Arial,Helvetica,sans-serif;"><span style="font-size: x-small;"><span style="font-family: Arial,Helvetica,sans-serif;">_______________</span></span> </span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;"></span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;">Note 1: Beyond several meters distance our binocular vision mechanism becomes ineffective and our depth perception relies on other cues such as parallax, scale consistency, atmospheric degradation, light shading, and memory. When you watch a conventional movie, all of your sense of depth in the scenes comes from these alternate cues.</span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;"><br /></span></span>
<span style="font-size: small;"><span style="font-family: inherit;">Note 2: </span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;">a) <a href="http://en.wikipedia.org/wiki/Stereogram">http://en.wikipedia.org/wiki/Stereogram</a> </span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;">b) <a href="http://en.wikipedia.org/wiki/Viewmaster">http://en.wikipedia.org/wiki/Viewmaster</a> </span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;">c) <a href="http://www.oculusvr.com/">http://www.oculusvr.com/</a></span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;"><br /></span></span>
<span style="font-size: small;"><span style="font-family: inherit;">Note 3: For diverging ("infinity") viewing it may help to hold up a piece of paper that prevents each eye from seeing the image intended for the other eye. It may also help to download the images on this post and reduce their size.</span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">Note 4: <a href="http://en.wikipedia.org/wiki/Active_shutter_3D_system">http://en.wikipedia.org/wiki/Active_shutter_3D_system</a></span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: inherit;">Note 5: <a href="http://en.wikipedia.org/wiki/Anaglyph_3D">http://en.wikipedia.org/wiki/Anaglyph_3D </a></span></span><br />
<br />
[end]desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-89276148132668988232013-12-27T10:30:00.004-08:002013-12-27T14:12:31.571-08:00Generating Bézier Curves<span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;">A</span></span><span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;"><span dir="auto"> Bézier </span>curve is a directed path defined by a ordered set of reference points. It starts at the first point and ends at the last point. It rarely passes through any of the intermediate points, which instead act as attractors that warp the curve in their direction as the curve passes by them.</span></span><br />
<span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;"><br /></span></span>
<span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;">For details about this class of curves and several dynamic visualizations, I refer you to the article at this location</span></span><br />
<span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;"><br /></span></span>
<span style="font-size: small;"><span style="font-family: Arial,Helvetica,sans-serif;"><a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">http://en.wikipedia.org/wiki/B%C3%A9zier_curve</a></span></span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">___________________________________________</span><br />
<span style="font-family: Arial;">This position along a Bézier curve is specified by an independent variable in the range [0,1]. The value '0' is the start of the curve, the value '1' is the end of the curve.</span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">One method of calculating a series of points along a Bézier curve is to use polynomial functions of this variable with coefficients that are linear in the positions of the reference points. The down side of this method is that you need a different polynomial whenever you change the number of reference points.</span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">My preferred method is recursive (<strong><em>note 1</em></strong>). Given the ordered list of reference points 'list posList = [ .. vectors...];' and the independent variable 'float s;' in the range [0,1], the calculation proceeds as follows (<strong><em>note 2</em></strong>):</span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">vector getBezierPos( float s ) {<br /> // This method uses the direct progressive linear interpolation definition<br /> // of an n-th order bezier, instead of the clumbersome formulae.<br /> list q = posList;<br /> integer nq;<br /> while ( (nq=llGetListLength(q)) > 1 ) {<br /> list q2 = [];<br /> integer k; for ( k=1; k < nq; k++ ) {</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><nq br="" k=""> vector p1 = llList2Vector(q,k-1);<br /> vector p2 = llList2Vector(q,k);<br /> q2 += (1-s)* p1 + s * p2;<br /> }<br /> q = q2;<br /> }<br /> return llList2Vector(q,0);<br />}</nq></span><br />
<span style="font-family: Courier New; font-size: x-small;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">In the Wikipedia reference, find the dynamic visualization that demonstrates the construction of a Bezier curve as a progression of linear interpolations. </span><span style="font-family: Arial, Helvetica, sans-serif;">My implementation of getBezierPos() exactly follows that demonstration.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-family: Arial;">___________________________________________</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">To elucidate the selection of values of 's', I will add here the function which rezzes prims along the Bézier curve.</span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">integer nDot = 20;</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">string dotName = "dot";</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">generateBezierDots() {<br /> // The Bézier parameters is a variable in the range [0,1]. Divide this<br /> // interval into nDot segments. Rez dots at the mid point of these segments.<br /> float step = 0;<br /> if ( nDot > 0 ) step = 1.0 / nDot;</span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> integer k; for ( k=1; k <= nDot; k++ ) {<br /> vector p = getBezierPos( step * (k - 0.5) );<br /> llRezObject(dotName, p, ZERO_VECTOR, ZERO_ROTATION, 0 );<br /> }<br />}</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<span style="font-family: Courier New; font-size: x-small;"></span><span style="font-family: Arial;">___________________________________________</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">In my full implementation (<strong><em>note 3</em></strong>) of this script, I use llSensor() to find a series of reference markers. The sensor() event makes note of the positions and descriptions of these prims, the description fields of the markers are used to sort the data, and the ordered position are stored in posList. </span><br />
<span style="font-family: Courier New; font-size: x-small;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Desdemona</span><br />
<span style="font-family: Arial;"></span><br />
_____________________________________________<br />
<span style="font-family: Times, "Times New Roman", serif;"><strong>Note 1</strong></span><br />
<span style="font-family: Times, "Times New Roman", serif;">Purists will note that I did not strictly use a recursive function. Ultra purists will complain that said function should have been tail recursive. I will leave it to them to post the pure implementation on their blogs and let them cope with a stack usage that that is quadratic in the number of reference points and with LSL not supporting tail recursion.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"></span><br />
<span style="font-family: Times;"><strong>Note 2</strong></span><br />
<span style="font-family: Times;">If you want a vector tangent to the curve, in getBezierPos() catch the value"p2-p1" when nq is 2. </span><br />
<br />
<span style="font-family: Times, "Times New Roman", serif;"><strong>Note 3</strong></span><br />
<span style="font-family: Times, "Times New Roman", serif;">If you would like a copy of my full implementation, come to my vast land empire of 512 m-sq and pick up a copy from my vendor titled "Simple Bezier Curve". You will get a combo object (mod/copy/trans, including scripts) that includes 4 green reference markers. Rez this and touch the blue sphere. Voila, 20 pink dots rezzed along the curve. </span><br />
<span style="font-family: Times, "Times New Roman", serif;"></span><br />
<span style="font-family: Times, "Times New Roman", serif;">Move the reference markers around and touch the blue sphere again. Delete reference markers or shi</span><span style="font-family: Times, "Times New Roman", serif;">ft copy more reference markers as you wish, however, make sure they all have distinct descriptions that will order them as you wish.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"></span><br />
<span style="font-family: Times, "Times New Roman", serif;">The vendor is here:</span><br />
<span style="font-family: Times, "Times New Roman", serif;"></span><br />
<span style="font-family: Times, "Times New Roman", serif;"><a href="http://maps.secondlife.com/secondlife/Pomponio/191/155/59">http://maps.secondlife.com/secondlife/Pomponio/191/155/59</a></span><br />
<span style="font-family: Times, "Times New Roman", serif;"></span><br />
<span style="font-family: Arial;">[end]</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-21579213533083715102013-12-03T15:49:00.001-08:002013-12-03T16:30:44.321-08:00Sanitizing Your Strings<span style="font-family: Arial,Helvetica,sans-serif;">Do you have systems that insist on giving you numeric strings with embedded commas, currency symbols, hash marks, and spaces? </span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">data = $12,340.14</span><br />
<span style="font-family: "Courier New",Courier,monospace;">data = 0.000 000 013 456</span><br />
<span style="font-family: "Courier New",Courier,monospace;">data = #336#</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;">Use this method to concisely remove these annoyances from strings: </span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"> string text = "whateverAboveMessTheyGaveYou<whateverabovemessyouweregiven>";</whateverabovemessyouweregiven></span><br />
<span style="font-family: "Courier New",Courier,monospace;"> float value = (float) llDumpList2String( </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> llParseString2List(text,["$",",","#"," "],[]),</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "");</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;">[end]</span><br />
<br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-45035209741588862892012-06-28T10:14:00.001-07:002014-03-25T06:45:06.786-07:00Rezzing prims with varying properties<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">If an object rezzes prims with varying properties (shape, size, color, texture, etc), it can rez a generic scripted prim and then send that prim a message containing a list of values to be given to llSetPrimitiveParams().<br /><br />The prim to be rezzed would contain this script</span><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-family: "Courier New",Courier,monospace; font-size: x-small;"> </span></span><br />
<br />
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-family: "Courier New",Courier,monospace; font-size: x-small;">integer rezzerChannel = -873648273;<br />integer settingsChannel = -873648274; </span></span><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">default</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">{</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">state_entry() { </span></span></span><br />
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> llSetStatus( STATUS_DIE_AT_EDGE, TRUE ); </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llListen( settingsChannel, "", NULL_KEY, "" );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span><br style="font-family: "Courier New",Courier,monospace;" /><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">on_rez( integer rezCode ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( rezCode == 0 ) { </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llResetScript();</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> } else {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llSay(rezzerChannel , "primRezzed|"+(string)rezCode);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span><br style="font-family: "Courier New",Courier,monospace;" /><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">listen ( integer channel, string fromName, key fromKey, string msg ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> list a = llParseStringKeepNulls( msg, ["|"], [] );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( llList2String(a,0) == "primSettings" ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( llList2String(a,-1) == "END" ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> integer n = (integer)llList2String(a,1);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( n > 0 ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> list params = decodeTypeList( llList2List( a,2,n+1) );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llSetPrimitiveParams( params );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> } else {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llSay(DEBUG_CHANNEL, "*** truncated message");</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llRemoveInventory( llGetScriptName() ); </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span></span></span><br />
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><br />Notes on the rezzed prim script: </span><br />
<ul>
<li style="font-family: Arial,Helvetica,sans-serif;"><span style="font-size: small;">STATUS_DIE_AT_EDGE keeps errant prims out of your Lost and Found folder.</span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">In on_rez(), the special handling of a rezCode of zero allows you to manually rez the prim. The rezzer should give a non-zero rezCode to each object it rezzes. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">For non-zero rezCodes, the script sends a message back to the rezzer. The rezzer responds with the desired settings. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">llSay() is sufficient because the prim must have been rezzed within 10 meters of the rezzer. </span></li>
</ul>
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">________________<br />A rezzer script that creates a green horizontal polygon could be written as follows:<br /><br /><span style="font-family: "Courier New",Courier,monospace; font-size: x-small;">integer rezzerChannel = -873648273;<br />integer settingsChannel = -873648274; <br /><br />integer polyCount = 8;<br /><br />default<br />{<br />state_entry() { <br /> llListen( rezzerChannel , "", NULL_KEY, "" );<br />}<br /><br />touch_start( integer nTouch ) {</span></span><span style="font-family: Arial,Helvetica,sans-serif; font-size: x-small;"> </span><span style="font-family: Arial,Helvetica,sans-serif; font-size: x-small;"> </span><br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> string name = llGetInventoryName(INVENTORY_OBJECT,0); <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">integer k;
</span><span style="font-size: x-small;">for ( k=0; k < polyCount; k++ ) {<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">llRezObject( name, llGetPos(), ZERO_VECTOR, <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">ZERO_ROTATION, 100 + k);<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">} <br />}<br /><br />listen ( integer channel, string fromName, key fromKey, string msg ) {<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">list a = llParseStringKeepNulls( msg, ["|"], [] );<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">if ( llList2String(a,0) == "primRezzed" ) {<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">integer index = (integer)llList2String(a,1);<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">float height = 5;<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">float radius = 15; </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">float width = 0.2;<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">float length = 2 * radius * llTan( PI / polyCount );</span><br />
<span style="font-size: x-small;"><br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">float angle = index * TWO_PI / polyCount;<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">rotation cRot = llEuler2Rot( < PI_BY_TWO, 0,0> ) <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">* llEuler2Rot( <0, 0, angle > );</span><br />
<span style="font-size: x-small;"><br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">vector cPos = llGetPos() + < 0,0 ,height> </span><br />
<span style="font-size: x-small;"> + </span><span style="font-size: x-small;">< radius,0 ,0></span><span style="font-size: x-small;">* cRot;</span><br />
<span style="font-size: x-small;"><br /></span><span style="font-size: x-small;"> // [ PRIM_TYPE, PRIM_TYPE_CYLINDER, integer hole_shape, <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">// vector cut, float hollow, vector twist, <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">// vector top_size, vector top_shear ] <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">list settingsList = [ <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0,1,0>, 0.0,<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><0,0,0>, <1,1,0>, <0,0,0>,<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">PRIM_COLOR, ALL_SIDES, <0,1,0>, 1.0,</span><span style="font-size: x-small;"><br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">PRIM_SIZE, < width, width, length >,</span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">PRIM_ROTATION, cRot, </span><br />
<span style="font-size: x-small;"> PRIM_POSITION, cPos, </span><span style="font-size: x-small;">PRIM_POSITION, cPos, </span><br />
<span style="font-size: x-small;"> PRIM_POSITION, cPos ];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> settingsList = encodeTypeList( settingsList );</span><br />
<span style="font-size: x-small;"><br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">llRegionSayTo( fromKey, settingsChannel, llDumpList2String( <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">[ "primSettings", llGetListLength(settingsList) ] <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">+ settingsList <br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">+ ["END"], "|" ));<br /> </span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">}<br />}<br />}</span></div>
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><br />Notes on rezzer script: </span><br />
<ul>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">It does not matter where llRezObject() places the prims since the subsequent message will specify the position. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"> Do not send prim settings in the object_rez() event. The prim may have rezzed, yet it may not have registered its listen event with the region. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">SET_POSITION is limited to a 10 meter movement, so use several as needed. Given the height and radius used in this script, three was more than sufficient. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">There is a limit to the number of messages that may be queued to the rezzer. If you will be rezzing more than 30 prims, use a timer to rez them in bursts of 20. Keep track of the number of rezzed prims and the number of messages received. Only rez bursts when the difference is less than 10.</span></li>
</ul>
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"> </span>________________<br />
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"></span><br />
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">General notes: </span><br />
<ul>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">The functions encodeTypeList() and decodeTypeList are described in the post "<a href="http://aetherialplane.blogspot.com/2012/06/interobject-communications-lists.html">Interobject Communications: lists</a>" </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">If the call to llRemoveInventory() is removed from </span><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">the rezzed prim script</span><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">, then the rezzer could later change the settings of specific rezzed prims. In this situation, the rezzed prim script should accept a "primScriptRemove" message.</span></li>
</ul>
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;"> </span><br />
<ul>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">Region managers frown on high performance rezzers. You might consider throttling the rezzing by putting a brief llSleep() after llRezObject(), which has an intrinsic delay of only 0.1 second. </span></li>
<li><span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">As a clean-up courtesy to the region server, the rezzed prim script might call llSetTimerEvent() when the rezCode is non-zero. The timer event handler would call llDie(). </span></li>
</ul>
<span style="font-family: Arial,Helvetica,sans-serif; font-size: small;">[end] </span>desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-33832946418591605522012-06-19T12:04:00.001-07:002012-06-22T06:41:03.004-07:00Rotation: algebra<div style="font-family: Arial,Helvetica,sans-serif;">
An earlier post on rotational pivoting used a correct yet misleading algebraic slight of hand. Given the relationship</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
(1) vecA = vecB * rotQ</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
the post solved for vecB by "dividing" both sides of the equation by rotQ:</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
(2) vecB = vecA / rotQ</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The LSL compiler accepts this expression, however, the concept of 'divide by a rotation' opens many doors to confused thinking. When solving complex rotational problems, it is safer to think in terms of multiplication by inverse rotations. </div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The inverse of rotQ is the rotation that undoes rotQ. In LSL this inverse is designated using the expression "ZERO_ROTATION / rotQ". By the meaning of 'inverse'<br />
<br />
(3) rotQ * ( ZERO_ROTATION / rotQ ) = ZERO_ROTATION<br />
(4) ( ZERO_ROTATION / rotQ ) * rotQ = ZERO_ROTATION <br />
<br />
_________<br />
To solve for vecB using inverse rotations, right side multiplying each side of (1) by the inverse of rotQ<br />
<br />
(5) vecA * (ZERO_ROTATION / rotQ) = (vecB * rotQ) * (ZERO_ROTATION / rotQ)<br />
<br />
Calculation precedence does not matter when multiplying vectors and rotation. Thus the terms on the right side of (5) can be regrouped:<br />
<br />
(6) vecA * (ZERO_ROTATION / rotQ) = vecB * ( rotQ * (ZERO_ROTATION / rotQ) )<br />
<br />
Using (3) on the right side of (6), (6) becomes<br />
</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
(7) vecA * ( ZERO_ROTATION / rotQ ) = vecB * ZERO_ROTATION<br />
<br />
Since ZERO_ROTATION means not rotating, and since not rotating vecB leaves it unchanged <br />
<br />
(8) vecB * ZERO_ROTATION = vecB.<br />
<br />
and therefore<br />
<br />
(9) vecB = vecA * ( ZERO_ROTATION / rotQ )<br />
<br />
___________________<br />
If the proof of (3) and (4) seems to be a trivial rearrangement of terms, then you may be thinking in terms
of numeric algebra, not vector and rotation algebra. The use of inappropriate numeric algebraic rules is the cause of many types of logical errors when attempting to solve rotational algebra
problems.<br />
<br />
In (9) the expression "ZERO_ROTATION / rotQ" is a compiler syntactical trick.
It should not be mentally parsed into the items ZERO_ROTATION, /,
and rotQ. The compiler consumes it as a unit and emits the operation
"compute inverse of rotQ". <br />
<br />
In equation (2), the expression "vecA / rotQ" is also a compiler syntactic trick and should not be mentally parsed into items. The LSL compiler treats "vecA / rotQ" as if it were "vecA * ( ZERO_ROTATION / rotQ )". Thus (2) and (9) express the same result.<br />
<br />
___________________</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
Notes:</div>
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">The formal name for the rule (vecA * rotP) * rotQ = vecA * (rotP * rotQ) is associativity. This rule means that the expression vecA * rotP * rotQ is unambiguous. </span></li>
<li><span style="font-size: small;">The order of rotations matters. vecA * rotP * rotQ != vecA * rotQ * rotP unless the rotations have the same axis. This formal name for this property is non-commutative. </span></li>
<li><span style="font-size: small;">Rotation is distributive when applied to the sum of two vectors. ( vecA + vecB ) * rotQ = vecA * rotQ + vecB * rotQ </span></li>
</ul>
<br />
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">When multiplying vectors and rotations, the rotation are
always on the right side. This is a syntactical convention based
on desiring vectors to be represented by a horizontal row of numbers in
matrix algebra. </span></li>
</ul>
<br />
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">The expression rotQ * vecA is meanless. </span></li>
<li><span style="font-size: small;">You cannot solve (1) for rotQ = vecA / vecB because a vector does not have an inverse. This limitation reflects the existence of an infinite number of rotations that carry vecB to vecA. However, there is a unique <i><b>smallest angle</b></i> rotation from vecB to vecA. llRotBetween(vecB, vecA) gives you this smallest rotation.</span></li>
<li><span style="font-size: small;">You may fall into serious logical trouble if you write expressions like vecA / rotP / rotQ because rotational / is not associative, that is (vecA/rotP)/rotQ != vecA*(rotP/rotQ).</span></li>
</ul>
<br />
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">For more discussion of the rules of rotational algebra consult any text book on computer graphics mathematics and seek the chapters on spatial rotation. If you consult non-CG text books you will discover the the rest of the world represents vectors as columns and uses left side rotational multiplication.</span></li>
<li><span style="font-size: small;">For a more formal discussion of non-commutative algebra read: <a href="http://www.springer.com/mathematics/algebra/book/978-1-84628-040-5">Introduction to Lie Algebra</a> by Erdmann and Wildon.</span></li>
</ul>
<br />
<ul style="font-family: Arial,Helvetica,sans-serif;"></ul>
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">A common bit of advice is to remark that
rotations are quaternions (they are not) and thus the inverse of rotQ
can be created using rotQ.s = -rotQ.s. LSL does indeed <i><b>represent</b></i> rotations by <a href="http://en.wikipedia.org/wiki/Quaternion">quaternions</a> and this technique does work. However, since the
LSL compiler translates the abstract expression "ZERO_ROTATION / rotQ" into the representation specific operations "tmp = rotQ; </span><span style="font-size: small;">tmp</span><span style="font-size: small;">.s = -</span><span style="font-size: small;">tmp</span><span style="font-size: small;">.s;", a laying-of-hands on the internals of a quaternion does not
make a script more efficient. </span></li>
</ul>
<ul style="font-family: Arial,Helvetica,sans-serif;">
</ul>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br />
<span style="font-size: small;"> [end]</span></div>desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-91956662225198713442012-06-19T08:58:00.000-07:002012-06-19T10:37:25.467-07:00A deed-once land media manager<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-size: small;">Consider this script fragment:</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"><br /></span></div>
<span style="font-size: small;"><span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">integer mediaChannel = -8782764;</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">key authorizedUser = "817b2981-aeb6-42db-9478-1d525624c66e"; </span><br style="font-family: "Courier New",Courier,monospace;" /><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">default</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">{</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">state_entry() {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llListen( mediaChannel, "", NULL_KEY, "" );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span><br style="font-family: "Courier New",Courier,monospace;" /><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">listen( integer channel, string fromName, key fromKey, string msg) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( (channel == mediaChannel) </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> && (llGetOwnerKey(fromKey)==(key)authorizedUser) ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> list a = llParseStringKeepNulls(msg,["|"], [] );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> string verb = llList2String(a,0);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> integer match = llListFindList(["setMedia", "queryMedia"],[verb]);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( match >= 0 ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> string tag = llList2String(a,1);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> integer n = (integer)llList2String(a,2);</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( n > 0 ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> list b = decodeList( llList2List(a,3,2+n) );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> if ( match == 0 ) { </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llParcelMediaCommandList( b );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llRegionSayTo(fromKey, mediaChannel, llDumpList2String( </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> [ verb+"Ack", tag, "ok" ], "|"));</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> } else if ( match == 1 ) {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> list c = encodeList ( llParcelMediaQuery(b) );</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llRegionSayTo(fromKey, mediaChannel, llDumpList2String(</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> [ verb+"Ack", tag, "ok",</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llGetListLength(c)] + c, "|"));</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> } else {</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> llRegionSayTo(fromKey, mediaChannel, llDumpList2String(</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> [ verb+"Ack", tag, "fail", "no list" ], "|"));</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> } </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> }</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">}</span></span></span><br />
<span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace; font-size: x-small;">} </span></span><br />
<div style="font-family: Arial,Helvetica,sans-serif;">
<br />
<span style="font-size: small;">If you add the encode/decode functions, place the script into a prim and then have that prim deeded to a parcel, then undeeded scripted objects </span><span style="font-size: small;">that are owned by the authorizedUser and </span><span style="font-size: small;">that send messages on the mediaChannel will be able to manage land media.</span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-size: small;"><br /></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-size: small;">If you are a land manager that hosts exhibits, then you can use this script to give your visiting exhibitors control of the land media without giving them the power to deed objects to the land.</span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-size: small;"><br /></span></div>
____________________________<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-size: small;">Notes:</span></div>
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li><span style="font-size: small;">The encodeList() and decodeList() functions are described in the prior post "Interobject Communications: lists".</span></li>
<li><span style="font-size: small;">Sending media commands and query reults as encoded lists in messages means that you will never have to add features to this script. If Linden Labs one day supports a new media action (PARCEL_MEDIA_COMMAND_whatever) then this script will already support that action. </span></li>
<li><span style="font-size: small;">The verb 'deed' it is shorthand for the longer, more awkward phrase
"deed to a group that owns the parcel or have the parcel owner rez on
the parcel". </span></li>
</ul>
<br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-66080902480331486222012-06-16T08:11:00.005-07:002012-06-17T13:04:29.325-07:00Rotation: pivot around a child prim<div style="font-family: Arial,Helvetica,sans-serif;">
Given that an a object can pivot around any point, an object can pivot around a child prim by pivoting around the global position of the child prim.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
Given these values:</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
vector gloVecObj -- the global position of the root prim of an object</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
rotation gloRotObj -- the global rotation of the root prim of an object </div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
vector locVecChild -- the local position of a child prim of an object</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
use this fundamental relation between positions and rotations represented in different frame of reference (cf. "Rotation: pivot around a point"):</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
(1) gloVecA = gloVecObj + locVecA * gloRotObj </div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
where A will be the child prim. Thus </div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
(2) gloVecChild = gloVecObj + locVecChild * gloRotObj </div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The calculation result of (2), gloVecChild, is the global vector of pivot point.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
____________________________</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
To script this in the root prim, note that </div>
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
vector gloVecObj = llGetPos();<br />
rotation gloRotObj = llGetRot();</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
and that for the child with link number 'link'</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
list a = llGetLinkPrimitiveParams( link, [ PRIM_POS_LOCAL ] );</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
vector locVecChild = llList2Vector( a, 0 );</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br />
The post "Rotation: pivot around a point" describes how to use this value to perform the pivoting.<br />
<br /></div>
<span style="font-family: Arial,Helvetica,sans-serif;">[end]</span>desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-23806817673024676582012-06-07T18:41:00.000-07:002012-06-08T08:08:35.802-07:00Rotation: pivot around a pointFor this discussion there will be two frames of reference: global and local, local being the frame of reference attached to an object's root prim. Any position can be represented as a vector in either the global or local frame. In this specific problem, rotations are always represented in the global frame.<br />
<br />
The object has a starting global position and rotation and an ending global position and rotation. There is a global pivot position. The algebraic problem to solve is as follows: Given the pivot position, the starting position, the starting rotation and the ending rotation, determine the ending position.<br />
<br />
The specific relationship for solving this specific problem is that "to pivot about" means that the local vector of the pivot point does not change.<br />
<br />
The general relationship for solving all rotation problems is that for any position, A, a rotation transforms a local vector into global vector in this manner:<br />
<br />
(1) gloVecA = gloVecObj + locVecA * gloRotObj <br />
<br />
____________________________<br />
Represent the beginning and ending positions and rotations of the object by:<br />
<br />
gloVecObjBeg and gloVecObjEnd<br />
gloRotObjBeg and gloRotObjEnd<br />
<br />
The global position of the pivot point does not change. Represent it by: <br />
<br />
gloVecPivot<br />
<br />
By the meaning of "to pivot about" the local position of the pivot point also does not change. Represent it by:<br />
<br />
locVecPivot<br />
<br />
The local and global pivot positions are related by the general equation (1):<br />
<br />
(2) gloVecPivot = gloVecObjBeg + locVecPivot * gloRotObjBeg <br />
(3) gloVecPivot = gloVecObjEnd + locVecPivot * gloRotObjEnd <br />
<br />
<br />
Equations (2) and (3) will solved for the local pivot vector which will be elimiated by equating. The resulting equation will be solved for gloVecPivotEnd in terms of the other known variables.<br />
<br />
___________________________________<br />
Step A) Solve (2) and (3) for the local vectors<br />
<br />
(4) locVecPivot = ( gloVecPivot - gloVecObjBeg ) /gloRotObjectBeg<br />
(5) locVecPivot = ( gloVecPivot - gloVecObjEnd ) / gloRotObjectEnd<br />
<br />
Step B) Equate the right side expressions of Equations (4) and (5)<br />
<br />
(6) ( gloVecPivot - gloVecObjBeg ) / gloRotObjBeg <br />
= ( gloVecPivot - gloVecObjEnd ) / gloRotObjEnd<br />
<br />
Step C) Multiple both sides of (6) by gloRotObjectEnd
<br />
<br />
(7) ( ( gloVecPivot - gloVecObjBeg ) / gloRotObjBeg ) * gloRotObjEnd<br />
= gloVecPivot - gloVecObjEnd <br />
<br />
Step D) Rearrange (7) to isolate gloVecObjectEnd<br />
<br />
(8) gloVecObjEnd = gloVecPivot<br />
- ( ( gloVecPivot - gloVecObjBeg ) / gloRotObjBeg ) * gloRotObjEnd
<br />
<br />
__________________________________<br />
To script this, note that<br />
<br />
gloVecObjBeg = llGetPos();<br />
gloRotObjBeg = llGetRot();<br />
<br />
and that the script knows gloVecPivot and that the script has calculated a value for gloRotObjEnd.<br />
<br />
After using equation (8) to calculate gloVecObjEnd, the script will change the postion and rotation of the object:<br />
<br />
llSetPrimitiveParams( [ PRIM_POSITION, gloVecObjEnd,<br />
PRIM_ROTATION, gloRotObjEnd ] );<br />
<br />
___________________________<br />
Notes:<br />
<ul>
<li>The labeling of variables is complex in this problem because it is essential to keep track of the frame of reference of any vector or rotation value.</li>
<li>Do not invert the order of rotations in equation (8).</li>
<li>Use llSetPrimitiveParameters() to avoid seeing the object shift and rotate in two steps.</li>
</ul>
<br />
[end] <br />
<br />desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-9531843997284407582012-06-07T13:29:00.002-07:002014-03-25T06:46:00.591-07:00Interobject Communications: listsLists contain values of varying types. If llDumpListString() is used to create a text string which is to be sent as a message, then the value type information is irretrievably lost.<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
Preserve the type information by creating a new list in which the type code precedes each value. The sender might have code like this:</div>
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list a = [ ... some series of values ];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list b = encodeList(a);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llSay( commChannel, llDumpList2String( [ "listData", llGetListLength(b) ]</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> encodeList(b) + ["END"] , "|" );</span></div>
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
The receiver might have code like this</div>
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">listen( integer channel, string fromName, key fromKey, string msg ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list f = llParseStringKeepNulls( msg, "|" );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( "listData" == llList2String(f,0) ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( "END" != llList2String(f,-1) ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> ... tell some that the message has been truncated</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer n = (integer) llList2String(f,1);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list dataList = [];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( n > 0 ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> dataList = decode( llList2List( f, 2, 1 + n );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> n = llGetListLength(dataList); </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> ........</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">}</span></div>
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
The encoder logic might be this</div>
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">list typeList = [TYPE_FLOAT, TYPE_INTEGER, TYPE_KEY, </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> TYPE_ROTATION, TYPE_STRING, TYPE_VECTOR ];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<br /></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">list encodeTypeList( list a ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list b = [];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer n = llGetListLength(a);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer k; for ( k=0; k < n; k++ ) {</span><br />
<span style="font-size: x-small;"> integer type = llGetListEntryType(a,k);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer match = llListFindList( typeList, [type] );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match >= 0 ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> b += [type] + llList2List(a,k,k);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else llOwnerSay("** failed to match list entry type: "+(string)type);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> return b;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">}</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"><br /></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The decoder logic might be this:</div>
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">list decodeTypeList( list a ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list b = [];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer n = llGetListLength(a);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer k; for ( </span><span style="font-size: x-small;">k=0; k < n; k += 2 )</span><span style="font-size: x-small;"> {</span><br />
<span style="font-size: x-small;"> integer type = (integer) llList2String(a,k);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> string svalue = llList2String(a,k+1);</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer match = llListFindList( typeList, [type] );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match >= 0 ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += (float) svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += (integer) svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += (key) svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += (rotation) svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match-- == 0 ) b += (vector) svalue;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> return b;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">}</span></div>
<br />
__________________<br />
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
Notes:</div>
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li>When sending variable length lists, append "END" to the end of the message and have the receiver verify that it is still there. There is a limit to the length of messages.</li>
<li>Include the encoded list length in the message, so that the receiver can extract the list.</li>
<li>Since lists may have zero length, the receiver should handle the zero length case.</li>
</ul>
<div style="font-family: Arial,Helvetica,sans-serif;">
[end]</div>
desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-79044448754492352962011-10-18T11:04:00.000-07:002012-06-07T13:49:27.668-07:00Interobject Communication<span style="font-size: small;"></span><span style="font-size: small;">The behaviors of several objects can be coordinated by having them exchange information using private chat protocols. One object emits chat using llRegionSay(). Another object has a listen() event which receives messages on the same channel.</span><br />
<span style="font-size: small;"><br /></span><br />
<span style="font-size: small;">The sender would have code like this</span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">integer commChannel = -837465; </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">... </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llRegionSay( commChannel, "start");</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">...</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"><br />
</span></div>
<span style="font-size: small;">The receiver </span><span style="font-size: small;">would have</span><span style="font-size: small;"> code like this </span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">integer commChannel = -837465; </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">default { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> state_entry() {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llListen( commChannel, "", NULL_KEY, "");</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> listen( integer channel, string fromName, </span><br />
<span style="font-size: x-small;"> key fromKey, string msg ){</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( msg == "start" ) { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llSay(PUBLIC_CHANNEL, "'"+fromName+"' says start"); </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else if ( msg == "stop" ) { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llSay(PUBLIC_CHANNEL, "'"+fromName+"' says stop"); </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;">}</span></div>
<span style="font-size: small;">____________________</span><br />
<span style="font-size: small;">Communication often consists pairs of messages that comprise a transaction. For a ping-pong transaction which allows one object to find many other objects, the receiver </span><span style="font-size: small;">would have </span><span style="font-size: small;">code like this</span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> listen( integer channel, string fromName, key fromKey, </span><br />
<span style="font-size: x-small;"> string msg ){</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer match = llListFindList( </span><br />
<span style="font-size: x-small;"> [ "start", "stop", "ping" ], [msg] );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match == 0 ) { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> .... </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else if ( match == 1 ) { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> ....</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else if ( match == 2 ) {</span><br />
<span style="font-size: x-small;"> llRegionSayTo( fromKey, commChannel, "pong" ); </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span> </div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<span style="font-size: small;"><br /></span><br />
<span style="font-size: small;">The receiver knows that the pong should go back to the emitter of the ping. Therefore the pong emitter may use llRegionSayTo() to send the message to a specific object.</span><br />
<span style="font-size: small;"><br /></span><br />
<span style="font-size: small;">The pinger code would include a listen handle that receives the pong message. To make a list of responder keys it could have code like this:</span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list pongerKeyList = [];</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"><br /></span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> listen( integer channel, string fromName, </span><br />
<span style="font-size: x-small;"> key fromKey, string msg ){</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> integer match = llListFindList( [ "pong" ], [msg] );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( match == 0 ) { </span></div>
<span style="font-family: "Courier New",Courier,monospace; font-size: x-small;"> pongerKeyList += fromKey;</span><br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span> </div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<span style="font-size: small;">____________________</span><br />
<span style="font-size: small;">The receiver of a message can extract substantial information from the key of the sender using llGetObjectDetails(). </span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: small;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> listen( integer channel, string fromName, </span><br />
<span style="font-size: x-small;"> key fromKey, string msg ){</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( msg == "pong" ) { </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list a = llGetObjectDetails( fromKey, </span><br />
<span style="font-size: x-small;"> [ OBJECT_NAME, OBJECT_OWNER, </span><br />
<span style="font-size: x-small;"> OBJECT_POS, OBJECT_ROT ] );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llSay(PUBLIC_CHANNEL, "pong response: "+llList2CSV(a));</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<span style="font-size: small;">____________________</span><br />
<span style="font-size: small;">Messages carry additional information by concatenating values using a special character pattern which does not appear within any values. The message sender uses llDumpList2String() to build the message. The receiver used llParseStringKeepNulls() to separate the message into a list of string fields. These string fields are converted back into values using casts. </span><span style="font-size: small;">The ping sender would have code like this:</span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> </span><span style="font-size: x-small;">touch_start( integer nTouch ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> float jitterPongMax = 4; <br /> llRegionSay( commChannel, llDumpList2String(<br /> [ "ping", </span><span style="font-size: x-small;">jitterPongMax </span><span style="font-size: x-small;">, llGetUnixTime(), </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> llGetPos() ], "|"));<br /> } </span></div>
<span style="font-size: small;"><br /></span><br />
<span style="font-size: small;">The ping receiver/pong sender would have code like this:</span><br />
<span style="font-size: small;"><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace; font-size: x-small;"> listen( integer channel, string fromName, </span></span><br />
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"><span style="font-size: x-small;"> key fromKey,</span> string msg ){</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> if ( channel == commChannel ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> list a = llParseStringKeepNulls( msg, ["|"], [] );</span><span style="font-size: x-small;"> </span><br />
<span style="font-size: x-small;"> string verb = llList2String(a,0);</span><br />
<span style="font-size: x-small;"> integer match = llListFindList( </span><br />
<span style="font-size: x-small;"> [ "start", "stop", "ping" ], [verb] ); </span><br />
<span style="font-size: x-small;"> if ( match == 0 ) {</span><br />
<span style="font-size: x-small;"> ... </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } else if ( match == 1 ) {</span><span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> } else if ( match == 2 ) { </span><br />
<span style="font-size: x-small;"> float jitterMax = (integer)llList2String(a,0);</span><span style="font-size: x-small;"> </span><br />
<span style="font-size: x-small;"> integer sendTime = (integer)llList2String(a,1);</span><span style="font-size: x-small;"> </span><br />
<span style="font-size: x-small;">
</span><span style="font-size: x-small;"> vector pingerPos = (vector) </span><span style="font-size: x-small;">llList2String(a,3);</span><span style="font-size: x-small;">
</span><span style="font-size: x-small;"> </span><br />
<span style="font-size: x-small;"> llSleep( llFrand(</span><span style="font-size: x-small;">jitterMax </span><span style="font-size: x-small;">) ); <br />
</span><br />
<span style="font-size: x-small;"> llRegionSayTo( fromKey, commChannel, "pong" ); </span><br />
<span style="font-size: x-small;">
</span><span style="font-size: x-small;"> </span><span style="font-size: x-small;">....</span><span style="font-size: x-small;"> } </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> } </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="font-size: x-small;"> }</span></div>
<div style="font-family: Times,"Times New Roman",serif;">
<span style="font-size: small;">____________________</span><br />
<span style="font-size: small;">Notes:<br />
</span><br />
<ul>
<li><span style="font-size: small;">If your system will be deployed across region boundaries, then use llShout(), which has a range of 100 meters.</span></li>
<li><span style="font-size: small;">If the messages pass between one agent's attachments, use llWhisper(), which has a range of 10 meters.</span></li>
<li><span style="font-size: small;">In the last example llSleep(llFrand(jitterMax)) prevents all the pongers from responding at the same time. There are limits to how many messages can be queued by a region.</span></li>
<li><span style="font-size: small;">llParseStringKeepNulls() is used because string values may be zero length strings.</span></li>
<li><span style="font-size: small;">llListFindList() and subsequent integer comparisons is more efficient that a series of string comparisons.</span></li>
</ul>
<span style="font-size: small;">Revised 6Jun2012</span></div>
<span style="font-size: small;">[end]</span>desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-47721349817834015392011-02-12T11:08:00.000-08:002012-06-07T13:48:04.943-07:00Uniform Motion Using llMoveToTarget<div style="font-family: inherit; text-align: left;">
<div style="text-align: left;">
<span style="font-size: small;">When an object is physical, the script function</span></div>
<div style="text-align: center;">
<br />
<img src="http://latex.codecogs.com/gif.latex?%5Cbg_black%20%5Cfn_phv%20llMoveToTarget%28%20vector%20%5Cvec%7Bd%7D%29,%20float%20%5Ctau%20%29;" title="\bg_black \fn_phv llMoveToTarget( vector \vec{d}), float \tau );" /><br />
<br />
<div style="text-align: left;">
<span style="font-size: small;">causes an object to drift smoothly toward a target position. The drawback is that the motion is not uniform. The velocity decreases toward zero as the target is approached.</span></div>
<span style="font-size: small;"><span style="font-size: xx-small;"> </span></span></div>
<div style="font-family: inherit;">
This movement is approximated by<br />
<br />
<div style="text-align: center;">
<img src="http://latex.codecogs.com/gif.latex?%5Cbg_black%20%5Cfn_phv%20%5Cvec%7Bp%7D%28t%29%20-%20%5Cvec%7Bp%7D%280%29%20=%20%28%20%5Cvec%7Bd%7D%20-%20%5Cvec%20%7Bp%7D%280%29%20%29%20%28%201%20-%20%5Cexp%20%7B%28-%20t%20/%20%5Ctau%29%20%7D%29" /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="font-family: inherit; text-align: left;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVgJV98vy_hSKT2FAPv3MHTrL5t9RbLYxfVBSzw92h-620bro1knFTH3ZEVsepg-L9pP19E4ZNnyN9n3S6vSqccY8haL9XLKy7USFYdRhpNyTRMjyJ0MdpbSFHHj16Q_WLtCXMoRQyX9Xi/s1600/expsplot.bmp" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVgJV98vy_hSKT2FAPv3MHTrL5t9RbLYxfVBSzw92h-620bro1knFTH3ZEVsepg-L9pP19E4ZNnyN9n3S6vSqccY8haL9XLKy7USFYdRhpNyTRMjyJ0MdpbSFHHj16Q_WLtCXMoRQyX9Xi/s320/expsplot.bmp" width="320" /></a></div>
<br />
<span style="font-size: small;">The object is at position <img src="http://latex.codecogs.com/gif.latex?%5Cinline%20%5Cbg_black%20%5Cfn_phv%20%5Cvec%20%7Bp%7D%28t%29" title="p is vector position, t is time" /> at time t. Because of the exponential attenuation of the velocity, it will reach the position <img src="http://latex.codecogs.com/gif.latex?%5Cinline%20%5Cbg_black%20%5Cfn_phv%20%5Cvec%20%7Bd%7D" title="d is vector target position" /> after several intervals of the time interval <img src="http://latex.codecogs.com/png.latex?%5Cinline%20%5Cbg_black%20%5Ctau" />. </span><br />
<br />
<span style="font-size: small;"><span style="font-size: xx-small;"><strike> </strike> </span> </span><br />
<span style="font-size: small;">The object motion is made more uniform by using only an early portion of this exponential motion.</span></div>
<div style="font-family: inherit; text-align: left;">
<div style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAmBiS-0vOBf2OkI-dhZwzv-rNbvG-YbKBSysAFWjDsbPul_E4UpYpHAAb_hMfE2fBWHIYlsG5Rx9Kh-HKgedzr_4RuTbnc4JOiiednROk-MyUnhWLuEuEs1q6e7fPCq5dTyHkKcwPuZsG/s320/expsplot2.bmp" width="320" /></div>
<br />
To create this effect, calculate a target <span style="font-size: small;">position</span><span style="font-size: small;"> <img src="http://latex.codecogs.com/gif.latex?%5Cinline%20%5Cbg_black%20%5Cfn_phv%20%5Cvec%20%7BD%7D" /> which lays beyond </span><span style="font-size: small;"><img src="http://latex.codecogs.com/gif.latex?%5Cinline%20%5Cbg_black%20%5Cfn_phv%20%5Cvec%20%7Bd%7D" />, then </span><span style="font-size: small;">terminate the movement at the time</span><span style="font-size: small;"> <img src="http://latex.codecogs.com/png.latex?%5Cinline%20%5Cbg_black%20%5Ctau" />. In algebraic terms, solve this equation for </span><span style="font-size: small;"> <img src="http://latex.codecogs.com/gif.latex?%5Cinline%20%5Cbg_black%20%5Cfn_phv%20%5Cvec%20%7BD%7D" />:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div style="margin-left: 1em; margin-right: 1em;">
</div>
<div style="margin-left: 1em; margin-right: 1em;">
<img src="http://latex.codecogs.com/png.latex?%5Cinline%20%5Cbg_black%20%5Cvec%7Bd%7D%20-%20%5Cvec%7Bp%7D%280%29%20=%20%28%5Cvec%7BD%7D%20-%20%5Cvec%7Bp%7D%280%29%29%281%20-%20%5Cexp%7B%28-%5Ctau%20/%20%5Ctau%20%29%7D%29" title="t replaced with tau, p(t) replaced with d, d replaced with D" /></div>
<br />
The solution is <br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="margin-left: 1em; margin-right: 1em;">
<img src="http://latex.codecogs.com/png.latex?%5Cinline%20%5Cbg_black%20%5Cvec%7BD%7D%20=%20%5Cvec%7Bp%7D%280%29%20+%20%28%20%5Cvec%7Bd%7D%20-%20%5Cvec%7Bp%7D%280%29%29%28%20e%20/%20%28%20e%20-%201%29%29" title="\inline \bg_black \vec{D} = \vec{p}(0) + ( \vec{d} - \vec{p}(0))( e / ( e - 1))" /></div>
<br />
<div style="font-family: inherit; text-align: left;">
where e is the base of the natural logarithms, <span style="white-space: nowrap;">2.71828<span style="margin-left: 0.25em;">18284</span></span><span style="white-space: nowrap;">....</span><br />
<br />
<span style="font-size: small; white-space: nowrap;"> </span><span style="font-size: small;"><span style="font-size: xx-small;"><strike> </strike> </span></span><br />
<span style="font-size: small;">For a target position </span><span style="font-size: small;">d_target</span><span style="font-size: small;">, a single step movement is shown below as code fragments.</span><br />
<br />
<span style="white-space: nowrap;"><span style="font-family: "Courier New",Courier,monospace;">float tau = 4;</span></span><div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">vector d_target = <110,200,30>;</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">float e = </span><span style="white-space: nowrap;">2.7182818284;</span><br />
<span style="white-space: nowrap;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">touch_start( integer nTouch ) {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> float f = e / ( e - 1 ); </span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> </span><span style="white-space: nowrap;">vector D_target = llGetPos() + f *( d_target - llGetPos() );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> </span><span style="white-space: nowrap;">llMoveToTarget( D_target, tau );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> </span><span style="white-space: nowrap;">llSetTimerEvent( tau );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">}</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"><br />
</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">timer() {</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> llStopMoveToTarget();</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;"> </span><span style="white-space: nowrap;">llSetTimerEvent( 0 );</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<span style="white-space: nowrap;">}</span></div>
<div style="font-family: "Courier New",Courier,monospace;">
<br />
<span style="font-size: small;">A more nuanced implementation would declare a list of
d_target positions. The timer event would move thought the list,
calculating a series of D_targets, then using llMoveToTarget(). At the
end of the list, the timer event would either return to the beginning of
the list, or use llStopMoveToTarget().</span><br />
<br />
<span style="font-size: small;"> </span><br />
<i>Des.de.mona</i><br />
<br />
[end]</div>
<div style="font-family: "Courier New",Courier,monospace;">
<br />
<br />
<span style="font-size: small;"></span></div>
</div>
<div style="font-family: inherit; text-align: left;">
<span style="font-size: small;"><i> </i></span></div>
</div>desdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.comtag:blogger.com,1999:blog-6717499955749003191.post-5822466756591375532011-02-07T10:17:00.001-08:002011-02-11T09:35:01.766-08:00Embedding EquationsGiven that blogspot does not intrinsically support equations, I am experimenting with the <a href="http://en.wikipedia.org/wiki/LaTeX">LaTeX</a> converter found at <a href="http://www.codecogs.com/">codecogs</a>. <br />
<br />
<div style="text-align: center;"><img height="22" src="http://latex.codecogs.com/gif.latex?%5Cbg_black%20%5Cfn_phv%20llMoveToTarget%28%20%5Cvec%7Bp%7D,%20%5Ctau%20%29" title="\bg_black \fn_phv q = llMoveToTarget( \vec{p}, \tau )" width="200" /></div><br />
<div style="text-align: center;"></div><div style="text-align: center;"><img src="http://latex.codecogs.com/gif.latex?%5Cbg_black%20%5Cfn_phv%20%5Cvec%7BF%7D_g=-F%5Cfrac%7Bm_1%20m_2%7D%7Br%5E2%7D%20%5Cvec%7Be%7D_r" title="\bg_black \fn_phv \vec{F}_g=-F\frac{m_1 m_2}{r^2} \vec{e}_r" /></div><br />
<div style="text-align: center;"></div><div style="text-align: center;"></div><div style="text-align: center;"></div><div style="text-align: center;"></div><div style="text-align: center;"><img src="http://latex.codecogs.com/gif.latex?%5Cbg_black%20%5Cfn_phv%20%5Cfrac%7Bd%7D%7Bdx%7D%5Cln%28x%29=%5Cfrac%7B1%7D%7Bx%7D" title="\bg_black \fn_phv \frac{d}{dx}\ln(x)=\frac{1}{x}" /></div><br />
While this relies on the continued existence of the codecogs website, the countervailing advantage of this method is that the LaTeX input statement used to generate an equation becomes embedded in the web page. For example, if you look at the source of this web page, you will see that the above equation for the derivative of the natural logarithm is generated using this statement:<br />
<br />
<div style="text-align: center;">\frac{d}{dx}\ln(x)=\frac{1}{x}</div><br />
Should codecogs cease to exist, the LateX input statement has been preserved and may be used with any converter to regenerate the typeset image. As for LaTeX itself, it is one of those Unix things that has been around for 30 years and is now distributed under the LaTeX Project Public License.<br />
<br />
Des.de.monadesdemona enfieldhttp://www.blogger.com/profile/03770253946320850388noreply@blogger.com