QRコード
QRCODE
アクセスカウンタ
読者登録
メールアドレスを入力して登録する事で、このブログの新着エントリーをメールでお届けいたします。解除は→こちら
現在の読者数 0人
オーナーへメッセージ
slMame › 一日一膳腹八分目

  

Posted by at
2011年09月21日

llCastRay()実装

されたみたいですね。
和訳がまだないようですので簡単にまとめておきます。


list llCastRay( vector start, vector end, list options )



リージョン座標startからendを結ぶ直線上を調査して、検出されたオブジェクト、アバター、地面等について、optionsで指定された属性とUUIDと座標をlistで返します。
また、戻りリストの末尾はエラーコードまたは検出された物の数となります。
末尾の数(integer)が負の値の場合は、以下の意味となります。

RCERR_UNKNOWN(-1)
理由が分かりませんがエラーです。バグレポートをリンデンに送りましょう。

RCERR_SIM_PERF_LOW(-2)
SIMが重すぎて実行できませんでした。

RCERR_CAST_TIME_EXCEEDED(-3)
地区やアバターで許されている実行用のリソースが使い切られていて実行できませんでした。
少し時間を空けると実行できるようになります。


オプション設定


RC_REJECT_TYPES
無視するものを以下のフラグのビット和( | )で指定できます。
RC_REJECT_AGENTS アバターを無視します
RC_REJECT_PHYSICAL 物理プリムを無視します
RC_REJECT_NONPHYSICAL 通常プリムを無視します
RC_REJECT_LAND 地面を無視します

RC_DATA_FLAGS
取得するデーターにいくつかの追加、変更を行えます。以下のフラグのビット和( | )で指定できます。
RC_GET_NORMAL 検出地点(プリムの表面で起こります)の法線ベクトル(面に垂直な単位ベクトル)を追加して返します。
RC_GET_ROOT_KEY 指定すると検出したプリムのリンクセットのルートプリムのUUIDを返します。デフォルトでは検出したプリムそのもののUUIDが返ります。
RC_GET_LINK_NUM 指定するとそのリンクセットのプリム数を追加して返します。

戻るlistの値は、

指定なし
[uuid , 検出されたプリム表面のリージョン座標 , ・・・・・・,検出した数]

RC_GET_LINK_NUMを指定
[uuid , リンク数 , 検出されたプリム表面のリージョン座標 , ・・・・・・,検出した数]

RC_GET_NORMALを指定
[uuid , 検出されたプリム表面のリージョン座標 , 法線ベクトル , ・・・・・・,検出した数]

RC_GET_LINK_NUMとRC_GET_NORMALを指定
[uuid , リンク数 , 検出されたプリム表面のリージョン座標 , 法線ベクトル , ・・・・・・,検出した数]

と並びます。検出したオブジェクトが複数の場合の、飛び石リストの並び順はstartからendへ向かう順になっているようです。(※地面にあたるとNULL_KEYが入るのでしょうか。また、地面の中からスタートするとNULL_KEYは入らずのようです。同様にプリムの中からスタートするとそのプリムは無視するのかもしれません。)


RC_MAX_HITS
ヒットさせる最大数を指定します。デフォルトは1で、出来るだけ小さい数が当然望ましいらしいです。


RC_DETECT_PHANTOM
TRUEを指定するとファントムとVolume Detectプリムを検出の対象にするようになります。



