2011-12-18 2 views
3

После выполнения сложной серии поворотов и переводов я хочу вернуть текущее направление на «Север», указывающее вверху страницы. Как я могу это сделать?Поверните на север

Очевидный ответ - следить за тем, какое направление я указываю при каждом переводе, но это похоже на большую работу. Я хочу что-то вроде «0 rotateto», которое оставляет меня в текущем местоположении, но указывает на абсолютный верх страницы; Аналогичным образом, «90 rotateto» будет указывать правильно.

Я также хочу знать, как перейти к определенной точке на странице после серии поворотов и переводов. Другими словами, я ищу инструкцию «абсолютного moveto», которая перемещается в определенную точку, а не относительно текущих переведенных координат.

Моя цель - создать черепаху в стиле логотипа. Две команды, которые распознает черепаха, - это setpos (которая перемещается в абсолютное положение) и setorientation (которая вращается в абсолютном направлении). Я пытаюсь понять, как реализовать эти команды в PostScript.

EDIT 1:

Благодаря LUSER Droog, но что-то все-таки не так. Моя библиотека включает команды черепахи, показанные ниже, с их эквивалентами PostScript; rotateto и setpos являются определением вы дали ранее, is_penup глобальной переменную первоначально устанавливается истина, и я еще не рассматривал позы и ориентацию, которые сообщают текущее абсолютное положение х и ориентацию черепахи:

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 

Пример, который рисует два квадрата, показан ниже; квадрат команда записывает четыре строки длины 50, каждый из которых сопровождается 90 градусов поворота направо:

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

Но это не работает. Ни одна из команд setpos не выполняется. Есть два квадрата, а второй квадрат наклонен на 45 градусов, но оба начинаются в центре страницы. Я боюсь, что каждый раз, когда я говорю, перевод текущей точки, я вмешиваюсь в то, что вы делаете в своей команде setpos.

Можете ли вы предложить какие-либо предложения?

EDIT 2:

я решил не беспокоиться о возвращении текущего положения и ориентации на схему; это слишком много работы для моей текущей цели, хотя это может быть полезно когда-нибудь в будущем. Окончательная версия моего кода схемы показана ниже. Отправить - обычная утилита, turtle-init определяет библиотеку черепах в PostScript, далее следует черепаховая библиотека Scheme, затем примерная программа, которая рисует два квадрата. Все работает отлично.

(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))) 

Это все появляются в моем blog некоторое время в январе; Я еще не уверен в точной дате.

Спасибо!

EDIT 3:

Я вернулся и прочитать документацию для логотипа черепахи, и обнаружил, что setpos чтит текущее состояние пера; таким образом, если перо не работает, setpos пишет строку из старой позиции в новую позицию.Я изменил setpos, чтобы иметь правильное поведение:

/setpos { defmat transform itransform is-pendown 
    { lineto } { moveto } ifelse fix } def 

Я также изменил черепаха иниц так, что он на самом деле вызывает инициализации вместо того, чтобы просто его определения. Не много пользы, если вы никогда не называете это.

+0

Как вы переводите с Кембриджа на Польский на обратный польский? Вы выводите постскриптум из другой программы? –

+0

Библиотека будет написана на Схеме. Перевод на PostScript не сложно. Однако вывод PostScript, который я хочу перевести, вызывает проблемы. – user448810

+0

Какой-то Лисп кажется хорошим выбором. Если можно, сообщите нам ссылку, когда она работает. :) –

ответ

3

Ну, для начала, ось y указывает север по умолчанию. Поэтому любые нормальные переводы и вращения могут быть сброшены с помощью matrix defaultmatrix setmatrix. Вы можете сбросить масштабирование и вращение без изменения перевода с помощью чего-то вроде matrix currentmatrix dup 0 matrix defaultmatrix 0 4 getinterval putinterval setmatrix.

Если вы можете игнорировать масштабирование, вы могли бы сделать rotateto (предполагается, что текущее положение является источником пользовательского пространства), как это:

/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 

Чтобы установить абсолютную позицию, вам нужно сделать несколько преобразования.

Обычно любые указанные координаты относятся к пользовательскому пространству. Это означает, что они будут умножены на Матрицу трансформации тока до вступления в силу. Для установки «абсолютной» позиции подразумевается интерпретация координат как относящаяся к «абсолютному пространству». Единственное такое привилегированное пространство - это матрица по умолчанию.

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

