2011-12-18 9 views
3

複雑な一連の回転と平行移動を行った後、現在の方向をページの上部を指す「北」に戻したいと思います。どうやってやるの?北に回転

明白な答えは、私が翻訳するたびにどの方向を指しているかを把握することですが、それは多くの作業のようです。私は現在の場所に私を残すが、ページの絶対的なトップを指し示す "0回転"のようなものが欲しい。同様に、「90回転」は右を指す。

また、一連の回転と平行移動の後、ページ上の特定のポイントに移動する方法も知りたいと思います。言い換えれば、私は現在の変換座標に関係なく、特定のポイントに移動する "絶対移動"命令を探しています。

私の目的は、ロゴスタイルのカメを実装することです。カメが認識する2つのコマンドは、setpos(絶対位置に移動する)とsetorientation(絶対方向に回転する)です。これらのコマンドをPostScriptで実装する方法を理解しようとしています。

EDIT 1:ドローグluser

おかげで、しかし何かがまだ間違っています。私の図書館には、以下のようなPostScriptのカメコマンドが含まれています。

init    -- %! 
        /rotateto { ... } bind def 
        /setpos { ... } def 
        newpath 
        306 396 moveto % center 8.5x11 portrait 
        0 setgray 2 setlinewidth 
penup   -- % set global variable is_penup to true 
pendown   -- % set global variable is_penup to false 
forward n  -- if is_penup then 0 n rmoveto currentpoint translate 
           else 0 n rlineto currentpoint translate 
backward n  -- if is_penup then 0 n neg rmoveto currentpoint translate 
           else 0 n neg rlineto currentpoint translate 
right n   -- n neg rotate 
left n   -- n rotate 
setpos x y  -- x y setpos 
setorientation n -- n rotateto 
done    -- stroke newpage 
pos    -- get current absolute x y position 
orientation  -- get current absolute orientation 
:rotatetoとsetposはis_penup最初にtrueに設定されたグローバル変数であり、私はまだ亀の現在の絶対XY位置と向きを報告posと方向性を考慮していない、あなたが以前に与えた定義であります

2つの四角形を描画する例を以下に示します。 squareコマンドは長さ50の4行を書き込み、その後にそれぞれ90度の右折を行います。

init 
pendown 
setpos 100 100 
square 50 
setpos 400 400 
right 45 
square 25 
done 

しかし、これは機能しません。どちらのsetposコマンドも尊重されません。 2つの正方形があり、2つ目の正方形は45度で傾けられていますが、どちらもページの中央から始まります。私がcurrentpointを翻訳するたびにsetposコマンドでやっていることに干渉するのではないかと心配しています。

提案はありますか?

EDIT 2:

私はスキームに現在の位置と方向を返す心配しないことにしました。それは私の現在の目的のためにはあまりにも多くの仕事ですが、将来はいつか役に立つかもしれません。私のスキームコードの最終版を以下に示します。 Sendは共通のユーティリティで、turtle-initはPostScriptのTurtleライブラリを定義し、Scheme Turtleライブラリの残りの部分は次に、2つの四角形を描画するサンプルプログラムを定義します。それはすべて正常に動作します。

(define (send x . xs) 
    (cond ((null? xs) (display x) (newline)) 
    (else (display x) (display " ") (apply send xs)))) 

(define (turtle-init) 
    (for-each send '(
    "%!" 
    "/defmat matrix defaultmatrix def" 
    "/fix { currentpoint translate } def" 
    "/rotateto { matrix rotate" 
    " dup 4 matrix currentmatrix 4 2 getinterval" 
    " putinterval setmatrix } def" 
    "/setpos { defmat transform itransform moveto fix } def" 
    "/left { rotate } def" 
    "/right { neg rotate } def" 
    "/is-pendown false def" 
    "/penup { /is-pendown false def } def" 
    "/pendown { /is-pendown true def } def" 
    "/done { stroke showpage } def" 
    "/init { initgraphics 306 396 moveto fix 0 setgray 2 setlinewidth } def" 
    "/forward { 0 exch is-pendown { rlineto } { rmoveto } ifelse fix } def" 
    "/backward { 0 exch is-pendown { rlineto } { rmoveto } ifelse fix } def"))) 
