うしブログ

うしブログ

趣味で運営する、GeoGebraの専門ブログ。

(作業メモ)StartPoint要検証(2行の場合;テキスト変更時未定義問題)

(要修復)ToggleButton・RollPolygonWithoutSlipping・貯金時計・直感力トレーニング

(web版GeoGebra限定)スライダーの情報を取得するJavaScript関数

//スライダーの情報を取得(戻り値eval済み)
function getSliderInfo(name) {
    //xmlデータを取得
    var xmlStr = ggbApplet.getXML(name);

    //DOMにパース
    var parser = new DOMParser();
    var dom = parser.parseFromString(xmlStr, "text/xml");

    //sliderタグ内の情報を取得
    var sld = dom.getElementsByTagName('slider');

    //オブジェクトがスライダーでない場合、undefinedを返して終了
    if (sld.length == 0) {
        return undefined;
    }

    //オブジェクトとしてアウトプット
    var output = new Object();
    for (var k = 0; k < sld[0].attributes.length; k++) {
        var nameText = sld[0].attributes[k].name;
        var val = sld[0].attributes[k].value;
        output[nameText] = eval(val);
    }

    //始点
    var startX = output.x;
    var startY = output.y;
    if (output.absoluteScreenLocation) {
        startX = ggbApplet.getValue('x(Corner[1])+(x(Corner[3])-x(Corner[1]))*((' + startX + '+1)/(x(Corner[5])+2))');
        startY = ggbApplet.getValue('y(Corner[3])-(y(Corner[3])-y(Corner[1]))*((' + startY + '+1)/(y(Corner[5])+2))');
    } //ピクセル座標(画面上固定)の場合
    //console.log('始点:('+startX+','+startY+')');

    //console.log('width='+output.width);

    //終点
    var endX = output.x + (output.horizontal ? output.width : 0);
    var endY = output.y + (output.horizontal ? 0 : output.width);
    if (output.absoluteScreenLocation) {
        endX = ggbApplet.getValue(startX + '+(x(Corner[3])-x(Corner[1]))*((' + (output.horizontal ? output.width : 0) + ')/(x(Corner[5])+2))');
        endY = ggbApplet.getValue(startY + '+(y(Corner[3])-y(Corner[1]))*((' + (output.horizontal ? 0 : output.width) + ')/(y(Corner[5])+2))');
    } //ピクセル座標(画面上固定)の場合
    //console.log('終点:('+endX+','+endY+')');

    //outputに始点・終点情報を記録
    output['startX'] = startX;
    output['startY'] = startY;
    output['endX'] = endX;
    output['endY'] = endY;

    return output;
}

※ローカル版GeoGebraでは機能しません。

 

戻り値のプロパティ名は、以下のとおりである。startX, startY, endX, endY以外は、スライダーのxml情報中、sliderタグの属性から取得している。

f:id:usiblog:20201027213555p:plain

↑スライダーを画面固定した場合。

f:id:usiblog:20201027213713p:plain

↑スライダーを画面固定しない場合。absoluteScreenLocationプロパティが定義されていない点が、画面固定した場合との違いである。

使用例

スライダーa、自由な点オブジェクトStart, Goal, 自由な数値オブジェクト(最小値・最大値の限定無し)min_a, max_aを作成する。

また、点Pを、以下の定義で作成する。

P = Dilate(Goal, (a - min_a) / (max_a - min_a), Start)

グローバル欄に、上記関数を記述する。

aのOn Update ハンドラに、以下を記述する。

//スライダー情報を取得
var info = getSliderInfo('a');

//スライダーの端点の座標を、StartとGoalに記録
ggbApplet.evalCommand('SetValue[Start,(' + info.startX + ',' + info.startY + ')]');
ggbApplet.evalCommand('SetValue[Goal,(' + info.endX + ',' + info.endY + ')]');

//スライダーの最小値、最大値を、min_a, max_aに記録
ggbApplet.evalCommand('SetValue[min_a,' + info.min + ']');
ggbApplet.evalCommand('SetValue[max_a,' + info.max + ']');

すると、aを更新すると、Start, Goalがaのスライダーの端点に移動し、min_a, max_aには、それぞれaのスライダーの最小値・最大値が記録される。

点Pは、aのスライダーの点(ドラッグできる部分)に揃う。

サンプル

スライダー情報を取得 – GeoGebra

 

直線を、楕円の接線に吸い付かせる

課題

自由な点オブジェクトA,B,C,D,E および

楕円c=Ellipse(A, B, C)と、直線f=Line(D, E)がある。

下図のように、直線を動かして、楕円に近づけていって、直線が楕円に接する位置付近に来たときに、接線に吸い付くような挙動を実現するには、どうすればよいか。

f:id:usiblog:20201012183218g:plain

解答例

①Dを動かしたときの処理

DのOn Update スクリプトとして、以下を記述する。

UpdateConstruction()
If(Distance(D,ClosestPoint({Tangent(f, c)}, D))<0.2,SetValue(D,ClosestPoint({Tangent(E, c)}, D)))

②Eを動かしたときの処理

EのOn Update スクリプトとして、以下を記述する。

UpdateConstruction()
If(Distance(E,ClosestPoint({Tangent(f, c)}, E))<0.2,SetValue(E,ClosestPoint({Tangent(D, c)}, E)))

③直線を動かしたときの処理

fを動かすと、同時にE,Fも動くので、上記E,FのOn Update スクリプトが発動してしまう。これは、直線をドラッグ(つまり平行移動)して、傾きを変えずに楕円に外接させる挙動を実現するうえでの障害になる。そこで、fのOn Update ハンドラにスクリプトを記述するのではなく、

g = CopyFreeObject(f)

で、自由な直線オブジェクトgを作成しておき、gに適宜On Update スクリプトを記述していく(fは非表示にしておく)ことにする。

gのOn Update スクリプトとして、以下を記述する。

Execute({"SetValue(D,ClosestPoint(g,D))","SetValue(E,ClosestPoint(g,E))"})
UpdateConstruction()
If(Distance(D,ClosestPoint({Tangent(f, c)}, D))<0.2,Execute({"SetValue(g,Line(ClosestPoint({Tangent(f, c)}, D),g))","SetValue(D,ClosestPoint(g,D))","SetValue(E,ClosestPoint(g,E))"}))

1行目:fをgに揃える。なお、これによってD,E,fの状態が更新されても、D,E,fのOn Updateスクリプトは発動しない。これは、On Updateスクリプトによって更新されたオブジェクトのOn Updateスクリプトは発動しない、というGeoGebraの仕様による。

2行目:1行目を適用した後の状態を前提に、次以降の行を記述するための処理。

3行目:吸い付き処理。

 

fのOn Update スクリプトとして、以下を記述する。

SetValue(g,f)

サンプル

https://www.geogebra.org/m/fdsf69vd

(覚書)wordフィールド

フィールドの作成:command + fn + F9

フィールドの表示・非表示:option + fn + F9

フィールドの更新:Shift + option + command + U または fn + F9

 

現在時刻

2020年10月10日23時27分56秒

{ DATE ¥@ "yyyy年M月d日HH時mm分ss秒" }

"yyyy":4桁西暦(2020)

"yy":2桁西暦(20)

"ge":年号アルファベット+年(R2)

"ggge":年号漢字+年(令和2)

"M":月※パディングなし(10, 4)

"MM":月※2桁ゼロパディング(10, 04)

 

"H":24時間表記

"h":12時間表記

"am/pm":AMまたはPM

"AMPM":午前または午後

 

参考

http://office-qa.com/Word/wd626.htm