Edit: Это сложно материал! Я смог получить ваш тест для работы с этим набором процедур.

%! 
/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

Здесь есть что-то хорошее. Я планировал делать все эти определения в библиотеке черепахи-графики Scheme, а не в PostScript, но они тоже работают здесь. Для pos и ориентации идея состоит в том, чтобы «вернуть» значения обратно в сценарий Scheme, но я не уверен, как это сделать. Спасибо за вашу помощь. – user448810

+0

@ user448810 Как вернуть значения было бы хорошим вопросом. Простейшим может быть именованный канал. –

2

«moveto» PostScript является абсолютным moveto, а не относительным. В PostScript, если вы хотите относительный moveto, вы используете rmoveto. Тем не менее, нет принципиально никакого доступа к пространству устройства. PostScript имеет два пространства теоретически бесконечно тонкое пространство пользователя и пространство устройства, которое фактически печатается и имеет разрешение выходного устройства. Current Transformation Matr4ix (CTM) отображает пространство пользователя на пространство устройства.

Вы не можете получить доступ к пространству устройства напрямую, все операции PostScript выполняются через CTM. Таким образом, нет способа адресовать абсолютную точку в пространстве устройства, и поэтому нет никакого «абсолютного moveto» в том смысле, о котором вы просите, все точек в пространстве пользователя преобразуются через CTM, чтобы добраться до места устройства.

Нет никакого «направления» в том смысле, что у черепахи Logo есть один из них, из любой точки, которую вы можете перемещать прямо в любую другую точку, нет необходимости вообще вращаться.

Если вы вращаете CTM, тогда да, вам действительно нужно следить за этим. Вы можете сбросить CTM несколькими способами. Вы можете gsave/grestore вокруг серии операций. Обратите внимание, что это сбросит все, включая текущую точку и путь. Если вы хотите сохранить текущую точку, тогда «gsave ..... currentpoint grestore moveto» сделает это.

В качестве заметок luser droog вы можете использовать setmatrix по умолчанию, или вычислить свою собственную матрицу и использовать setmatrix, например «currentmatrix invertmatrix concat setmatrix».

Но в целом вы вращаете CTM только для специальных эффектов, таких как резка или рисование изображений и т. Д., А обычная технология PostScript - gsave/grestore вокруг таких последовательностей.

Вместо отслеживания CTM вы можете отслеживать текущее направление черепахи и применять геометрию для расчета нового положения после того, как черепаха перемещается на заданное расстояние в этом направлении, что может упростить вашу проблему.

+0

Drat! Я думаю ты прав. Простое поддержание/направление в градусах не было бы слишком сложным (просто «360 мод», чтобы сохранить его разумным). Тогда вы могли бы просто «разобраться»? {rmoveto} {rlineto} ifelse'. И вообще никаких матриц!В зависимости от того, как инвестировал @ user448810 в текущий ход мыслей, это может быть хорошим вариантом для рассмотрения проекта 2. –

2

Крадущая идея Кена, и с дальнейшим пониманием того, что вы пытаетесь сделать (от вашего blog), Вот псевдо-оо постскриптум черепахи.

%! 
/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

месяцев спустя ...

Мы все идиоты! Там, безусловно, is «абсолютная» система координат: пространство устройства! Конечно, операторы moveto и currentpoint взаимодействуют с вашей программой в CTM-относительных координатах, вы можете вручную «отменить» преобразование, чтобы «взять абсолютную позицию» и «переделать» его позже, чтобы преобразовать в CTM-относительные координаты.

В этом примере используется OO-Turtle и набор макро-расширений для выполнения системы Lindenmayer со встроенными преобразованиями (кружево Queen Anne's Lace).

Queen Anne's Lace

И волшебные линии:

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

Вы можете оставить их в стеке, сохраните их в переменной. Пока вы не свалили матрицу туда, где точка больше не ссылается (коэффициент масштабирования 0), она все равно будет ссылаться на ту же позицию, когда itransform ed относительно любой матрицы, которая является текущей.

Я оставил старый, утомительный способ присутствовать в комментариях, поэтому полный ужас его может служить предупреждением потомкам.

%! 
%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