(define (turtle-penup) (send "penup")) 
(define (turtle-pendown) (send "pendown")) 
(define (turtle-forward n) (send n "forward")) 
(define (turtle-backward n) (send n "backward")) 
(define (turtle-right n) (send n "right")) 
(define (turtle-left n) (send n "left")) 
(define (turtle-setpos x y) (send x y "setpos")) 
(define (turtle-setorientation n) (send n "rotateto")) 
(define (turtle-done) (send "stroke showpage")) 

(define (square n) 
    (do ((i 4 (- i 1))) ((zero? i)) 
    (turtle-forward n) (turtle-right 90))) 

(define (squares) 
    (turtle-init) 
    (turtle-pendown) 
    (turtle-setpos 100 100) 
    (square 50) 
    (turtle-setpos 400 400) 
    (turtle-right 45) 
    (square 25) 
    (turtle-done)) 

(with-output-to-file "squares.ps" 
    (lambda() (squares))) 

これはすべて1月中に私のblogに表示されます。私はまだ正確な日付がわからない。

ありがとうございます!

EDIT 3:

私は戻って、ロゴ亀のドキュメントを読み、setposはペンの現在の状態を尊重することを発見しました。したがって、ペンが停止している場合、setposは古い位置から新しい位置に行を書き出します。私は正しい動作をするためにsetposを変更しました:私はturtle-initも単に定義するのではなくinitを実際に呼び出すようにturpon-initを変更しました。あなたが決してそれを呼び出すことはあまりありません。

+0

どのようにケンブリッジポーランド語から逆ポーランド語に翻訳していますか?あなたは別のプログラムからポストスクリプトを出力していますか? –

+0

ライブラリはSchemeで記述されます。 PostScriptへの翻訳は難しくありません。しかし私が翻訳したいPostScriptを見つけ出すことは問題を引き起こしています。 – user448810

+0

ある種のLispは良い選択のようです。可能であれば、動作しているときに私たちにリンクを与えてください。 :) –

答えて

3

まず、y軸はデフォルトで北を指しています。したがって、通常の翻訳と回転はmatrix defaultmatrix setmatrixでリセットできます。 matrix currentmatrix dup 0 matrix defaultmatrix 0 4 getinterval putinterval setmatrixのようなものを使って、翻訳を変更せずに拡大縮小と回転をリセットすることができます。

/rotateto { % angle rotateto - 
    matrix rotate % create a rotation matrix 
    dup 4 
    matrix currentmatrix 4 2 getinterval %get the current translation 
    putinterval setmatrix % put translation into rot. matrix and install 
} bind def 

が、あなたは、いくつかの操作を行う必要があります、絶対位置を設定するには:

あなたはスケーリングを無視することができる場合、あなたはrotateto行うことができ、このような(現在の位置を想定し、ユーザー空間の原点です)変換。

通常、指定された座標はすべてユーザー空間を参照します。つまり、効果を出す前に、現在の変換マトリックスを乗算します。 「絶対」位置を設定することは、座標を「絶対空間」を参照するものとして解釈することを意味する。そのような特権を与えられた唯一のスペースはDefault Matrixです。

/setpos { % x-abs y-abs setpos - 
    matrix defaultmatrix transform % x' y' %to device space 
    itransform % x y %back to current user space 
    translate 
} def 

編集:これはトリッキーなものです!私はあなたのテストをこの一連の手続きで動作させることができました。私をトリップ

%! 
/defmat matrix defaultmatrix def 
/fix { currentpoint translate } def 
/rotateto { matrix rotate 
    dup 4 matrix currentmatrix 4 2 getinterval 
    putinterval setmatrix } def 
/setpos { defmat transform itransform moveto fix } def 
/left { rotate } def 
/right { neg rotate } def 
/is-pendown false def 
/penup { /is-pendown false def } def 
/pendown { /is-pendown true def } def 
/done { stroke showpage } def 
/init { initgraphics 306 396 moveto fix 0 setgray 2 setlinewidth } def 
/pos { matrix currentmatrix 4 2 getinterval {} forall } def 
/forward { 0 exch is-pendown { rlineto } { rmoveto } ifelse fix } def 
/backward { 0 exch is-pendown { rlineto } { rmoveto } ifelse fix } def 