という感じみたいです。
これ、斜面でも斜面に沿って足を下ろす、ちゃんと歩行して見える乗り物が作れますね。。(笑
あんまり激しく使うとすぐエラー-3が返ってきますが・・・  


Posted by RBK Drachnyd(しお) at 20:59Comments(6)忘れない為に。。
2011年07月15日

LSLEditor勝手に改造版


待てど暮らせど本家が追加された関数や定数に対応してくれないので、4月ごろに7月17日付9月22日付で改造しました。
改造というほどのものでもありませんが。。^^;
しばらく使ってみて特に問題なさそうですので、欲しい方はどうぞ。
現在のlsl wikiでIマークがついていないllCastRay()以外の実装関数と定数類は全て網羅してあります(はずです^^; 足りないものを見かけられたらご一報ください)。

http://www.tam.ne.jp/rbk/lslEditor/LSLEditor.exe
不足関数、定数等追加しました。

ウィルスチェックは自己責任でお願いいたします。チェックしておりません。
圧縮ファイルやインストーラーではなく、そのまま実行ファイルですので、既存のフォルダ内の同じファイルを上書きしてください。
バージョン数字勝手に修正しています。(本家更新がかかった場合にバージョン番号が変わりますので、自動アップデート機能は一応ONのままを推奨いたします。どうにも望み薄の気配ですが・・)
デバッグ機能(F5キー)は意味がないのと対応させていませんのでキーショートカットもメニューも殺してあります。構文チェック(F6キー)は実装させています。
ちょっとだけ日本語に表記を書き換えました。


本家公開版はこちら。
http://www.lsleditor.org/

ソース取得元はこちら。
http://sourceforge.net/projects/lsleditor/files/Source/

同じsourceforgeサイト内にコミュニティエディションのβ版がバイナリーで置いてありますが、試してみましたところソリューションが消えてしまうバグがまた発生していて、落雷などの時にちょっとドキドキする事になります。^^; 改造元の2.40では、突然終了してもソリューションが消えることはありませんでした。


LSLEditorはGPL2ライセンスです。
改変後ソースが何が何でも必要な方はIM等でご一報ください。いらないと思いますが。。w  


Posted by RBK Drachnyd(しお) at 15:52Comments(5)小物
2011年05月14日

モーション制作スクリプト完成♪

作動の原理は特に珍しいものではありませんが、製品としてこのタイプが出ているのを見たことがありませんので、商品化前提で作成したアニメーション作成ツールの作動テストの様子です。
海外の人も見れば性能の程度が分かる様にと、スターウォーズから。

All Terrain Armored Transport(AT-AT)
The Empire Strikes Back



QAvimatorの様に関節の連結関係を持たせることが出来、設定中部品を動かすと、それにぶら下がっている部品も連動して動くようにしてあります。この仕様は大正解でした。これ以外に3種類テストオブジェクトを作成しましたが、アニメ記録の手間は単純に手足の本数に依存する単純作業でした。。(笑
モーションはキーフレームの指定を行えば良く、キーフレーム間の中間姿勢は計算で自動補間するようにしてあります。計算原理は戦車砲と同じで、関節の親子関係が連なっても大丈夫に汎化されているだけです。上の動画の場合で、ルート(赤色の箱)からフットパッドまでの間に関節が6段はさまっています。

物理に組み込めるものかはよく分かりません。動画のオブジェクトは坂にさしかかってもめり込んでいくだけですから、正確にはFT-AT(平地専用装甲車)です。(笑)

今回記憶させたキーフレームは19で、だらだらと作っていたため正確な時間は分かりませんが、述べで作業時間は8時間ほどでしょうか。足一本を前に踏み出すのに40分~1時間程度かかっています。

クリエイターさんやアーティストの表現の枠が広がればいいなと思いますので、発売の際には価格も少し低めに設定しようかと思いますが、それより前に、最近のスクリプト改変でこういう事も出来るようになっています、というお知らせ程度に。。。  


Posted by RBK Drachnyd(しお) at 22:26Comments(1)作成物/製品
2011年04月07日

NNさんのスカルプ製造機が良いです




ご存じShop NN様の、「Prim Generator」が非常に良いです。今日存在を知りました。(そして即決で買いました。。普段はお財布のひもはカタ結びした上に水で濡らしてあるのですが。。(笑))

操作はこちらも有名なS2様のプリムオーブンをほぼそのまま踏襲していて、通常プリムを配置していってボタン一発の簡単操作なのですが、生成がより強化されていて中空やひねり等の諸元もかなりの所までOKで、32プリムまで配置可能などなど、大幅に性能強化されています。



http://maps.secondlife.com/secondlife/Terriergate/22/216/23  


Posted by RBK Drachnyd(しお) at 20:51Comments(0)お店紹介
2011年01月08日

Visual C# スキャナーから画像を取り込み

あけましておめでとうございます。今年もよろしくお願い申し上げます。m(__)m

すぐ忘れるので自分用のメモです。。^^;
「スキャナで取り込んだ画像をイチイチ保存してからUPするのは面倒くさいから、勝手にするようにしてくれないか?」というワガママなRLお客様のご注文の為に。。(笑

Windows Imaging Acquisitionを参照設定に追加してから、要するに基本は以下の通りでした。。


using WIA;


public partial class Form1 : Form
{
public Form1(string[] args)
{
InitializeComponent();
(以下、なんだか色々)
}


private void scan()
{
WIA.CommonDialog dlg = new WIA.CommonDialog();
ImageFile Image = dlg.ShowAcquireImage(WiaDeviceType.ScannerDeviceType,
             WiaImageIntent.ColorIntent, WiaImageBias.MaximizeQuality,
             "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}", true, true, true);
string p = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
System.IO.File.Delete(p + @"\tmp.bmp");
Image.SaveFile(p + @"\tmp.bmp");
}



}


ImageFile.SaveFile()メソッドは同名ファイルがあると例外をスローする様ですので、先に消しておくくらいでしょうか。。

LSLでところてんになった頭でたま~にWindowsアプリを作ろうとすると、ほんっとに今の環境はなんでも考えずに出来ますね。。メモリーは馬鹿みたいにありますしCPUは遊んでますし。。^^;
我ながら子供の遊びレベルです。。  


Posted by RBK Drachnyd(しお) at 22:56Comments(0)忘れない為に。。
2010年11月26日

Captive Balloon

Captive Balloon



28日で終わってしまいますが、Art exhibition『Captive Balloon~捕らわれた気球』に行ってまいりました。

元々個人的に現代アートは積極的に嫌いで、美観が少々骨董品なのですが、これは本当に素晴らしいと思いました。

スナップショットはダメだと思います。ので、全景だけ、草葉の陰からです。。(笑


Art exhibition『Captive Balloon~捕らわれた気球』
http://slurl.com/secondlife/Luminosita/54/220/21

  


Posted by RBK Drachnyd(しお) at 01:38Comments(0)お店紹介
2010年11月17日

スクリプト 残酷な電子のテーゼ


原曲
必ず再生しながら読んでください。

http://www.youtube.com/watch?v=B8k3pKHwJDI




残酷な電子のように。。
少年よ 神話になれ。。。。

赤いログがいま 君の胸を叩いても
私だけをただ見つめて うろたえてるあなた。。
そこに見えるもの かみくだくのに夢中で
運命さえまだ知らない いたいけな瞳。。。(-_-+

だけどいつか気付くでしょう そのスクリには
遥か地獄 おちるための ”穴”があること。。

残酷な電子のテーゼ 窓辺からやがて飛び立つ
ほとばしる赤いエラーで 君の意を裏切るなら
そのバグを抱いて輝き
少年よ 神話になれ



(葬送)



ずっと眠ってる。。。私の中の爆弾(ゆりかご)。。。
あなただけが それのシ者に 呼ばれる時がくる。。。
”細い道筋”を 月あかりが示してる。。
世界中の時を止めて 閉じこめたいけど。。。(;_;/~

もしもそれに”逢えた”ことに 意味があるなら
私はそう パスタを 知るためのバイブル

残酷な電子のテーゼ 悲しみがそしてはじまる
抱きしめた論理のかたち その無理(ゆめ)に目覚めたとき
誰よりも光を放ち
少年よ 神話になれ

君はバグをつむぎながら 私をつくる
メジャーなんてなれないまま 私は生きる

残酷な電子のテーゼ 窓辺からやがて飛び立つ(I'm a bird.. I can fly..!)
ほとばしる赤いエラーで 君の意を裏切るなら
そのバグを抱いて輝き
少年よ 神話になれ






貴方の事を箱の中の人から見ますと、多分、このように見えるでしょう。。  


Posted by RBK Drachnyd(しお) at 00:36Comments(0)雑記
2010年10月10日

秋祭り開催中(lsl+α:任意形状のあたり判定をする)

硬い話になる前に..
Arts Style SIMで開催中の秋祭りです。(10/17日で終了しました)
このブログのネタになっている屋台ははっきり申しまして陰険極まりない代物(末尾参照)ですが、残りの14台は必見です。


SIM景観をデザインされたRocket BiedermannさんとLieza Noelさんによる屋台はもちろん、ArtsStyle(味噌猫自動車?)のTwinker Tellingさん以下、下野町町内会の皆様が豪華に協賛されています。

場所はこちらです。着地点より順路案内にそって進んでください。





さて。。
出品中のかたぬき屋台の抜き判定に使った線上・外側・内側の判別方法です。
二つ作り、結局設定が楽なので後者を利用しました。





1:ベクトルを使う判定方法


3Dゲームの当たり判定に使われている方法です。SLでは住居のセキュアシステムで立方体範囲の検出に使われている物です(と思います)。

下図の様に、目的の領域を線分で囲んだとき、全ての線分から見て必ず内側にある任意の点Oを一つ用意します。
この時、線分から垂直なベクトルでOが終点であるようなベクトルVOを用意すると、内側か外側か線上か試したい点Pと線分の始点または終点を結んだベクトルVPは以下の関係になります。

1:VPとVOの内積が正⇒点Pは中心側
2:VPとVOの内積がゼロ⇒点Pは線上
3:VPとVOの内積が負⇒点Pは中心と逆側




コの字型のように「どの辺から見ても中心であるような点」がない場合には、複数の中の点Oを用意して、図形を分割してやる必要がありますが、上の図の用に中の点Oが共有できるすべての辺とOの内積を取って符号を見て、全部正なら内側、一つでも0なら線上、一つでもマイナスなら外側として、任意の点とのあたり判定を取ることが出来ます。線分に直交するベクトルで中の点Oの方を向いている物を使っても同じ関係になります。
立体で行う場合も関係は同じで、その場合は面に垂直で中の点Oの方を向いているものを採用します。
かたぬきの図形のように曲線で構成されている物の場合は曲線に内接する多角形と外接する多角形を用意して調べることになります。作るだけ作り、設定が面倒ですみやかに挫折しました。(笑


2:塗りつぶしを使う判定方法


大昔の2Dゲームでドットの重なりで判定していた方法です(と、思います)。
元の画像の内側、外側(ないし線上)など、見分けるべき3者のうち2者を塗りつぶしてしまい、その後ピクセルの色を調べてデーター化し、あらかじめスクリプトに持たせます。
元画像の全ピクセルのデーターを持たせるのが理想ですが圧縮しない限りメモリが足りない為、192*192のエリアに分割して、1,0で表現することにしました。(安直ですがその程度の解像度で十分でしたので。)

表現したい内容が3種類で、値が1、0の二種類しかないですから、外側は0,0,0・・の連続、線上は1、内側は1,0,1,0,1・・・の連続としてビット情報化してあります。



この場合、 llDetectedTouchST()で得られた座標が192*192マスのどれに該当するかを割り出して、次に、その左右(上下方向で走査なら上下)のピクセルの値も取得し、1,0,1または0,1,0であれば内側、そうでない場合自分の座標が1なら線上、そうでないなら外側、で仕分けすることが出来ます。
平面でデーターを作るのは非常に楽ですね。内側と外側を画像処理ライブラリの関数を使って塗りつぶせばおしまいです。立体では六面体ではなく球を使う方が現実的かもしれません。




コツ。以下は必要な方だけ見てください。



  


Posted by RBK Drachnyd(しお) at 00:03Comments(1)算数
2010年09月26日

lsl 戦車砲をシミュレートする

表題の相談を受けまして作成しましたが、内容の説明はチャットだけではつらい為、中身の説明が主な目的となります。


概要


とりあえず、動画から詳しい動きを解析しました。






1.砲塔そのものは車体の現在の傾きに対して何かを中心に左右にだけ回転すること。
2.砲身は砲塔の現在の傾きに対して付け根を中心にして上下にだけ回転すること。
3.限界の回転速度が各々あること。
4.1、2、3を合成した結果が照準に追随すること。


という動き方をしているようです。

構造


車体が回転していない状況では、対空砲と基本的に同じです。ただし、水平回転と垂直回転を各々砲塔、砲身に分担させればよいということになります。

車体の回転や砲塔の回転を考慮する今回の場合は、対空砲ではリージョン座標(SIMの座標)系で水平垂直の回転の合成として向くべき方向をそのまま計算していたものを、対象の方向を自分の土台(ルートまたは砲塔)のローカル座標系に変換してから水平垂直の回転の合成に置き換えることになります。
この種の直交座標系の変換は、自分の回転状態の逆回転で絶対座標系の値(ベクトル)を回転させ、自分は回転していないものと見做してもろもろの計算を行います。位置関係が必要であれば自分の絶対座標系での座標を目標の座標から引きます。





次に、砲塔も砲身も回転中心がプリムの中心(スクリプトで回転させる際の実際の回転中心)とはずれていますので、vectorの回転の方法を使って回転中心をずらして表現します。(下図)



砲身は自身の偏心だけでなく、砲塔の旋回による位置変更も伴います。これらも上図と同様に位置変更を計算して合成する必要があります。

4.は照準を指すまでの回転と移動を特定の距離・回転角度に抑え込んで補間移動するという事になりますので、位置移動と回転について姿勢の補間を使って、さらに最初~最後までの変更速度を一定にするために、何らかの基準になる変更速度との比を用いて表現します。

この種の中間姿勢の補間方法は一般式にすると

その時刻の姿勢=始点の姿勢×Fstart(T)+終わりの姿勢×Fend(T)
(但T=0.0(始点)~1.0(終点)、Fstart(T)+Fend(T)=1.0で一定の関数)

です。
与えるTの値が0~1に変化していくときに、Tの値によって始点と終点の合成された姿勢が戻ってきます。また、Tの刻み幅が一定で変化するときに戻る姿勢の刻み幅は関数Fstart(X)、Fend(X)の戻りに依存します。普通は姿勢の刻みが一定に見えるように関数を作りますので、たとえば180度を回転する場合のTの刻み(⊿T0)をあらかじめ決めておいて、

今回のTの刻み=⊿T0*PI/今回の始点から終点までの回転角度

として用いれば良いでしょう。
移動には線形補間を、回転には球面線形補間を使うのが普通だと思います。
今回の運動では回転ですべてが表現されていますので、rotationの球面線形補間を使うことになります。なお、クオータニオンの補間内部で使う4次元ベクトルの内積のアークコサインは、180度での値はPI_BY_TWOになります。ですので、Tの刻みは、

今回のTの刻み=⊿T0*PI_BY_TWO/今回の始点と終点のrotationの内積の値のアークコサイン

とします。


次に、スクリプトの作りを少し考察します。
リンクされたプリムを回転させる場合、なめらかに動作するllSetLinkPrimitiveParamsFast()を利用することを前提とします。

照準の取得はタイマーなりlink_messageなりになるかと思われますが、rotationの座標系を回転処理本体に合わせることを要求すると、クオータニオンの知識が利用者にも必要となる可能性があるため、利用の便利さを考えますと、照準による戦車砲の回転の始点と終点は、標準の関数で簡単に割り出せ、扱いも簡単なベクトルで設定する事にしておいて、処理側でローテーションに勝手に変換する形で指定させる方が汎用性は高くなると思われます。

ルートが直接回転操作の対象となる様な(つまり砲塔や砲身がルートプリムであるような)乗り物はまずないと思いますので、回転操作の対象は子プリムに限定します。

メンテナンス性は子プリムにスクリを入れるよりルートにすべてを入れた方がよいのではないかと思いますので、プリム番号の取得のような物を使ってあらかじめ対象の番号を設定することを前提にして、ルートから操作することにしました。

設定項目


全てスクリプトの冒頭に集めておき、ここだけ修正すればよいようにしています。


TARGET_PRIM_NUMBER
スクリプトが回転操作を行う対象のリンク番号を設定します。1以下の数字(ルートを表す)の場合は実行されません。

SYNC_PRIM_NUMBER
FALSEまたは砲塔のリンク番号を設定します。リンク番号が指定の場合はそのプリムの回転によって相対位置を保ちながら補正します。FALSEの場合はルートとの相対位置を維持しようとします。

ENABLED_RL
TRUEにすると左右に旋回します。FALSEにすると左右旋回しません。

ENABLED_UD
TRUEにすると上下に旋回します。FALSEにすると上下旋回しません。

DECENTERING
回転中心の、プリムの中心からのずれをvectorで指定します。

VEC_END
この変数に照準の方向(目標を指差すベクトル)を指定します。初期状態で特定方向を向ける場合などには、ここに方向を示すリージョン座標を設定をしておけばそちらを向きますが、内部で上書きされる変数のため、別途デフォルトの向きを指定する変数を用意しない限り、普通は意味がないと思われます。

DT_PI
180度旋回する場合の補間の刻み(T値の刻み幅)を指定します。
小さいほどゆっくり旋回します。1以上の値にするとすぐさま目標の方向を向きます。ゼロ以下の場合は回転しません。

内容(改造のための要旨)


関数 init_params()
スクリプトの保存時とリセットの時に呼び出されます。対象プリムの初期状態の回転と、ルートまたは連動対象との相対位置関係を取得しています。
対象プリム設定がルートを指している場合FALSE、その他はTRUEを返します。

関数 init()
初期化関数ですが何もせずサンプル(センサーイベント)を起動しています。
実行開始時とrezの時に呼び出されます。

sensorイベント
照準設定のサンプルが入っています。
最も近い距離にいるアバターの方向を、自分から見た方向として変数VEC_ENDに設定しています。
カメラ方向などを指定する場合は回転初期値startVecの設定と同じように、llRot2Fwd(カメラ方向)などとすれば良いかと思われます。
また、回転スクリプトがカメラ操作権限を取ることはないと思いますので、実際に乗り物に利用時はセンサーではなくlink_messageなどの中で設定を行うことになり、timerイベント(回転処理本体)の開始もlink_messageの中になるだろうと思われます。

attachイベント
使っていませんが、改造用に変数isAttachにアタッチされているかどうかを設定しています。

timerイベント
実際の回転処理が入っています。
アタッチメント、REZの両者に対応するために、llGetLinkPrimitiveParams()を多用しています。
これは、従来関数のllGet系はアタッチとREZで動作が異なって少々面倒な場合がある為、いつでもリージョン座標系の値しか返さないllGetLinkPrimitiveParams()を使っているという意味です。ルートに置くことを前提にしているためでもありますが、子プリムに入れる場合は従来関数を使用している部分を数か所、適正に修正するだけでよいはずです(※取消:ルートのローカル回転は依然、ルートのllGetLocalRot()でなければ取れませんでした。)(※再度取消:llGetLinkPrimitiveParams()でPRIM_ROT_LOCALを指定してルートの回転を取れば子プリムに入っていてもアタッチ・REZを問わず動作させられます。同様に回転の実行時にもPRIM_ROT_LOCALを使う方が簡単になります。)

実行の順序的には、

1.与えられた始点と終点のベクトルを現在の自分のローカル座標系から見たrotationに変換
2.微小回転を球面線形補間(関数 interpolationRot())を用いて計算
3.砲身の場合(SYNC_PRIM_NUMBERに値がある)には回転土台をそれとして位置補正を計算
4.回転を実行

となっています。
以下詳細。。



timer()
{
最初に、回転対象がルートは、パラメーターミスのため実行せず戻ります。
if (TARGET_PRIM_NUMBER<=1)
{
llSetTimerEvent(0.0);
return;
}


ルート回転をllGetLocalRot()で取得します。リージョン回転またはアタッチポイントとの相対回転が取得されます。
avRotは正確にはアタッチメント、REZを問わずrootプリム(アバター※)のリージョン回転になりますが、アバターのアニメは含まれない為、アタッチで使用する場合はアニメーションの方ではアタッチ位置の回転が行われない様にしなければなりません。(※修正:気になって調べてみたところllGetRootRotation()と同じ戻りの模様でした。)

rotation rootRot=llGetLocalRot();
rotation avRot=llList2Rot(llGetLinkPrimitiveParams(LINK_ROOT,[PRIM_ROTATION]),0);



座標系の変換処理
照準のベクトルを自分のルートプリムの現在の回転で割ってローカル回転にしています。

vector norm=llVecNorm(startVec/avRot);
vector norm2=llVecNorm(VEC_END/avRot);

旋回土台の回転を取得
rotation parentRot=avRot;
if (SYNC_PRIM_NUMBER)
{
連動対象がある場合はそちらの回転を採用
parentRot=llList2Rot(llGetLinkPrimitiveParams(SYNC_PRIM_NUMBER,[PRIM_ROTATION]),0);
照準のベクトルも連動対象のローカル座標系の単位ベクトルに再設定します。
自分の土台から見た自分自身の回転だけを計算させる方が(恐らく)改造が楽なため、このようにしてあります。(たとえば砲身の仰角・俯角に限界を設ける場合は、このようにしておけば自分のY軸旋回だけを見て限界判定できますので。。)

norm=llVecNorm(startVec/parentRot);
norm2=llVecNorm(VEC_END/parentRot);
}

ベクトルを水平面垂直面回転に変換しています。
正面軸がX軸でない場合はllEuler2Rot()やllRotBetween()の中の値がある座標軸を変更します。

rotation startRot=llEuler2Rot(<0,(llAcos(norm.z)-PI/2.0)*(float)ENABLED_UD,0>)*llRotBetween(<1,0,0>,<norm.x*(float)ENABLED_RL,norm.y*(float)ENABLED_RL,0>);
rotation endRot=llEuler2Rot(<0,(llAcos(norm2.z)-PI/2.0)*(float)ENABLED_UD,0>)*llRotBetween(<1,0,0>,<norm2.x*(float)ENABLED_RL,norm2.y*(float)ENABLED_RL,0>);


T値の刻みを補正しています。
angleBetweenRot()は球面線形補間内で使われるアークコサインの値を返します。
180度旋回時の値PI_BY_TWOをそれで割ってT刻みの初期値に掛けることで見かけの回転速度を一定にします。

dT=1.0;
float a=angleBetweenRot(startRot,endRot);
if (a!=0.0)
{
dT=PI_BY_TWO/a*DT_PI;
}
else
{
無回転のため、処理を終えて戻ります。
llSetTimerEvent(0.0);
return;
}


今回の回転を球面線形補間で計算しています。
Tの値が1以上(回転終了)の場合にはタイマーを停止します。

T+=dT;
if (T>=1.0) llSetTimerEvent(0.0);
rotation rot=interpolationRot(startRot,endRot,T);


位置補正(連動があれば)を計算します。
初期状態では位置は偏心成分と、ルートから見た相対位置として設定します。

vector pos=DECENTERING;
rotation rot_sync=ZERO_ROTATION;
vector pos_sync=RELATIVE_POS;
if (SYNC_PRIM_NUMBER)
{
連動プリムが設定されている場合は値を上書きします。
対象のローカル回転を取得します。連動プリムのリージョン回転をルートのリージョン回転で割って、ローカル回転成分だけを取得します。

rot_sync=parentRot/avRot;
座標移動をルートからのローカル位置関係として計算します。
リージョン座標系での相対移動距離を計算後に、ルートのリージョン回転と逆回転してローカル座標系に移しています。

pos_sync=(RELATIVE_POS*parentRot+llList2Vector(llGetLinkPrimitiveParams(SYNC_PRIM_NUMBER,[PRIM_POSITION]),0)-llList2Vector(llGetLinkPrimitiveParams(LINK_ROOT,[PRIM_POSITION]),0))/avRot;
}
回転を合成します。
自分のデフォルトの回転、今回の回転、土台の回転を合成します。

rot=defaultMyRot*rot*rot_sync;

移動量を合成します。
pos_syncはルートからの移動量となっています。
自分の偏心成分(pos内)は今回の回転全体をかけて方向を修正します。

pos=pos*rot+pos_sync;

さらに回転全体をルートプリムの回転で割ります。(LSLのバグ?のため必要な決まり事です。)
rot=rot/rootRot;

姿勢変更を実行します。
llSetLinkPrimitiveParamsFast(TARGET_PRIM_NUMBER,[PRIM_POSITION,pos,PRIM_ROTATION,rot]);
}
  


Posted by RBK Drachnyd(しお) at 14:09Comments(0)算数
2010年09月26日

プリムの面番号とリンク番号を取得する

ビューワー2になってから面番号の取得がキー操作で出来なくなった(?)のか、私がキー操作を間違えているのか分かりませんが(^^;、以前にあるとよいフリースクリというご意見も伺いましたので。。

ルートプリムのコンテンツに入れて目的のプリムの目的の面をタッチします。

default
{
touch_start(integer total_number)
{
llOwnerSay("プリム番号:"+(string)llDetectedLinkNumber(0));
llOwnerSay("面番号:"+(string)llDetectedTouchFace(0));
}
}
  


Posted by RBK Drachnyd(しお) at 11:27Comments(2)小物
2010年09月01日

極端に重い処理をJavaScriptに投げると・・

llSetPrimMediaParams()(ビューワー2専用)のパラメーターを見ていて今更気づきました。(笑
URLの代わりに1KBまで限定で、document.write()と同じことが出来るんですね。。^^;
外部URLのJavaScriptの実行は普通にしているようで、各ユーザーのパソコン上での実行のようです。ということは、スクリプトのソースが流出することを覚悟するなら、計算が極端に速くできるという事だと思いましたので、実際にやってみました。

元状態:LSLで全てしている場合の速度(黒棒が生えたら終了)




改造後:多倍長計算をプリムメディア(ブラウザ)に投げた場合




スクリプトはlslのものを関数名や制御構造をJavaScriptのそれに変えた(jumpが無いとか)だけで、中身は同じですが、思ったとおり劇的な速度向上が得られます。

なお、JavaScriptファイルを外部サーバーにおくと、ユーザーブラウザがサーバーにアクセスしたときに少なくとも元データーとIPは(私に)抜かれてしまいますし、私が外部サーバーを閉じてしまう(破産したとか。。^^;)と全ユーザーで一斉に動かなくなってしまいますので、外部サーバーへのアクセスを排除する為にhttp-inでプリムをWEBサーバーにして、JavaScriptソースをstringとして持っていてGET要求があるとそれを返すようにしてあります。(クラウドをもてはやす評論家って、一体何を考えているんでしょうね。。常々疑問です。。)

計算結果はXMLHttpRequestでPOSTで送り返すようにしましたが、2Kを超えるbodyは切られてしまうため、結果のサイズをブラウザ側で調べて、分割して分けて送り返すようにしました。この動画の場合、結果転送の待ち時間で3秒程度かかっていて、これにllSetPrimMediaParams()の1秒のスクリプト停止があります。




んー。最大の難点は方法ではなくて、ビューワー2を使っている人がどのくらいいるか、ですね。。  


Posted by RBK Drachnyd(しお) at 15:37Comments(2)作成物/製品
2010年02月28日

スクリプト ところてんの歌

「ところてん」について。
知らない方はご一読ください。
http://www.kurata-wataru.com/t-osamu/osamu107.html



原曲
再生しながら読んでください。
http://www.youtube.com/watch?v=w22WZW1elxM







♪とっころ っとっこ~ろ とっころ っとっこ~ろ



(間奏)



誰かが こっそり。。。 小道に 好み うずめた。。。

小さなの 見えたら 秘密の暗号 徹夜のパスポート

す~て~き~な~ 冒険 はじまる~~~(T_T



♪となりの とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

バグの山に 昔から泣いてる。。。(;_;/

♪となりの とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

テストのときにだけ あなたに許される 不思議な出会い。




(間奏)




ログ取り(T_T バグ取り(T_T ずいぶん大(おお)バグがいたら。。。

あなたの アイディア 挿してあげましょう パスタへパスポート

魔法の扉 あきます。。。(T_T/



♪となりの とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

月夜の晩に パスタに苦しむ

♪となりの とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

もしも解けたなら 素敵な睡眠(しあわせ)が

あなたに来るわ。。。




♪とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

バグの山に 昔から住んでる。。。(;_;/

♪となりの とっころ っとっこ~ろ(てん!) とっころ っとっこ~ろ(てん!)

テストのときにだけ あなたが許される

不思議な出会い。。。

♪とっころ っとっこ~ろ とっころ っとっこ~ろ

(繰り返し)
 ・
 ・
 ・





冷静な話ところてん装置とは目の前にある箱のことですね。。。(笑  


Posted by RBK Drachnyd(しお) at 01:47Comments(0)雑記
2010年02月22日

lsl 連立一次方程式を解く

プログラムとしては割とありふれた内容で、n次連立一次方程式の未知数達を左辺に、定数を右辺に移動した後に、左辺の未知数の係数達をn*nの正方行列(飛び石リスト)、右辺をn個のリストとして与えると答えを計算して解のリストを戻します。

後々出てくるかどうか不明ですが、一応λの計算用に前進消去部分は外部関数として独立させてあります。

2・23訂正
早速バグが見つかったので訂正(^^;


// www.lsleditor.org  by Alphons van der Heijden (SL: Alphons Jano)
//****************************************************************************
//連立一次方程式を解く
//ガウスの消去法による
//第一引数が未知数の係数行列、第二引数が定数項のベクトル
//****************************************************************************
list gauss(list A,list B)
{
integer lenA=llGetListLength(A);
integer len=llFloor(llSqrt((float)lenA));
//チェック
if (len*len!=lenA || len!=llGetListLength(B))
{
return [];
}
A=truangularMatrix(A+B);
B=llList2List(A,-1*len,-1);
A=llDeleteSubList(A,-1*len,-1);
integer i=len-1;
 
//一つ目の解
list res=[llList2Float(B,-1)/llList2Float(A,-1)];
integer j=1;
 
//後進代入処理
while (i--)
{
float tmp=0.0;
list tmpList=llList2List(A,i*len,(i+1)*len-1);
while(j--)
{
tmp=tmp+llList2Float(res,-1*(j+1))*llList2Float(tmpList,len-j-1);
}
res=[(llList2Float(B,i)-tmp)/llList2Float(tmpList,i)]+res;
j=llGetListLength(res);
}
return res;
}
//****************************************************************************
//前進消去により行列を上三角行列にする
//当然、出力の対角線成分が行列の固有値のリストになる。
//引数は方程式の左辺(正方行列)+方程式の右辺ベクトルを追加したものでもよい。
//その場合は右辺ベクトルにも変更が行われる。(ガウスの消去法用)
//****************************************************************************
list truangularMatrix(list A)
{
integer lenA=llGetListLength(A);
integer len=llFloor(llSqrt((float)lenA));
//チェック
list B=[];
if (len*len!=lenA)
{
if (len*len+len!=lenA)
{
//正方行列でも方程式でもなかった
return [];
}
else
{
//方程式らしい
B=llList2List(A,-1*len,-1);
A=llDeleteSubList(A,-1*len,-1);
lenA=len*len;
}
}
integer i=0;
while (i<len)
{
integer j=i+1;
while (j<len)
{
integer p=0;
float f=0.0;
do
{
integer q=(i+p)*(len+1);
if (q>=lenA) return [];
f=llList2Float(A,q);
if (f!=0.0)
{
if (p)
{
A=llListInsertList(llDeleteSubList(A,(i+p)*len,(i+p+1)*len-1),llList2List(A,(i+p)*len,(i+p+1)*len-1),i*len);
B=llListInsertList(llDeleteSubList(B,i+p,i+p),llList2List(B,i+p,i+p),i);
}
jump continue;
}
++p;
} while (TRUE);
@continue;
float tmp=llList2Float(A,j*len+i)/f;
A=llListReplaceList(A,[0.0],j*len+i,j*len+i);
integer k=len-i;
while(--k)
{
A=llListReplaceList(A,[llList2Float(A,j*len+i+k)-tmp*llList2Float(A,i*(len+1)+k)],j*len+i+k,j*len+i+k);
}
if (B!=[])
{
B=llListReplaceList(B,[llList2Float(B,j)-tmp*llList2Float(B,i)],j,j);
}
++j;
}
++i;
}
return A+B;
}
//****************************************************************************
//おしまい
//****************************************************************************
 
 
 
//****************************************************************************
//おまけ。
//行列式の値の計算
//第一引数は正方行列または正方行列の末尾に方程式の右辺(定数項のベクトル)を加えたもの
//第二引数がTRUEの場合関数内で上三角行列に変換する。
//第二引数がFALSEの場合は事前に上三角行列に変換しておくこと。
//****************************************************************************
float determinant(list A, integer f)
{
integer lenA=llGetListLength(A);
integer len=llFloor(llSqrt((float)lenA));
float res=1.0;
//チェック
if (len*len!=lenA)
{
if (len*len+len!=lenA)
{
//正方行列でなかった
return 0.0;
}
else
{
//方程式らしい
A=llDeleteSubList(A,-1*len,-1);
lenA=len*len;
}
}
if (f) A=truangularMatrix(A);
integer i=len;
while (i--)
{
res=res*llList2Float(A,i*(len+1));
}
return res;
}
 
 
 
 
 
 
default
{
touch_start(integer total_number)
{
list test=[0,0,1,8,1,4,2,3,4];
list test2=[4,5,3];
llSay(0, llDumpList2String(gauss(test,test2)," , "));
}
}
  


Posted by RBK Drachnyd(しお) at 21:40Comments(0)算数
2010年02月20日

悲しいね。。

必ず冒頭のURLの曲を再生しながら、順に読んでください。




渡辺美里 「悲しいね」
http://www.youtube.com/watch?v=ZOHNJyqjV54











♪くだりのツモ運。。。
南場までは まだはれない。。。
まつげの先そっと 涙の火が 灯るよ。

やさしく息がかかるくらい ちかくにいて。。
切ないほどドラを 遠く感じている。。

君に泣き顔見せないように
後ろ向きでツモ切るのはなぜ?

流れては過ぎる配パイに




答えがあふれだす。。。




幼いころは 十三不塔(しぃさんぷとぅ) 待っていたよ。
凍るようなツモは 君の声待ってる。(ろん!)

ツモ切りの中まみれてると、
ドラさえ手放したくなるのはなぜ?

”強くて清らかな”配パイに
少し疲れたよう。。。





一番の勇気はいつの日も 自分らしく素直にツモること。
白い棒 箱の中 減ってくる。。
ドラ以外 見えなくなる。。。


悲しいね。
手のなかは いつだって。。。
つながりを 失った ゴミの色。

悲しいね?
悲しいね?
悲しいね?

ちぃ すること ためらうなんて。。。。。。





(間奏)





極道じみた Guy(奴)の上に 風がゆれる。。

かじかむ手の内に
冬(北)が近づいてる。。。。


人の心の暖かさに
情けないほど触れたいのは何故?

ふり込みのたびにわけもなく、
涙が溢れ出す。。。








一番の

勇気は

いつの日も

自分らしく

素直に 

ツモること。


白い棒、箱の中、減ってくる。。。。。

ドラ以外、見えなくなる。。。。。。。。。。。。。。。


悲しいね。
ひとりきり いつだって。。。 つながりを うしなった 遠いツモ。


悲しいね?
悲しいね?
悲しいね?

ふりこむばかりじゃ 悲しいね?







(間奏)






かなしいね、ふりこみは いつだって。。。

かなしいね、ひとりきり いつだって。。。。

あらららら。。。。

あらららら。。。。  


Posted by RBK Drachnyd(しお) at 04:24Comments(1)雑記
2010年02月10日

lsl 多倍長演算

何に使うのか。。。といった風ですが(笑)、多倍長整数実数の演算です。
負数に対応しています(はずです。。。(笑))。


以下アルゴリズムです。
検索から飛んで来られる方がおられるようですが、こちらは32ビット符号付整数と(バグがあるとかないとか言う)単精度浮動小数点数しかないLSLという環境用です。乗算や除算には、メモリーが許せばもっと高速なアルゴリズムがあったと思います。


1:足し算引き算
筆算と同じです。9桁づつ文字列から取り出して計算し、繰上げ切り下げを次の桁で行います。

2:掛け算
筆算と同じです。3桁づつ文字列から取り出して計算し、9桁までの繰上げはその場で、10桁以降は次の桁計算に持ち越します。

3:割り算
筆算と同じです。ただし商を求める際に分母先頭8桁と分子先頭8桁を使って仮の商を算出し、手順を簡略化しています。
整数の割り算(longIntDiv())のみ、listが戻りになり、0番が商、1番が剰余になります。
longDiv()では戻りは商のみとなります。


2010/4/28:追記および変更
サンプルを削除しました。
バグを修正し、実数計算を追加しました。
小数点を一旦消して整数計算して戻しているだけですが、高次の連立方程式用として現在試験中です。
桁数の管理や精度はかなりいい加減です。加減乗算では小数点以下の桁数を管理しておらず、割り算では桁数が多すぎると無条件に切り捨てていますので。。。^^;
また、いちいち文字列から部分を抜き出していますが、あらかじめlistに桁あふれしない長さの整数で格納しておくほうが高速に動作するはずです。(listはメモリー的に不利ですから。。。)




// www.lsleditor.org by Alphons van der Heijden (SL: Alphons Jano)
//****************************************************************
//多倍長実数計算
//****************************************************************
//整数であるか調べ、符号かFALSEを返す
integer isInt(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-"];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//実数であるか調べ、符号かFALSEを返す
integer isFloat(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-","."];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//文字列先頭の指定文字を削除
string ltrim(string s, string t)
{
if (llGetSubString(s,0,0)!=t) return s;
integer i=0;
integer maxI=llStringLength(s);
if (!maxI) return s;
++maxI;
while(i<maxI)
{
++i;
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,i,maxI);
}
//文字列末尾の指定文字を削除
string rtrim(string s, string t)
{
if (llGetSubString(s,-1,-1)!=t) return s;
integer i=llStringLength(s);
if (!i) return s;
while(i--)
{
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,0,i);
}
//整数数値文字列の絶対値について大小比較
integer longIntAbsCmp(string a, string b)
{
a=ltrim(a,"-");
b=ltrim(b,"-");
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return 0;
if (a!="" && b=="") return 1;
if (a=="" && b!="") return -1;
if (a==b) return 0;
integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (!lA && !lB) return 0;
if (lA>lB) return 1;
if (lA<lB) return -1;
integer i=0;
integer ia=0;
integer ib=0;
do
{
ia=(integer)llGetSubString(a,i,(i+8));
ib=(integer)llGetSubString(b,i,(i+8));
if (ia!=ib) jump continue;
i+=9;
} while(i<lA);
@continue;
if (ia>ib) return 1;
if (ia<ib) return -1;
return 0;
}

//****************************************************************
//足し算引き算
//****************************************************************
string longIntSum(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
integer flag=1;
if (f1!=f2) flag=-1;
integer f3=longIntAbsCmp(a,b);
string rflag="";
if (f3==0 && flag==-1) return "0";
if (f3<0)
{
if (f2<0) rflag="-";
string c=a;
a=b;
b=c;
integer tmp=f2;
f1=f2;
f2=tmp;
}
else
{
if (f1<0) rflag="-";
}
//9ケタづつ加減算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer k=0;
integer u=0;
string res="";
while(k>lA)
{
k-=9;
integer va=(integer)llGetSubString(a,k,k+8);
va=va+(integer)llGetSubString(b,k,k+8)*flag+u;
u=llFloor((float)va/1000000000.0);
va=llAbs(va-u*1000000000);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<9)
{
l=8-l;
tmp=llGetSubString("000000000",0,l)+tmp;
}
res=tmp+res;
}
res=rflag+ltrim((string)u+res,"0");
if (res=="") return "0";
if (res=="-") return "0";
return res;
}
//****************************************************************
//掛け算
//****************************************************************
string longIntMul(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";
if (b=="1")
{
if (f1*f2<0) return "-"+a;
return a;
}
if (a=="1")
{
if (f1*f2<0) return "-"+b;
return b;
}
//3ケタづつ乗算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer i=0;
integer j=0;
integer k=0;
string res="";
integer of=0;
while(j>lB-3)
{
j-=3;
k=0;
while(k>lA)
{
k-=3;
integer va=(integer)llGetSubString(a,k,k+2);
va=va*(integer)llGetSubString(b,j,j+2)+of*1000000;
of=0;
i=k+j+3;
integer rlen=llStringLength(res);
if (rlen+i<0)
{
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<6)
{
l=5-l;
tmp=llGetSubString("000000",0,l)+tmp;
}
res=tmp+res;
}
else
{
va+=(integer)llGetSubString(res,i-6,i+2);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<=9)
{
l=9-l;
if (l>0) tmp=llGetSubString("000000000",0,l-1)+tmp;
}
else
{
of=(integer)llGetSubString(tmp,0,l-9-1);
tmp=llGetSubString(tmp,l-9,l);
}
res=llGetSubString(res,rlen*-1+i-7,i-7)+tmp+llGetSubString(res,i+3,-1);
}
}
}
res=ltrim((string)of+res,"0");
if (res=="") return "0";
if (res=="0") return "0";
if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}
//****************************************************************
//整数の割り算
//****************************************************************
list longIntDiv(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f2==0) return ["INFINITY","0"];
if (f1==0) return ["0",b];
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return ["INFINITY","0"];
if (a=="")
{
if (f2<0) return ["0","-"+b];
return ["0",b];
}

//6桁以下の分子なら通常計算して終わる
if (llStringLength(a)<=6)
{
if (longIntAbsCmp(b,a)>0)
{
return ["0",a];
}
else
{
return [llFloor((float)a/(float)b),(integer)a % (integer)b];
}
}

integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (lB>lA) return ["0",a];
if (longIntAbsCmp(a,b)<0) return ["0",a];
integer i=0;
integer j=0;
integer k=0;
string res="";
string mod="0";
string zero="0";
integer B1ToB8=(integer)llGetSubString(b,0,7);

//初期化
string A=llGetSubString(a,0,lB-1);
a=llGetSubString(a,lB,lB+lA);
if (longIntAbsCmp(A,b)<0)
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
//除算
do
{
integer q=0;
while (!q)
{
integer A1ToA8OrA9=(integer)llGetSubString(A,0,7);
if (llStringLength(A)>7)
{
if (A1ToA8OrA9<B1ToB8)
{
A1ToA8OrA9=A1ToA8OrA9*10+(integer)llGetSubString(A,8,8);
}
}
q=llFloor((float)A1ToA8OrA9/(float)B1ToB8);
if (!q)
{
if (a=="")
{
res=res+zero;
mod=A;
jump continue;
}
res=res+"0";
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
}
string bq;
integer test=-1;
while(q>0)
{
if (lB<8)
{
bq=(string)((integer)b*q);
mod=(string)((integer)A-(integer)bq);
test=0;
}
else
{
if (q==1)
{
//仮の商が1。桁が一桁違う場合がありうる。
if (llStringLength(A)>llStringLength(bq))
{
q=10;
while(--q)
{
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0) jump continue3;
}
}
bq=longIntMul(b,(string)q);
@continue3;
}
else
{
bq=longIntMul(b,(string)q);
}
}
if (test==-1) test=longIntAbsCmp(A,bq);
if (test<0)
{
--q;
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0)
{
res=res+(string)q;
jump continue2;
}
}
else
{
res=res+(string)q;
jump continue2;
}
}
@continue2;
if (q<=0)
{
mod=A;
jump continue;
}
zero="";
if (a!="") zero="0";
mod=ltrim(longIntSum(A,"-"+bq),"0");

//次の数字
integer modLen=llStringLength(mod);
A=mod;
if (modLen<lB)
{
integer m=lB-modLen;
integer an=llStringLength(a);
if (an>0)
{
if (m>an) m=an;
while(--m)
{
res=res+"0";
}
m=lB-modLen;
A=A+llGetSubString(a,0,m-1);
a=llGetSubString(a,m,lB+lA);
}
}
if (longIntAbsCmp(A,b)<0)
{
if (a!="")
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
if (modLen<lB)
{
res=res+"0";
}
}
else
{
res=res+zero;
jump continue;
}
}
if (llStringLength(A)<lB)
{
res=res+zero;
mod=A;
jump continue;
}
} while(TRUE);
@continue;
res=ltrim(res,"0");
mod=ltrim(mod,"0");
if (mod=="") mod="0";
if (f1*f2<0) res="-"+res;
if (f1<0 && mod!="0") mod="-"+mod;
if (res=="") res="0";
return [res,mod];
}

//****************************************************************
//実数の多倍長加減算
//****************************************************************
string longSum(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
//準備
//小数点以下が長いほうにあわせて桁移動して整数化。
integer la=llStringLength(a);
integer lb=llStringLength(b);
integer pa=llSubStringIndex(a,".");
integer pb=llSubStringIndex(b,".");
integer digit;
if (pa!=-1 || pb!=-1)
{
if (pa!=la-1 || pb!=lb-1)
{
if (pa==-1)
{
pa=la;
++la;
a=a+".";
}
if (pb==-1)
{
pb=lb;
++lb;
b=b+".";
}
digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb-digit;
while(digit--)
{
a=a+"0";
}
}
else
{
digit=digit-(lb-pb);
while(digit--)
{
b=b+"0";
}
}

}
a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);
}

if (f1<0)
{
a="-"+a;
}
if (f2<0)
{
b="-"+b;
}
string res=longIntSum(a,b);

digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb;
}
--digit;
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
string tmp="";
if (llSubStringIndex(res,"-")==0)
{
tmp="-";
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}
return tmp+res;

}

//****************************************************************
//実数の多倍長乗算
//****************************************************************
string longMul(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";

//準備
//小数点以下の長さを記憶しておく。
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
integer digit=llStringLength(a)-llSubStringIndex(a,".")+llStringLength(b)-llSubStringIndex(b,".")-2;

a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);

string res=longIntMul(a,b);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
integer la=llStringLength(res);
if (llSubStringIndex(res,"-")==0)
{
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
integer pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
integer pa=la-digit;
res=llInsertString(res,pa,".");
}

if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}


//****************************************************************
//実数の多倍長割り算
//第一引数:分子(被除数)
//第二引数:分母(除数)
//第3引数は小数点以下の桁数を指定
//****************************************************************
string longDiv(string a, string b,integer digit)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f2==0) return "INFINITY";
if (f1==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return "INFINITY";
if (a=="") return "0";

//準備 / 分子分母の整数化
integer pa=llSubStringIndex(a,".");
integer la=llStringLength(a);
if (pa==0)
{
a="0"+a;
pa=1;
++la;
}
if (pa==-1)
{
pa=la;
a=a+".";
++la;
}
integer pb=llSubStringIndex(b,".");
integer lb=llStringLength(b);
if (pb==-1)
{
pb=lb;
++lb;
}
else if (pb==0)
{
pb=1;
++lb;
}
//分子小数点以下に希望の桁数を追加
integer i=digit-(lb-pb-1);
if (i<0)
{
//小数点以下が長すぎる
b=llGetSubString(b,0,pb+digit);
lb=llStringLength(b);
pb=llSubStringIndex(b,".");
}
i=digit-(la-pa-1);
if (i<0)
{
//小数点以下が長すぎる
i=0;
a=llGetSubString(a,0,pa+digit);
la=llStringLength(a);
pa=llSubStringIndex(a,".");
}
if (la-pa<lb-pb) i=i+lb-pb-la+pa;
while(i--)
{
a=a+"0";
}
if (pb>=0)
{
//分母に小数点。
//分母を整数にし、分子の小数点を移動
b=(string)llParseString2List(b,["."],[]);
integer p=lb-pb-1;
string floatA=llGetSubString(a,pa+1,-1);
a=llGetSubString(a,0,pa-1)+llInsertString(floatA,p,".");
}
//桁数の補正
//digitより小数点以下の数が少なければ追加
pa=digit-(llStringLength(a)-llSubStringIndex(a,".")-1);
if (pa>0)
{
do
{
a=a+"0";
}while(--pa);
}
a=(string)llParseString2List(a,["."],[]);
//計算実行
string res=llList2String(longIntDiv(a,b),0);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}




if (f1*f2<0) res="-"+res;

return res;
}
//****************************************************************
//多倍長計算関連おしまい
//****************************************************************





default
{
state_entry()
{
llResetTime();
llOwnerSay(longSum("-0.0960866054","-0.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longMul("0.0960866054","-1.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longDiv("2304.0960866054","0.0452746054",20));
llOwnerSay((string)llGetTime());
}
}  


Posted by RBK Drachnyd(しお) at 22:04Comments(2)算数
2010年02月04日

lsl 乱数生成器

簡単な暗号通信をしたいと思い立ち、計算が軽い物を。。。
乱数に関しましては、北国ぺんぎん様のブログにもっと長周期(現在最強?)のものが紹介されております。

鍵になる文字列からハッシュを生成し、それを元にxorShift32乱数で4つのSeedを生成し、そのSeedを元にxorShift128乱数を生成します。
受信側と送信側のSeedが同期している限り復号し、同期が取れなくなると復号できなくなります。




// www.lsleditor.org  by Alphons van der Heijden (SL: Alphons Jano)
integer x = 123456789;
integer y = 362436069;
integer z = 521288629;
integer w = 88675123;
 
//***************************************************
//暗号化
//***************************************************
string alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/*-+.!\"#$%&'()~^|@{}[]*;?/_";
string encode(string txt)
{
integer n=llStringLength(txt);
string s="";
while(n--)
{
integer v=llRound(xorShift128(1.0)*(llStringLength(alphabet)-1));
s=llGetSubString(alphabet,v,v)+s;
}
return llXorBase64StringsCorrect(llStringToBase64(txt),llStringToBase64(s));
}
//***************************************************
//復号
//***************************************************
string decode(string crypt)
{
integer n=llStringLength(llBase64ToString(crypt));
string s="";
while(n--)
{
integer v=llRound(xorShift128(1.0)*(llStringLength(alphabet)-1));
s=llGetSubString(alphabet,v,v)+s;
}
return llBase64ToString(llXorBase64StringsCorrect(crypt,llStringToBase64(s)));
}
 
 
//論理右シフト
integer shrl(integer i,integer j)
{
return ((i >> j) & (0x7fffffff >> j-1));
}
//RSハッシュ
integer rsHash(string str)
{
integer len=llStringLength(str);
integer b = 378551;
integer a = 63689;
integer hash = 0;
while(str!="")
{
if (str!="")
{
while (llStringLength(str)<4)
{
str=str+" ";
}
}
string s1=llGetSubString(str,0,3);
str=llGetSubString(str,4,len);
integer i=llBase64ToInteger(llStringToBase64(s1));
integer k=llStringLength(s1);
while(k--)
{
hash = hash * a + (((i & (0x000000ff << 8*k)) >> 8*k) & 0x000000ff);
a = a * b;
}
}
return hash;
}
//Seed初期化(XorShift32)
randmize(string k)
{
integer y0=rsHash(k);
y0=y0^(y0<<13);
y0=y0^shrl(y0,17);
x=y0^(y0<<5);
y0 =y0^(y0<<13);
y0=y0^shrl(y0,17);
y=y0^(y0<<5);
y0=y0^(y0<<13);
y0= y0^shrl(y0,17);
z=y0^(y0<<5);
y0=y0^(y0<<13);
y0=y0^shrl(y0,17);
w=y0^(y0<<5);
}
//XorShift乱数(周期2^128-1)
float xorShift128(float f)
{
do
{
integer t = x ^ (x << 11);
x = y;
y = z;
z = w;
w =(w ^ shrl(w,19)) ^ (t ^ shrl(t,8));
} while(w==-2147483648);
return ((float)(2147483647-llAbs(w))/2147483646.0*f);
}

default
{
state_entry()
{
randmize("abdcefg");
}
touch_start(integer total_number)
{
integer a=x;
integer b=y;
integer c=z;
integer d=w;
string test="Rocket FM is great!";
llSay(0,test);
string crypt=encode(test);
llSay(0,llBase64ToString(crypt));
x=a;
y=b;
z=c;
w=d;
llSay(0,decode(crypt));
}
}
  


Posted by RBK Drachnyd(しお) at 17:51Comments(0)忘れない為に。。
2010年01月11日

Mako's Pandorabox

アクセサリーと家具のお店です。

http://slurl.com/secondlife/MIYAZAKI/16/124/22





1月11日1時11分11秒にこだわってとのことで(笑)、本日オープンされました。おめでとうございます。


店内。左側がアクセサリー、右側が家具のスペースになっています。






AVボードセット。落ち着いたデザインで大変高級感があります。部屋の雰囲気がぐっと引き締まるでしょう。
小物入れなどはちゃんと開閉します。





暖炉。(土地も無いくせに)インテリア好きな者としては、衝動買いをぐっと我慢しなければなりません。。(笑






ラッキーボード。グループにJOIN後にもらえます。イニシャルは5分更新です。








Mako's Pandorabox
http://slurl.com/secondlife/MIYAZAKI/16/124/22
  


Posted by RBK Drachnyd(しお) at 14:23Comments(0)お店紹介
2010年01月06日

1L$で30プリムの出店ブース

あけましておめでとうございます。

恋花SIM正式に公開とのことですのでご紹介させていただきます。

http://slurl.com/secondlife/Koibana/128/128/22






上の写真左下がショッピングモール、隣に初心者支援の1L$ブースの建物があります。
写真左上の建築郡がテナントスペース、右上の建物がバーになっています。






1L$のブース郡。
グループ加入に300L$が必要ですがその後は週1L$のみで30プリム(!)が使えます。
臨時プリムはNGですがアニメーションスクリプトは(極端にサーバーに負荷をかけない限り)OK、また、ブース内部であればパーティクルのデモもOKとの事。何でも動かしたい私としては素敵な条件です。






私のブース。まだ何もありませんが汎用アニメーションスクリプトに記憶させた動きでヤドカリが歩き回っています。
ブース横の棚も使えますので、本体でデモ、販売箱は棚という分け方もできますね。


末尾は先日のパーティクル製造装置で作成した雪のパーティクル。
ほかにもダンスホール用のレーザー照明やら炎やら煙やらを試しに作ってみましたが、その種の装飾や景観用のパーティクルスクリは、凝らなければ15分ほどもあれば出来てしまいます。不具合も見つけましたが、総じて思った以上に便利でした。
他の方の商売の邪魔になりますので売りに出すのは価格が難しいですが、遊び感覚だけでいろいろできますので、新しい方に物づくりの楽しさを知っていただくのには向いているかもしれません。。。
スライダーの最大値最小値の数値表示と、選択可能なスライダーの見やすさを調整したら売りに出します。
7月にREZしてからようやくにして、人に自信を持って「これはなかなか良いですよ」と言えるものが出来た気がします。




  


Posted by RBK Drachnyd(しお) at 22:50Comments(0)雑記
2009年12月25日

パーティクル製造機

チュートリアルです。


パーティクルジェネレーターです。






ON・OFFパラメーター


PSYS_PART_BOUNCE_MASKです。指定するとパーティクルが発射体より下にいかなくなります。 下方向に加速が設定されていると床に当たったように飛び跳ねます。

PSYS_PART_EMISSIVE_MASKです。 設定するとプリムの「明るさ全開」と同じになります。

PSYS_PART_FOLLOW_SRC_MASKです。 発射体が移動すると放出済みのパーティクルが発射体について一緒に移動します。

PSYS_PART_FOLLOW_VELOCITY_MASKです。パーティクルが自分の進行方向に上方向を向けるようになります。 テクスチャをはっているか、サイズ変更をして縦横比が違っていると、弓矢の矢の様な飛び方に見えます。

PSYS_PART_INTERP_COLOR_MASKです。設定すると色が変化するようになります。色の設定はカラーピッカーを使用します。上が初期色(およびOFFの時の色)、下が最終色の設定用です。上半分で色相・彩度・輝度を、その下にグレースケール、一番下の赤から青の部分で透明度を指定できます。



PSYS_PART_INTERP_SCALE_MASKです。設定すると大きさが変化するようになります。大きさの指定はカラーピッカーの右にある3本のスライドバーを使用します。同じく、上が初期値、下が最終値になります。 左の白いバーは横・縦を一度に設定するバーになります。赤は横幅、緑は縦幅です。

PSYS_PART_WIND_MASKです。 パーティクルが風に流されるようになります。

PSYS_PART_TARGET_LINEAR_MASKです。パーティクルが指定の対象に一直線に向かっていきます。 対象指定はマウスルックになって対象をクリックしてください。玉が命中した人かオブジェクトが対象になります。

PSYS_PART_TARGET_POS_MASKです。進行方向以外に加速度が働いているとき、パーティクルが指定の対象に放物線を描いて飛んでいきます。 同じく、対象指定はマウスルックになって対象をクリックしてください。玉が命中した人かオブジェクトが対象になります。

PSYS_SRC_PATTERN_EXPLODEです。 パーティクルが四方八方に飛び出します。

PSYS_SRC_PATTERN_ANGLEです。パーティクルは平たい円のように出ます。 http://rbk.slmame.com/e695786.html

PSYS_SRC_PATTERN_ANGLE_CONEです。パーティクルは円錐のように出ます。 http://rbk.slmame.com/e695786.html

PSYS_SRC_PATTERN_DROPです。 パーティクルはその場に出現します。



数値パラメーター


装置中央付近の長いスライドバーを使用して設定します。
白は1数値用、赤はXまたは始点、緑はYまたは終点、青はZを指定するために使います。
使用しないバーは黒色になり、タッチしても動きません。

PSYS_SRC_BURST_PART_COUNTです。バーで指定した値に最も近い整数に四捨五入されます。 一度に放出されるパーティクルの粒の数になります。

PSYS_PART_MAX_AGEです。 パーティクルの寿命になります。(秒)

PSYS_SRC_MAX_AGEです。パーティクルが出なくなるまでの時間になります。(秒) 0にすると永久にパーティクルを出し続けます。

PSYS_SRC_BURST_RADIUSです。 放出プリムの中心とパーティクルの出現位置の距離(隙間)になります。(メートル)

PSYS_SRC_ANGLE_BEGINとPSYS_SRC_ANGLE_ENDです。
コーンまたは扇形にパーティクルを出している際の、円弧の形状になります。

PSYS_SRC_BURST_RATEです。パーティクルが放出される時間間隔になります(秒)。 0にすると連続放出になります。

PSYS_SRC_BURST_SPEED_MINとPSYS_SRC_BURST_SPEED_MAXです。 パーティクルの初速の最小値と最大値になります。(メートル毎秒)

PSYS_SRC_ACCELです。 パーティクルが飛んでいる間に受ける加速度をXYZ方向について指定します。(メートル毎秒)

PSYS_SRC_OMEGAです。放出されるパーティクルの放出面や方向が回転する角度になります。(ラジアン毎秒) 指定するとパーティクルの放出方向や面がぐるぐる回ります。

その他のボタン


押すとアクティブになっているスライドバーの値が現在設定の倍率表示で最低になります。押すと反映される値は上にテキストで表示されています。

押すとアクティブになっているスライドバーの値が現在設定の倍率表示で最大になります。押すと反映される値は上にテキストで表示されています。

押すとアクティブなスライドバーの刻みが10倍になります。(縮小ツールもどき)

押すとアクティブなスライドバーの刻みが10分の1になります。(拡大ツールもどき)

頭がところてんになってしまった場合にこれを押すと、すべてを無かった事にできます。または、押してしまった方の頭をところてんにします。

完成時に押すと、スクリプト生成用のコードを「ささやき」で装置が話します。



テクスチャーと飛んでいくターゲットの設定


テクスチャーを生成装置の、パーティクルを飛ばしている方のコンテンツに入れるとそのテクスチャーを採用します。UUID指定の場合は最終段階に、スクリプト生成ファイルに設定することになります。

PSYS_PART_TARGET_LINEAR_MASKやPSYS_PART_TARGET_POS_MASKを指定して特定のオブジェクトに向けてパーティクルを飛ばす場合は、マウスルックボタンを押してマウスルックになった後に対象をクリックしてください。
または、REZして使用しておられる場合は、ParticleSrcタッチのダイアログで出る「Popgun」を押して、送られてきたPopgunを装備してマウスルックになり、対象となるオブジェクトに玉を命中させてください。
いずれも玉が人か物体に命中すると、それに向かってパーティクルが飛んでいくようになります。
砂場で設定する際はBANされないようにあらかじめ周囲の方に断るほうが良いでしょう。



展開


ParticleSrcをタッチして現れるダイアログから、「HTML」を選ぶとスクリプト生成用のソースがかかれたノートが送られてきます。
その内容をPC上にHTMLファイル(拡張子.htmlまたは.htm)として保存し、ファイルをダブルクリックしてブラウザで表示させてください。
次に、表示されたテキスト入力枠に「ささやき」のコードを貼り付け、Generateボタンを押すと放出LSLスクリプトが生成されます。



生成されたスクリプトをプリムのスクリプトにペーストして保存すれば出来上がりです。
生成してくるスクリプトは、
http://miz.slmame.com/e1733.html
を利用させていただきました。m(__)m
  


Posted by RBK Drachnyd(しお) at 16:33Comments(2)作成物/製品
2009年12月04日

lsl 特定の面のサイズと4隅のリージョン座標を取得する

あってしかるべき物の様な気もするのですが、見つからなかったので作りました。

手計算すれば求まりますが、テーパーが入った上に上部が入っていたり、形状がややこしいと私のように計算に弱い頭は、すぐにところてんになってしまいますので、タッチイベントで取得できるタッチ位置のリージョン座標と、面上のST座標を利用して数値計算で割り出すことにします。(といいますか代換手段がみつかるまでは一度作ってしまえば楽ができますので。。。(笑))

タッチされた面上のST座標は単純にプリムにマス目テクスチャを貼り付けたときの歪みと一致している様で、下の画像の様に左下と右上を結ぶ対角線を境にして座標系が折れ曲がっています。(白線がその対角線)




このとき、




のような図を考えますと、llDetectedTouchST()関数で取得できる面上の座標(S,T)は、対角線の下半分(青色の部分)で、Sは下底に平行、Tは右辺に平行に値が変化しますので、結局、タッチした点PのリージョンベクトルVPは、

VP=V0+HR*T+WB*S

となります。
未知数(未知ベクトル?)がV0、HR、WBの3つですので、青色部分の範囲内で3点をタッチして連立方程式にすれば、これらの情報は求まります。

VP1=V0+HR*T1+WB*S1
VP2=V0+HR*T2+WB*S2
VP3=V0+HR*T3+WB*S3

この連立方程式は展開してもベクトルの割り算を含みませんので、幸いなことに高校数学程度の知識でも解く事が出来ました。^^;


平行四辺形と三角形はこれで全て算出できますが、上図のような任意の四角形の場合には対角線より上のもう一点をタッチし、同じように左辺と上底の関係で現した式に入れれば求まることになります。
3点タッチの時点で3頂点に関する情報が求まっていますので、4点目はただの代入になります。

VTL=(P4-S4*VRT-(1-T4)*V0)/(T4-S4)

末尾は3点・4点タッチでグローバル変数に計算結果を入れるサンプルスクリプトです。
式の展開結果は、http://www.usamimi.info/~geko/arch_acade/elf001_simult/index.htmlを検索していて見つけました。利用させていただきました。

// www.lsleditor.org  by Alphons van der Heijden (SL: Alphons Jano)
//*****************************************************************************************
//メッセージ類
//*****************************************************************************************
string ERR_TOO_NEAR="";
setTextMessage()
{
if (llGetAgentLanguage(llGetOwner())=="ja")
{
//日本語
ERR_TOO_NEAR="選択した点が近すぎます";
}
else
{
//その他
ERR_TOO_NEAR="The touched point is too near.";
}
}
//*****************************************************************************************
//初期化
//*****************************************************************************************
vector E1=ZERO_VECTOR;
vector E2=ZERO_VECTOR;
vector E3=ZERO_VECTOR;
vector E4=ZERO_VECTOR;
 
vector ST1=ZERO_VECTOR;
vector ST2=ZERO_VECTOR;
vector ST3=ZERO_VECTOR;
vector ST4=ZERO_VECTOR;
 
integer face1=-1;
integer face2=-2;
integer face3=-3;
integer face4=-4;
 
vector V0;
vector VRT;
vector VLT;
vector HL;
vector HR;
vector WT;
vector WB;
init()
{
setTextMessage();
}
default
{
state_entry()
{
init();
}
touch_start(integer total_number)
{
face4=llDetectedTouchFace(0);
E4=llDetectedTouchPos(0);
ST4=llDetectedTouchST(0);
if (face1!=face4)
{
if (llVecDist(E3,E4)<0.05 || llVecDist(E2,E4)<0.05)
{
llOwnerSay(ERR_TOO_NEAR);
face1=-1;
face2=-2;
face3=-3;
face4=-4;
E1=ZERO_VECTOR;
E2=ZERO_VECTOR;
E3=ZERO_VECTOR;
E4=ZERO_VECTOR;
return;
}
face2=-2;
face3=-3;
face1=face4;
E1=E4;
ST1=ST4;
return;
}
else if (face2!=face4)
{
if (llVecDist(E1,E4)<0.05 || llVecDist(E3,E4)<0.05)
{
llOwnerSay(ERR_TOO_NEAR);
face1=-1;
face2=-2;
face3=-3;
face4=-4;
E1=ZERO_VECTOR;
E2=ZERO_VECTOR;
E3=ZERO_VECTOR;
E4=ZERO_VECTOR;
return;
}
face2=face4;
E2=E4;
ST2=ST4;
return;
}
else if (face3!=face4)
{
if (llVecDist(E1,E4)<0.05 || llVecDist(E2,E4)<0.05)
{
llOwnerSay(ERR_TOO_NEAR);
face1=-1;
face2=-2;
face3=-3;
face4=-4;
E1=ZERO_VECTOR;
E2=ZERO_VECTOR;
E3=ZERO_VECTOR;
E4=ZERO_VECTOR;
return;
}
face3=face4;
E3=E4;
ST3=ST4;
 
float A1=1.0;
float A2=1.0;
float A3=1.0;
float B1=ST1.y;
float B2=ST2.y;
float B3=ST3.y;
float C1=ST1.x;
float C2=ST2.x;
float C3=ST3.x;
//座標原点(左下)
V0=(E1*B2*C3+E2*B3*C1+E3*B1*C2-E1*B3*C2-E2*B1*C3-E3*B2*C1)/(A1*B2*C3+A2*B3*C1+A3*B1*C2-A1*B3*C2-A2*B1*C3-A3*B2*C1);
//下底ベクトル
WB=(A1*B2*E3+A2*B3*E1+A3*B1*E2-A1*B3*E2-A2*B1*E3-A3*B2*E1)/(A1*B2*C3+A2*B3*C1+A3*B1*C2-A1*B3*C2-A2*B1*C3-A3*B2*C1);
//右辺ベクトル
HR=(A1*E2*C3+A2*E3*C1+A3*E1*C2-A1*E3*C2-A2*E1*C3-A3*E2*C1)/(A1*B2*C3+A2*B3*C1+A3*B1*C2-A1*B3*C2-A2*B1*C3-A3*B2*C1);
 
//座標最大点(右上)
VRT=V0+WB+HR;
}
else
{
if (llVecDist(E1,E4)<0.05 || llVecDist(E2,E4)<0.05 || llVecDist(E3,E4)<0.05)
{
llOwnerSay(ERR_TOO_NEAR);
face1=-1;
face2=-2;
face3=-3;
face4=-4;
E1=ZERO_VECTOR;
E2=ZERO_VECTOR;
E3=ZERO_VECTOR;
E4=ZERO_VECTOR;
return;
}
//左辺上の頂点
VLT=(E4-ST4.x*VRT-(1.0-ST4.y)*V0)/(ST4.y-ST4.x);
//左辺ベクトル
HL=VLT-V0;
//上辺ベクトル
WT=VRT-VLT;
face1=-1;
face2=-2;
face3=-3;
face4=-4;
E1=ZERO_VECTOR;
E2=ZERO_VECTOR;
E3=ZERO_VECTOR;
E4=ZERO_VECTOR;
}
}
}
  


Posted by RBK Drachnyd(しお) at 21:04Comments(0)算数