/square { 4 { dup forward 90 right } repeat pop } def 
init 
pendown 
100 100 setpos 
50 square 
400 400 setpos 
45 right 
25 square 
done 

ことの一つは、(最初​​の移動を含む)すべての動きの後currentpoint translateに思い出しました。

orientationの場合は、マトリックスを「解釈する」必要があります。 提案をする前に、これについて熟考する必要があります。頭が上がる場合、回転行列は[cosA sinA -sinA cosA 0 0]のように見えることに注意してください。

+0

ありがとうございました。私はまだ問題があります。元の質問の上記の私の編集を見てください。 – user448810

+0

ここには良いものがあります。私はPostScriptではなく、Scheme turtle-graphicsライブラリでこれらすべての定義を行うことを計画していましたが、ここでも動作します。 posとorientationについては、値をSchemeスクリプトに返すというアイデアがありますが、どうすればよいか分かりません。あなたのすべての協力に感謝します。 – user448810

+0

@ user448810値を返す方法は良い質問です。最も簡単なのは名前付きパイプかもしれません。 –

2

PostScriptの「moveto」は、絶対移動であり相対的なものではありません。 PostScriptでは相対的な移動をしたい場合はrmovetoを使います。つまり、基本的にデバイススペースへのdiredctアクセスはありません。 PostScriptには理論的に無限に良いユーザー空間と実際に印刷され、出力装置の解像度を持つデバイス空間という2つのスペースがあります。現在の変換Matr4ix(CTM)は、ユーザスペースをデバイススペースにマッピングします。

デバイススペースに直接アクセスすることはできず、すべてのPostScript操作はCTMを介して行われます。したがって、デバイス空間の絶対点に対処する方法はないので、ユーザ空間のすべてのポイントがCTMを介してデバイス空間に変換されます。

ロゴタートルにはいずれかの方向性がありません。いずれのポイントからでも、他のポイントに直接移動できます。まったく回転する必要はありません。

CTMをローテーションすると、本当にそれを把握する必要があります。 CTMは、さまざまな方法でリセットできます。一連の操作をgsave/grestoreすることができます。これは、現在のポイントとパスを含むすべてをリセットすることに注意してください。現在のポイントを保存したい場合は、 'gsave ..... currentpoint grestore moveto'を実行します。

luser droogノートでは、defaultmatrix setmatrixを使用するか、独自の行列を計算してsetmatrix(たとえば、 'currentmatrix invertmatrix concat setmatrix')を使用できます。

しかし一般にCTMはせん断や描画などの特殊効果のためにのみ回転し、通常のPostScript技法はそのようなシーケンスをgsave/grestoreすることです。

タートルの現在の方向を追跡する代わりに、タートルがその方向に所定の距離を移動した後に新しい位置を計算するジオメトリを適用して、問題を単純化することができます。

+0

Drat!あなたが正しいと思います。ちょうど角度で/度を維持することはそれほど難しくありません(ちょうどそれを合理的に保つために '360 mod')。それでは、あなたはちょうど 'r dir cos r dir sin up? {rmoveto} {rlineto} ifelse'。そして行列はまったくありません!現在の思考の列にuser448810がどのように投資されているかによって、これはドラフト2を検討する良い選択肢かもしれません。 –

2

Kenさんのアイデアを盗んで、あなたがしようとしていることの詳細を(blogから)擬似OO追記のカメです。

%! 
/Turtle << 
    /forward { 
     dup Turtle /angle get cos mul 
     exch Turtle /angle get sin mul 
     2 copy 
     Turtle /pen? get { lineto }{ moveto }ifelse 
     translate 
    } 
    /angle 90 
    /pen? false 
    /right { Turtle /angle 2 copy get 4 3 roll sub put } 
    /left { Turtle /angle 2 copy get 4 3 roll add put } 
    >> def 
/send { get exec } def 
/ini { 300 400 2 copy moveto translate } def 

<< %shortcuts 
    /F { 100 Turtle /forward send } 
    /+ { 90 Turtle /right send } 
    /- { 90 Turtle /left send } 
>> begin 

ini 
Turtle /pen? true put 
F + F + F + F 
F + F + F + F 
F + F + F + F 
F + F + F + F 
stroke %draws a four-square 
showpage 
3

ヶ月後...

我々は、すべての馬鹿です!最も確かに "絶対的な"座標系です:デバイススペース!もちろん、演算子movetocurrentpointは、プログラムとCTM相対座標でインターフェイスします。変換を手動で「取り消して」「絶対位置を取る」ことができ、後でCTM相対座標に変換することができます。

この例では、OO-Turtleとマクロ拡張スイートを使用して、組み込み変換(Queen Anne's Lace)を使用してLindenmayerシステムを実行します。

Queen Anne's Lace

と魔法の行は、次のとおりです。

 % ... 
    currentpoint transform % save "absolute" position 
    % ... 
    itransform translate 
    0 0 moveto  % return to saved position 
    % ... 

あなたは変数に保存し、スタック上に残すことができます。ポイントがもはや参照可能ではない場所(0のスケーリングファクタ)に行列を折りたたんでいない限り、itransformが現在の行列と比べて相対的に変化しても、同じ位置を参照します。

コメントの中に古い、退屈なやり方を残してしまったので、それの完全な恐怖が後世の警告として役立つかもしれません。

%! 
%linden.ps 

%one Iteration of macro-expansion 
% traverses an array, replacing tokens 
% defined in the dictionary P, 
% and constructs a new array 
/I { % O I O' 
    mark exch { 
     P exch 2 copy known { 
      get aload pop 
     }{ 
      exch pop 
     } ifelse 
    } forall counttomark array astore exch pop cvx 
} def 
%Generate nth expansion of O 
/G { % n G O'^n 
    /O load exch 
    { I } repeat 
} def 

% n x y x - 
% moveto x y, generate nth expansion of O, stroke, grestore 
/x { moveto gsave G exec stroke grestore } def 


/Turtle << 
    /forward { 
     dup Turtle /angle get cos mul 
     exch Turtle /angle get sin mul 
     2 copy 
     Turtle /pen? get { lineto }{ moveto }ifelse 
     translate 
    } 
    /angle 90 
    /pen? false 
    /right { Turtle /angle 2 copy get 4 3 roll sub put } 
    /left { Turtle /angle 2 copy get 4 3 roll add put } 
    >> def 
/send { get exec } def 
/ini { 300 400 2 copy moveto translate } def 

<< %shortcuts 
    /F { R Turtle /forward send } 
    /+ { T Turtle /right send } 
    /- { T Turtle /left send } 
>> begin 

ini 

{ %branching stems 
/V << % description of the Lindenmeyer System 
    /#0 {F leaf} 
    /#1 {F} 

    /O { #0 } % Original 
    /P << % Productions 
     /#0 { #1 [ - #0 ] + #0 } 
     /#1 { #1 #1 } 
     >> 
    /R 10 
    /T 45 
    /leaf { 0 0 R 2 mul 0 180 arc 0 0 moveto } 
>> def 
V begin 
0 -300 translate 
.5 .5 scale 
Turtle /pen? true put 

gsave 
    %"Special" Definitions 
    % The brackets in the procedure resulting 
    % from the expansion of /O are not used to 
    % construct arrays, but to save and reset 
    % the position and angle of the Turtle. 
    ([) { 
     %matrix currentmatrix 4 2 getinterval aload pop 
     currentpoint transform 
     Turtle /angle get 
    } def 
    (]) { 
     Turtle /angle 3 2 roll put 
     %matrix currentmatrix % Tx Ty M 
     %dup 4 5 4 roll put % Ty M 
     %dup 5 4 3 roll put % M 
     %setmatrix 
     itransform translate 
     0 0 moveto 
    } def 
    .5 .5 scale 
    8 0 0 x % execute 8-level-deep expansion of /O in /V 
grestore 

end showpage 
} exec