% $Id: dcpic.sty,v 1.31 2007/12/13 17:34:57 pedro Exp pedro $ %% DC-PiCTeX %% Copyright (c) 1990-2007 Pedro Quaresma de Almeida, Coimbra %% 11/1990 (version 1.0); %% 10/1991 (version 1.1); %% 9/1993 (version 1.2); %% 3/1995 (version 1.3); %% 7/1996 (version 2.1); %% 5/2001 (version 3.0); %% 11/2001 (version 3.1); %% 1/2002 (version 3.2) %% 5/2002 (version 4.0); %% 3/2003 (version 4.1); %% 12/2004 (version 4.1.1) %% 3/2007 (version 4.1.2) \immediate\write10{Package DCpic 2007/03/01 v4.1.2} \ProvidesPackage{dcpic}[2007/03/01 v4.1.2] %% Version X.Y.Z %% X - major versions %% Y - minor versions %% Z - bug corrections %% %% Copyright (c) 1990-2007 Pedro Quaresma %% The DCpic package is free software; you can redistribute it and/or %% modify it under the terms of the GNU General Public License as %% published by the Free Software Foundation; either version 2 of the %% License, or (at your option) any later version. %% %% The DCpic package is distributed in the hope that it will be %% useful, but WITHOUT ANY WARRANTY; without even the implied warranty %% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU %% General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this package; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %% %% Coimbra, 13 de Dezembro de 2007 %% Pedro Quaresma de Almeida %% %% DCpic is a package of \TeX\ macros for graph modelling in a %% (La)\TeX\ or Con\TeX t document. Its distinguishing features are: %% the use of \PiCTeX\ a powerful graphical engine, and a simple %% specification syntax. A graph is described in terms of its objects %% and its edges. The objects are textual elements and the edges can %% have various straight or curved forms. %% %% %% A graph in DCpic is a "picture" in \PiCTeX, in which we place our %% {\em objects} and {\em morphisms} (edges). The user's commands in %% DCpic are: {\tt begindc} and {\tt enddc} which establishe the %% coordinate system where the objects will by placed; {\tt obj}, the %% command which defines the place and the contents of each object; %% {\tt mor}, and {\tt cmor}, the commands which define the %% morphisms, linear and curved edges, and its labels. %% %% Example: %% \begindc{\commdiag}[3] %% \obj(10,15){$A$} %% \obj(25,15){$B$} %% \obj(40,15){$C$} %% \mor{$A$}{$B$}{$f$} %% \mor{$B$}{$C$}{$g$} %% \cmor((10,11)(11,7)(15,6)(25,6)(35,6)(39,7)(40,11)) %% \pup(25,3){$g\circ f$} %% \enddc %% %% NOTES: %% all the numeric values should be integer values. %% %% Available commands: %% %% The environment: %% \begindc{#1}[#2] %% #1 - Graph type %% 0 = "commdiag" (commutative diagram) %% 1 = "digraph" (direct graph) %% 2 = "undigraph" (undirect graph) %% 3 = "cdigraph" with incircled objects %% 4 = "cundigraph" with incircled objects %% (optional) #2 - magnification factor (default value, 30) %% %% \enddc %% %% Objects: %% \obj(#1,#2)[#3]{#4}[#5] %% #1 and #2 - coordenates %% (optional) #3 - Label, to be used in the morphims command, if not %% present the #4 will be used to that purpose %% #4 - Object contents %% (optional) #5 - placement of the object (default value \north) %% 0="\pcent", center %% 1="\north", north %% 2="\northeast", northeast %% 3="\east", east %% 4="\southeast", southeast %% 5="\south", south %% 6="\southwest", southwest %% 7="\west", west %% 8="\northwest", northwest %% !!! Note !!! %% if you omit the #3 argument (label) and the #4 argument is a %% complex LaTeX command this can cause this command to crash. In %% this case you must specify a label (the empty label [], if you do %% needed it it for nothing). %% %% Morphims (linear edges). This commando has to two major variants %% i) Starting and Ending objects specification %% \mor{#1}{#2}[#5,#6]{#7}[#8,#9] %% %% As you can see this first form is (intencionaly) badly formed, the %% arguments #3 and #4 are missing (the actual command is correctly %% formed). %% %% #1 - The starting object reference %% #2 - The ending object reference %% %% from this two we will obtain the objects coordinates, and also the %% dimensions of the enclosing box. %% %% The objects box dimensions are used to do an automatic adjustment of %% the edge width. %% %% from #1 we obtain (x,y), (#1,#2) in the second form %% from #2 we obtain (x',y'), (#3,#4) in the second form %% %% this values will be passed to the command second form %% %%ii) Two points coordinates specification %% \mor(#1,#2)(#3,#4)[#5,#6]{#7}[#8,#9] %% %% Now we can describe all the arguments %% %% #1 and #2 - coordinates (beginning) %% #3 and #4 - coordinates (ending) %%(optional)#5,#6 - correction factors (defaul values, 10 and 10) %% #5 - actual beginning of the edge %% #6 - actual ending of the edge %% #7 - text (morphism label) %%(optional)#8,#9 %% #8 - label placement %% 1 = \atright, at right, default value %% -1 = \atleft, at left %% #9 - edge type %% 0 = "\solidarrow", default edge %% 1 = "\dasharrow" %% 2 = "\solidline" %% 3 = "\dashline" %% 4 = "\dotline" %% 5 = "\injectionarrow" --- old value 3 %% 6 = "\aplicationarrow" --- old value 4 %% 7 = "\surjectivearrow" --- old value 5 %% %% Note: insert a space after the command. %% %% Curved Morphisms (quadratic edges): %% \cmor(#1) #2(#3,#4){#5}[#6] %% #1 - list of points (odd number) %% #2 - tip direction %% 0 = "\pup", pointing up %% 1 = "\pdown", pointing down %% 2 = "\pright", pointing right %% 3 = "\pleft", pointing left %% #3 and #4 - coordenates of the label %% #5 - morphism label %%(optional)#6 - edge type %% 0 ="\solidarrow", default value %% 1 = "\dasharrow" %% 2 = "\solidline" %% %% Notes: insert a space after the command. %% the space after the list of points is mandatory %% %% Exemples: %%\documentclass[a4paper,11pt]{article} %%\usepackage{dcpic,pictexwd} %% %%\begin{document} %%\begindc[3] %%\obj(14,11){$A$} %%\obj(39,11){$B$} %%\mor(14,12)(39,12){$f$}%[\atright,\solidarrow] %%\mor(39,10)(14,10){$g$}%[\atright,\solidarrow] %%\cmor((10,10)(6,11)(5,15)(6,19)(10,20)(14,19)(15,15)) %% \pdown(2,20){$id_A$} %%\cmor((40,7)(41,3)(45,2)(49,3)(50,7)(49,11)(45,12)) %% \pleft(54,3){$id_B$} %%\enddc %% %%\begindc{\commdiag}[3] %%\obj(10,15)[A]{$A$} %%\obj(40,15)[Aa]{$A$} %%\obj(25,15)[B]{$B$} %%\mor{A}{B}{$f$}%[\atright,\solidarrow] %%\mor{B}{Aa}{$g$}%[\atright,\solidarrow] %%\cmor((10,11)(11,7)(15,6)(25,6)(35,6)(39,7)(40,11)) %% \pup(25,3){$id_A$} %%\enddc %% %%\newcommand{\barraA}{\vrule height2em width0em depth0em} %%\newcommand{\barraB}{\vrule height1.6em width0em depth0em} %%\begindc{\commdiag}[35] %%\obj(1,1)[Gr]{$G$} %%\obj(3,1)[Grstar]{$G_{r^*}$} %%\obj(5,1)[H]{$H$} %%\obj(2,2)[SigmaG]{$\Sigma^G$} %%\obj(6,2)[SigmaH]{$\Sigma^H$} %%\obj(1,3)[Lm]{$L_m$} %%\obj(3,3)[Krm]{$K_{r,m}$} %%\obj(5,3)[Rmstar]{$R_{m^*}$} %%\obj(1,5)[L]{$L$} %%\obj(3,5)[Lr]{$L_r$} %%\obj(5,5)[R]{$R$} %%\obj(2,6)[SigmaL]{$\Sigma^L$} %%\obj(6,6)[SigmaR]{$\Sigma^R$} %%\mor{Gr}{SigmaG}{$\lambda^G$} %%\mor{Grstar}{Gr}{$i_5$}[\atleft,\aplicationarrow] %%\mor{Grstar}{H}{$r^*$}[\atright,\solidarrow] %%\mor{H}{SigmaH}{$\lambda^H$}[\atright,\dasharrow] %%\mor{SigmaG}{SigmaH}{$\varphi^{r^*}$}[\atright,\solidarrow] %%\mor{Lm}{Gr}{$m$}[\atright,\solidarrow] %%\mor{Lm}{L}{$i_2$}[\atleft,\aplicationarrow] %%\mor{Krm}{Lm}{$i_3\quad$}[\atright,\aplicationarrow] %%\mor{Krm}{Rmstar}{$r$} %%\mor{Krm}{Lr}{$i_4$}[\atright,\aplicationarrow] %%\mor{Krm}{Grstar}{$m$} %%\mor{Rmstar}{R}{$i_6$}[\atright,\aplicationarrow] %%\mor{Rmstar}{H}{$m^*$} %%\mor{L}{SigmaL}{$\lambda^L$} %%\mor{Lr}{L}{$i_1\quad$}[\atright,\aplicationarrow] %%\mor{Lr}{R}{$r$} %%\mor{R}{SigmaR}{$\lambda^R$}[\atright,\solidarrow] %%\mor{SigmaL}{SigmaG}{$\varphi^m$}[\atright,\solidarrow] %%\mor{SigmaL}{SigmaR}{$\varphi^r$} %%\mor{SigmaR}{SigmaH}{$\varphi^{m^*}$} %%\enddc %% %%\end{document} %%-----------------//------------- %% Modifica{\c c}{\~o}es (9/1993) %% argumento "dist{\^a}ncia entre as extremidades da seta e os %% objectos" passou a ser opcional; uma nova op{\c c}{\~a}o para as %% "setas" (op{\c c}{\~a}o 3). %% %% 2/3/1995 (vers{\~a}o 1.3) %% foi acrescentado o tipo de seta de aplica{\c c}{\~a}o %% (op{\c c}{\~a}o 4) a dist{\^a}ncia da etiqueta {\`a} seta respectiva %% passou a ser fixa (10 unidades de medida). %% 15/7/1996 (vers{\~a}o 2.1) %% O comando "\mor" passou a ter uma sintaxe distinta. Os %% par{\^a}metros 5 e 6 passaram a ser a dist{\^a}ncia entre os %% objectos e os extremos da seta o par{\^a}metro 7 {\'e} o nome do %% morfismo e os par{\^a}metros 8 e 9, coloca{\c c}{\~a}o do morfismo %% e tipo de morfismo passaram a ser opcionais. %% %% 5/2001 (vers{\~a}o 3.0) %% Implementa{\c c}{\~a}o do comando "\cmor" baseado no comando %% de desenho de curvas quadr{\'a}ticas pelo PiCTeX %% %% 11/2001 (vers{\~a}o 3.1) %% Modifica{\c c}{\~a}o das pontas das setas de forma a estas ficarem %% semelhantes {\`a}s setas (s{\'\i}mbolos) dos TeX. %% %% 1/2002 (vers{\~a}o 3.2) %% Modifica{\c c}{\~a}o dos comandos "obj" e "mor" de forma a introduzir %% a especifica{\c c}{\~a}o l{\'o}gica dos morfismos, isto {\'e}, passa-se a %% dizer qual {\'e} o objecto de partida e/ou o objecto de chegada %% em vez de ter de especificar o morfismo em termos de %% coordenadas. %% Por outro lado o tamanho das setas passa a ser ajustado %% automaticamente em rela{\c c}{\~a}o ao tamanho dos objectos. %% %% 5/2002 (versão 4.0) %% Modificação dos comandos "begindc" e "obj" %% !!! Modificação da sintaxe destes comandos !!! %% O comando "begindc" passou a ter um argumento (obrigatório) %% que nos permite especificar o tipo de grafo que estamos a %% querer especificar: %% "commdiag" (0), para diagramas comutativos %% "digraph" (1), para grafos orientados %% "undigraph" (2), para grafos não orientados %% O comando "obj" modificou a sua sintaxe passou a ter um (após %% a especificação das coordenadas, um argumento opcional, um %% argumento obrigatório, e um argumento opcional. O primeiro %% argumento opcional dá-nos a etiqueta que serve como %% referência para a especificação dos morfismos, na sua %% ausência usa-se o argumento obrigatório para esse efeito, o %% argumento obrigatório dá-nos o "conteúdo" do objecto, nos %% diagramas comutativos é centrado no ponto dado pelas %% coordenadas sendo o argumento seguinte simplesmente ignorado, %% nos grafos o "conteúdo" é colocado numa posição a norte, a %% noroeste, a este, ..., sendo que a posição concreta é %% especificada pelo último dos argumentos deste comando, o %% valor por omissão é o "norte". %% %% 3/2003 (versão 4.1) %% A pedido de Jon Barker criei um novo tipo %% de seta, a seta de sobrejecção. %% Para já a dupla seta só fica bem nas setas horizontais ou %% verticais. %% 12/2004 (versão 4.1.1) %% Nova versão das setas de sobrejecção que corrigue %% completamente os problemas da solução anterior. %% 3/2007 (versão 4.1.2) %% Acrescenta linhas a tracejado e a ponteado %%-----------------//------------- \catcode`!=11 % ***** THIS MUST NEVER BE OMITTED (Ver PiCTeX) \newcount\aux% \newcount\auxa% \newcount\auxb% \newcount\m% \newcount\n% \newcount\x% \newcount\y% \newcount\xl% \newcount\yl% \newcount\d% \newcount\dnm% \newcount\xa% \newcount\xb% \newcount\xmed% \newcount\xc% \newcount\xd% \newcount\ya% \newcount\yb% \newcount\ymed% \newcount\yc% \newcount\yd %% "variáveis globais" \newcount\expansao% \newcount\tipografo% versão 4.0 \newcount\distanciaobjmor% versão 4.0 \newcount\tipoarco% versão 4.0 %\newif\ifarredondada% versão 4.0 (valor inicial "false") \newif\ifpara% %% version 3.2 \newbox\caixa% \newbox\caixaaux% \newif\ifnvazia% \newif\ifvazia% \newif\ifcompara% \newif\ifdiferentes% \newcount\xaux% \newcount\yaux% \newcount\guardaauxa% \newcount\alt% \newcount\larg% \newcount\prof% %% para os ajustes \newcount\auxqx \newcount\auxqy \newif\ifajusta% \newif\ifajustadist \def\objPartida{}% \def\objChegada{}% \def\objNulo{}% %% %% Stack specification %% %% %% Emtpy stack %% \def\!vazia{:} %% %% Is Empty? : Stack -> Bool %% %% nvazia - True if Not Empy %% vazia - True if Empty \def\!pilhanvazia#1{\let\arg=#1% \if:\arg\ \nvaziafalse\vaziatrue \else \nvaziatrue\vaziafalse\fi} %% %% Push : Elems x Stack -> Stack %% \def\!coloca#1#2{\edef\pilha{#1.#2}} %% %% Top : Stack -> Elems %% %% the empty stack is not taken care %% the element is "kept" ("guardado") \def\!guarda(#1)(#2,#3)(#4,#5,#6){\def\id{#1}% \xaux=#2% \yaux=#3% \alt=#4% \larg=#5% \prof=#6% } \def\!topaux#1.#2:{\!guarda#1} \def\!topo#1{\expandafter\!topaux#1} %% %% Pop : Stack -> Stack %% %% the empty stack is not taken care \def\!popaux#1.#2:{\def\pilha{#2:}} \def\!retira#1{\expandafter\!popaux#1} %% %% Compares words : Word x Word -> Bool %% %% compara - True if equal %% diferentes - True if not equal \def\!comparaaux#1#2{\let\argA=#1\let\argB=#2% \ifx\argA\argB\comparatrue\diferentesfalse\else\comparafalse\diferentestrue\fi} \def\!compara#1#2{\!comparaaux{#1}{#2}} %%Comando Interno %% Valor absoluto (absolute value) %% \absoluto{n}{absn} %% entrada %% n - natural %% sa{\'\i}da %% absn - o valor absoluto de n \def\!absoluto#1#2{\n=#1% \ifnum \n > 0 #2=\n \else \multiply \n by -1 #2=\n \fi} %% Name definitions for edge types and directions \def\solidarrow{0} \def\dasharrow{1} \def\solidline{2} \def\dashline{3} \def\dotline{4} \def\injectionarrow{5} \def\aplicationarrow{6} \def\surjectivearrow{7} %% Name definitions for edge label placement \def\atright{-1} \def\atleft{1} %% Tip direction for curved edges \def\pup{0} \def\pdown{1} \def\pright{2} \def\pleft{3} %% Type of graph \def\commdiag{0} \def\digraph{1} \def\undigraph{2} \def\cdigraph{3} \def\cundigraph{4} %% Posicionamento da etiquetas nos grafos \def\pcent{0} \def\north{1} \def\northeast{2} \def\east{3} \def\southeast{4} \def\south{5} \def\southwest{6} \def\west{7} \def\northwest{8} %%Comando Interno %% Ajusta a dist{\^a}ncia entre as setas e os objectos em fun{\c c}{\~a}o das %% dimens{\~o}es destes {\'u}ltimos %% \ajusta{x}{xl}{y}{yl}{d}{Objecto} %% entrada %% (x,y) e (xl,yl), coordenadas dos pontos de {\'\i}nicio e fim da seta %% d, dist{\^a}ncia especificada pelo utilizador ou 10 (valor por %% omiss{\~a}o), Objecto d{\'a}-nos a refer{\^e}ncia do objecto ao qual se est{\'a} a %% efectuar o ajuste. %% sa{\'\i}da %% d, dist{\^a}ncia alterada. %% %% A dist{\^a}ncia alterada {\'e} o maior valor entre 10 e as dimens{\~o}es %% apropriadas da caixa que cont{\^e}m o objecto. %% Se o utilizador especificar um valor essa especifica{\c c}{\~a}o %% n{\~a}o {\'e} alterada. %% %% Se a seta {\'e} horizontal usa-se o valor da largura %% Se a seta {\'e} vertical usa-se: %% o valor da altura se a seta est{\'a} no 1o ou 2o quadrante %% o valor da profundidade se a seta est{\'a} no 3o ou 4o quadrante %% Se a seta {\'e} {\'o}bliqua vai-se escolher o valor conforme: %% de 315 a 45 graus usa-se a largura %% de 45 a 135 graus usa-se a altura %% de 135 a 225 graus usa-se a largura %% de 225 a 315 graus usa-se a profundidade \def\!ajusta#1#2#3#4#5#6{\aux=#5% \let\auxobj=#6% \ifcase \tipografo % diagramas comutativos \ifnum\number\aux=10 \ajustadisttrue % se o valor é o valor por omissão ajusta \else \ajustadistfalse % caso contrário não ajusta \fi \else % grafos (dirigidos, não dirigidos, com molduras) \ajustadistfalse % \or % grafos não dirigidos % \ajustadistfalse % \else % grafos dirigidos com molduras circulares nos objectos % \ifnum\number\aux=8 % \ajustadisttrue % se o valor é o valor por omissão ajusta % \else % \ajustadistfalse % caso contrário não ajusta % \fi \fi \ifajustadist % \tiny Vou ajustar %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \ifnum\number\aux=10% verificar se s{\~a}o os valores por omiss{\~a}o \let\pilhaaux=\pilha% \loop% \!topo{\pilha}% \!retira{\pilha}% \!compara{\id}{\auxobj}% \ifcompara\nvaziafalse \else\!pilhanvazia\pilha \fi% \ifnvazia% \repeat% %% rep{\~o}e os valores na pilha \let\pilha=\pilhaaux% \ifvazia% \ifdiferentes% %% %% N{\~a}o {\'e} poss{\'\i}vel efectuar o ajuste dado o utilizador n{\~a}o ter %% especificado uma etiqueta para o objecto em quest{\~a}o. {\'E} dado o %% valor de 10, igual ao valor por omiss{\~a}o. %% \larg=1310720% n{\~a}o faz o ajuste \prof=655360% \alt=655360% \fi% \fi% \divide\larg by 131072 \divide\prof by 65536 \divide\alt by 65536 \ifnum\number\y=\number\yl %% Caso 1 -- seta horizontal %% %% divide-se por 131072 para se obter metade da largura da caixa em %% pontos (pt), isto dado que o texto est{\'a} centrado na caixa. Soma-se %% mais tr{\^e}s, que constitue um ajuste imp{\'\i}rico. \advance\larg by 3 \ifnum\number\larg>\aux #5=\larg \fi \else \ifnum\number\x=\number\xl \ifnum\number\yl>\number\y %% Caso 2.1 -- seta vertical de cima para baixa %% \ifnum\number\alt>\aux #5=\alt \fi \else %% Caso 2.2 -- seta vertical de baixo para cima %% %% divide-se por 65536 para se obter a altura da caixa em pt. O ajuste %% de 5 foi obtido imp{\'\i}ricamente \advance\prof by 5 \ifnum\number\prof>\aux #5=\prof \fi \fi \else %% Caso 3 -- seta obl{\'\i}qua %% Caso 3.1 de 315o a 45o; |x-xl|>|y-yl| e %% Caso 3.3 de 135o a 225o; |x-xl|>|y-yl|; Largura \auxqx=\x \advance\auxqx by -\xl \!absoluto{\auxqx}{\auxqx}% \auxqy=\y \advance\auxqy by -\yl \!absoluto{\auxqy}{\auxqy}% \ifnum\auxqx>\auxqy \ifnum\larg<10 \larg=10 \fi \advance\larg by 3 #5=\larg \else %% Caso 3.2 de 45o a 135o; |x-xl|<|y-yl| e y>0; Largura \ifnum\yl>\y \ifnum\larg<10 \larg=10 \fi \advance\alt by 6 #5=\alt \else %% Caso 3.4 de 225o a 315o; |x-xl|<|y-yl| e y<0; Profundidade \advance\prof by 11 #5=\prof \fi \fi \fi \fi \fi} % o ramo "else" {\'e} omisso %%Comando Interno %% C{\'a}lculo da Raiz Quadrada %% raiz{n}{m} %% entrada %% n - natural %% sa{\'\i}da %% n - natural %% m - maior natural contido na raiz quadrada de n \def\!raiz#1#2{\n=#1% \m=1% \loop \aux=\m% \advance \aux by 1% \multiply \aux by \aux% \ifnum \aux < \n% \advance \m by 1% \paratrue% \else\ifnum \aux=\n% \advance \m by 1% \paratrue% \else\parafalse% \fi \fi \ifpara% \repeat #2=\m} %%Comando Interno %% Calcula os pontos de %% come{\c c}o da "seta" %% fim da "seta" %% coloca{\c c}{\~a}o do s{\'\i}mbolo %% %% ucoord{x1}{x2}{x3}{x4}{x5}{x6}{+|- 1} %% entrada %% x1,x2,x3,x4,x5 %% sa{\'\i}da %% x6 %% %% x2 - x1 %% x6 = x3 +|- ------- x4 %% x5 \def\!ucoord#1#2#3#4#5#6#7{\aux=#2% \advance \aux by -#1% \multiply \aux by #4% \divide \aux by #5% \ifnum #7 = -1 \multiply \aux by -1 \fi% \advance \aux by #3% #6=\aux} %%Comando Interno %% C{\'a}lculo do Quadrado da Dist{\^a}ncia Euclidiana entre dois pontos %% quadrado{n}{m}{l} %% entrada %% n - natural %% m - natural %% sa{\'\i}da %% l = (n-m)*(n-m) \def\!quadrado#1#2#3{\aux=#1% \advance \aux by -#2% \multiply \aux by \aux% #3=\aux} %%Comando Interno %% C{\'a}lculo auxiliar para determinar a dist{\^a}ncia entre o nome do %% morfismo e a seta. %% entrada %% (x,y), (x',y') e o nome do morfismo %% sa{\'\i}da %% dnm - dist{\^a}ncia do nome ao morfismo respectivo devidamente %% compensada pelo tamanho do objecto %% Observa{\c c}{\~o}es %% A compensa{\c c}{\~a}o s{\'o} est{\'a} a ser feita para setas %% horizontais e verticais. As obl{\'\i}quas s{\~a}o tratadas de %% outra forma. %% algoritmo %% caixa0 <- nome do morfismo %% se x-xl = 0 entao {recta vertical} %% aux <- largura da caixa0 %% dnm <- convers{\~a}o-sp-pt(aux)/2+3 %% sen{\~a}o {recta n{\~a}o vertical} %% se y-yl = 0 entao {recta horizontal} %% aux <- altura+profundidade da caixa0 %% dnm <- convers{\~a}o-sp-pt(aux)/2+3 %% sen{\~a}o {recta obl{\'\i}qua} %% dnm <- 3 %% fimse %% fimse %% fimalgoritmo \def\!distnomemor#1#2#3#4#5#6{\setbox0=\hbox{#5}% \aux=#1 \advance \aux by -#3 \ifnum \aux=0 \aux=\wd0 \divide \aux by 131072 \advance \aux by 3 #6=\aux \else \aux=#2 \advance \aux by -#4 \ifnum \aux=0 \aux=\ht0 \advance \aux by \dp0 \divide \aux by 131072 \advance \aux by 3 #6=\aux% \else #6=3 \fi \fi } %% %% O ambiente "begindc...enddc" %% \def\begindc#1{\!ifnextchar[{\!begindc{#1}}{\!begindc{#1}[30]}} \def\!begindc#1[#2]{\beginpicture \let\pilha=\!vazia \setcoordinatesystem units <1pt,1pt> \expansao=#2 \ifcase #1 \distanciaobjmor=10 \tipoarco=0 % seta \tipografo=0 % diagrama comutativo \or \distanciaobjmor=2 \tipoarco=0 % seta \tipografo=1 % grafo orientado \or \distanciaobjmor=1 \tipoarco=2 % linha \tipografo=2 % grafo não orientado \or \distanciaobjmor=8 \tipoarco=0 % seta \tipografo=3 % grafo orientado % \arredondadotrue % objectos com molduras circulares \or \distanciaobjmor=8 \tipoarco=2 % linha \tipografo=4 % grafo não orientado % \arredondadotrue % objectos com molduras circulares \fi} \def\enddc{\endpicture} %% %% Comando para construir a "seta" entre dois objectos %% %% Os pontos definidores da seta e da etiqueta respectiva s{\~a}o: %% %% (xd,yd) %% o %% | %% o------o---------o---------o------o %%(x,y) (xa,ya) (xm,ym) (xb,yb)(xl,yl) %% \def\mor{% \!ifnextchar({\!morxy}{\!morObjA}} \def\!morxy(#1,#2){% \!ifnextchar({\!morxyl{#1}{#2}}{\!morObjB{#1}{#2}}} \def\!morxyl#1#2(#3,#4){% \!ifnextchar[{\!mora{#1}{#2}{#3}{#4}}{\!mora{#1}{#2}{#3}{#4}[\number\distanciaobjmor,\number\distanciaobjmor]}}% \def\!morObjA#1{% \let\pilhaaux=\pilha% \def\objPartida{#1}% \loop% \!topo\pilha% \!retira\pilha% \!compara{\id}{\objPartida}% \ifcompara \nvaziafalse \else \!pilhanvazia\pilha \fi% \ifnvazia% \repeat% \ifvazia% \ifdiferentes% %% %% Mensagem de erro e atribui{\c c}{\~a}o de valores fict{\'\i}cios aos %% argumentos dos comandos que se seguem. %% Error: Incorrect label specification% \xaux=1% \yaux=1% \fi% \fi% \let\pilha=\pilhaaux% \!ifnextchar({\!morxyl{\number\xaux}{\number\yaux}}{\!morObjB{\number\xaux}{\number\yaux}}} \def\!morObjB#1#2#3{% \x=#1 \y=#2 \def\objChegada{#3}% \let\pilhaaux=\pilha% \loop \!topo\pilha % \!retira\pilha% \!compara{\id}{\objChegada}% \ifcompara \nvaziafalse \else \!pilhanvazia\pilha \fi \ifnvazia \repeat \ifvazia \ifdiferentes% %% %% Mensagem de erro e atribui{\c c}{\~a}o de valores fict{\'\i}cios aos %% argumentos dos comandos que se seguem. %% Error: Incorrect label specification \xaux=\x% \advance\xaux by \x% \yaux=\y% \advance\yaux by \y% \fi \fi \let\pilha=\pilhaaux \!ifnextchar[{\!mora{\number\x}{\number\y}{\number\xaux}{\number\yaux}}{\!mora{\number\x}{\number\y}{\number\xaux}{\number\yaux}[\number\distanciaobjmor,\number\distanciaobjmor]}} \def\!mora#1#2#3#4[#5,#6]#7{% \!ifnextchar[{\!morb{#1}{#2}{#3}{#4}{#5}{#6}{#7}}{\!morb{#1}{#2}{#3}{#4}{#5}{#6}{#7}[1,\number\tipoarco] }} \def\!morb#1#2#3#4#5#6#7[#8,#9]{\x=#1% \y=#2% \xl=#3% \yl=#4% \multiply \x by \expansao% \multiply \y by \expansao% \multiply \xl by \expansao% \multiply \yl by \expansao% %% %% calcular a dist{\^a}ncia Euclidiana entre dois pontos %% d = \sqrt((x-xl)^2+(y-yl)^2) %% \!quadrado{\number\x}{\number\xl}{\auxa}% \!quadrado{\number\y}{\number\yl}{\auxb}% \d=\auxa% \advance \d by \auxb% \!raiz{\d}{\d}% %% %% o ponto (xa,ya) est{\'a} {\`a} dist{\^a}ncia #5 (valor por omiss{\~a}o 10) do ponto %% (x,y) %% %% como existem dois pontos em considera{\c c}{\~a}o, o ponto de partida e o %% ponto de chegada, vai sei necess{\'a}rio recuperar de novo os seus %% valores por pesquisa na pilha \auxa=#5 \!compara{\objNulo}{\objPartida}% \ifdiferentes% S{\'o} vai fazer o ajuste quando {\'e} necess{\'a}rio \!ajusta{\x}{\xl}{\y}{\yl}{\auxa}{\objPartida}% \ajustatrue \def\objPartida{}% re-inicializar o valor do Objecto de Partida \fi %% vai guardar o valor de auxa (ap{\'o}s ajuste) para ser usado no caso %% dos morfismos de injec{\c c}{\~a}o. \guardaauxa=\auxa %% \!ucoord{\number\x}{\number\xl}{\number\x}{\auxa}{\number\d}{\xa}{1}% \!ucoord{\number\y}{\number\yl}{\number\y}{\auxa}{\number\d}{\ya}{1}% %% auxa vai ter o valor da dist{\^a}ncia entre os objectos menos a %% dist{\^a}ncia da seta ao objecto (10 por omiss{\~a}o) \auxa=\d% %% %% o ponto (xb,yb) est{\'a} {\`a} dist{\^a}ncia #6 (valor por omiss{\~a}o 10) do ponto %% (xl,yl) %% \auxb=#6 \!compara{\objNulo}{\objChegada}% \ifdiferentes% S{\'o} vai fazer o ajuste quando {\'e} necess{\'a}rio % Vou ajustar \!ajusta{\x}{\xl}{\y}{\yl}{\auxb}{\objChegada}% \def\objChegada{}% re-inicializar o valor do Objecto de Chegada \fi \advance \auxa by -\auxb% \!ucoord{\number\x}{\number\xl}{\number\x}{\number\auxa}{\number\d}{\xb}{1}% \!ucoord{\number\y}{\number\yl}{\number\y}{\number\auxa}{\number\d}{\yb}{1}% \xmed=\xa% \advance \xmed by \xb% \divide \xmed by 2 \ymed=\ya% \advance \ymed by \yb% \divide \ymed by 2 %% %% \!distnomemor{\number\x}{\number\y}{\number\xl}{\number\yl}{#7}{\dnm}% \!ucoord{\number\y}{\number\yl}{\number\xmed}{\number\dnm}{\number\d}{\xc}{-#8}% \!ucoord{\number\x}{\number\xl}{\number\ymed}{\number\dnm}{\number\d}{\yc}{#8}% \ifcase #9 % Seta S{\'o}lida \arrow <4pt> [.2,1.1] from {\xa} {\ya} to {\xb} {\yb} \or % Seta a Tracejado \setdashes \arrow <4pt> [.2,1.1] from {\xa} {\ya} to {\xb} {\yb} \setsolid \or % Linha S{\'o}lida \setlinear \plot {\xa} {\ya} {\xb} {\yb} / \or % Linha Tracejado \setdashes \setlinear \plot {\xa} {\ya} {\xb} {\yb} / \setsolid \or % Linha a Ponteado \setdots \setlinear \plot {\xa} {\ya} {\xb} {\yb} / \setsolid \or % Seta de Injec{\c c}{\~a}o %% C{\'a}lculos auxiliares %% %% 3 valor para o raio do "rabo" da "seta" %% %% repor o valor de auxa \auxa=\guardaauxa %% dar a compensa{\c c}{\~a}o para o "rabo" \advance \auxa by 3% %% %% IMPORTANTE os valores de xa e ya v{\~a}o ser alterados %% \!ucoord{\number\x}{\number\xl}{\number\x}{\number\auxa}{\number\d}{\xa}{1}% \!ucoord{\number\y}{\number\yl}{\number\y}{\number\auxa}{\number\d}{\ya}{1}% \!ucoord{\number\y}{\number\yl}{\number\xa}{3}{\number\d}{\xd}{-1}% \!ucoord{\number\x}{\number\xl}{\number\ya}{3}{\number\d}{\yd}{1}% %% Constru{\c c}{\~a}o da "seta" \arrow <4pt> [.2,1.1] from {\xa} {\ya} to {\xb} {\yb} %% e do seu "rabo" \circulararc -180 degrees from {\xa} {\ya} center at {\xd} {\yd} \or % Seta de Aplica{\c c}{\~a}o ("|-->") \auxa=3% valor para o meio-segmento do "rabo" da "seta" %% c{\'a}lculo dos pontos (xmed,ymed) e (xd,yd) para o segmento de recta que %% define o "rabo" da seta \!ucoord{\number\y}{\number\yl}{\number\xa}{\number\auxa}{\number\d}{\xmed}{-1}% \!ucoord{\number\x}{\number\xl}{\number\ya}{\number\auxa}{\number\d}{\ymed}{1}% \!ucoord{\number\y}{\number\yl}{\number\xa}{\number\auxa}{\number\d}{\xd}{1}% \!ucoord{\number\x}{\number\xl}{\number\ya}{\number\auxa}{\number\d}{\yd}{-1}% %% Constru{\c c}{\~a}o da "seta" \arrow <4pt> [.2,1.1] from {\xa} {\ya} to {\xb} {\yb} %% e do seu "rabo" \setlinear \plot {\xmed} {\ymed} {\xd} {\yd} / \or % Seta de Sobrejec{\c c}{\~a}o ("-->>") \arrow <4pt> [.2,1.1] from {\xa} {\ya} to {\xb} {\yb} %% e da segunda "seta" \setlinear \arrow <6pt> [0,.72] from {\xa} {\ya} to {\xb} {\yb} \fi %% Coloca{\c c}{\~a}o do nome do morfismo. %% Se os morfismos s{\~a}o horizontais ou verticais constro{\'\i} uma caixa %% centrada no ponto pr{\'e}viamente calculado. Se as setas s{\~a}o %% obl{\'\i}quas coloca a caixa de forma a n{\~a}o colidir com o morfismo %% tendo em aten{\c c}{\~a}o o quadrante assim como a posi{\c c}{\~a}o %% relativa do morfismo e do respectivo nome. \auxa=\xl \advance \auxa by -\x% \ifnum \auxa=0 \put {#7} at {\xc} {\yc} \else \auxb=\yl \advance \auxb by -\y% \ifnum \auxb=0 \put {#7} at {\xc} {\yc} \else \ifnum \auxa > 0 \ifnum \auxb > 0 \ifnum #8=1 \put {#7} [rb] at {\xc} {\yc} \else \put {#7} [lt] at {\xc} {\yc} \fi \else \ifnum #8=1 \put {#7} [lb] at {\xc} {\yc} \else \put {#7} [rt] at {\xc} {\yc} \fi \fi \else \ifnum \auxb > 0 \ifnum #8=1 \put {#7} [rt] at {\xc} {\yc} \else \put {#7} [lb] at {\xc} {\yc} \fi \else \ifnum #8=1 \put {#7} [lt] at {\xc} {\yc} \else \put {#7} [rb] at {\xc} {\yc} \fi \fi \fi \fi \fi } %% %% Comando para construir a "seta" curvilinea entre dois objectos %% %% \cmor(){} %% %% Em primeiro lugar {\'e} necess{\'a}rio modificar o comando plot de forma a %% que a sintaxe de utiliza{\c c}{\~a}o do novo comando seja coerente com a %% sintaxe dos restantes comandos %% \def\modifplot(#1{\!modifqcurve #1} \def\!modifqcurve(#1,#2){\x=#1% \y=#2% \multiply \x by \expansao% \multiply \y by \expansao% \!start (\x,\y) \!modifQjoin} \def\!modifQjoin(#1,#2)(#3,#4){\x=#1% \y=#2% \xl=#3% \yl=#4% \multiply \x by \expansao% \multiply \y by \expansao% \multiply \xl by \expansao% \multiply \yl by \expansao% \!qjoin (\x,\y) (\xl,\yl) % \!qjoin is defined in QUADRATIC \!ifnextchar){\!fim}{\!modifQjoin}} \def\!fim){\ignorespaces} %% %% O comando para desenhar a seta vai receber a lista de pontos da qual %% retira o {\'u}ltimo par de pontos, dependente da escolha dada pelo %% utilizador a seta vai ser desenhada para cima, para baixo, para a %% direita ou para a esquerda %% \def\setaxy(#1{\!pontosxy #1} \def\!pontosxy(#1,#2){% \!maispontosxy} \def\!maispontosxy(#1,#2)(#3,#4){% \!ifnextchar){\!fimxy#3,#4}{\!maispontosxy}} \def\!fimxy#1,#2){\x=#1% \y=#2 \multiply \x by \expansao \multiply \y by \expansao \xl=\x% \yl=\y% \aux=1% \multiply \aux by \auxa% \advance\xl by \aux% \aux=1% \multiply \aux by \auxb% \advance\yl by \aux% \arrow <4pt> [.2,1.1] from {\x} {\y} to {\xl} {\yl}} %% %% Temos agora a defini{\c c}{\~a}o do comando "cmor" %% \def\cmor#1 #2(#3,#4)#5{% \!ifnextchar[{\!cmora{#1}{#2}{#3}{#4}{#5}}{\!cmora{#1}{#2}{#3}{#4}{#5}[0] }} \def\!cmora#1#2#3#4#5[#6]{% \ifcase #2% para cima "\pup" (pointing up) \auxa=0% x mant{\^e}m-se \auxb=1% o y "sobe" \or% para baixo "\pdown" (pointing down) \auxa=0% x mant{\^e}m-se \auxb=-1% o y "desce" \or% para a direita "\pright" (pointing right) \auxa=1% o x move-se para a direita \auxb=0% o y mant{\^e}m-se \or% para a esquerda "\pleft" (pointing left) \auxa=-1% o x move-se para a esquerda \auxb=0% o y mant{\^e}m-se \fi % constru{\c c}{\~a}o do arco \ifcase #6 % arco (com seta) s{\'o}lido \modifplot#1% Desenhar o arco % constru{\c c}{\~a}o da seta \setaxy#1 \or % arco (com seta) a tracejado \setdashes \modifplot#1% Desenhar o arco \setaxy#1 \setsolid \or % arco sem seta \modifplot#1% Desenhar o arco \fi % seta de injec{\c c}{\~a}o %% coloca{\c c}{\~a}o da etiqueta do morfismo \x=#3% \y=#4% \multiply \x by \expansao% \multiply \y by \expansao% \put {#5} at {\x} {\y}} %% %% Comando para construir os Objectos %% \obj(x,y){}[] %% \def\obj(#1,#2){% \!ifnextchar[{\!obja{#1}{#2}}{\!obja{#1}{#2}[Nulo]}} \def\!obja#1#2[#3]#4{% \!ifnextchar[{\!objb{#1}{#2}{#3}{#4}}{\!objb{#1}{#2}{#3}{#4}[1]}} \def\!objb#1#2#3#4[#5]{% \x=#1% \y=#2% \def\!pinta{\normalsize$\bullet$}% para definir o tamanho normal das pintas \def\!nulo{Nulo}% \def\!arg{#3}% \!compara{\!arg}{\!nulo}% \ifcompara\def\!arg{#4}\fi% \multiply \x by \expansao% \multiply \y by \expansao% \setbox\caixa=\hbox{#4}% \!coloca{(\!arg)(#1,#2)(\number\ht\caixa,\number\wd\caixa,\number\dp\caixa)}{\pilha}% \auxa=\wd\caixa \divide \auxa by 131072 \advance \auxa by 5 \auxb=\ht\caixa \advance \auxb by \number\dp\caixa \divide \auxb by 131072 \advance \auxb by 5 %(\number\auxa, %\number\auxb) % \aux=\ht\caixa \divide \auxa by 131072 % \advance \auxa by 5 % \auxb=\dp\caixa \divide \auxb by 131072 % \advance \auxb by 8 \ifcase \tipografo % diagramas comutativos \put{#4} at {\x} {\y} \or % grafos dirigidos \ifcase #5 % c=0 \put{#4} at {\x} {\y} \or % n=1 \put{\!pinta} at {\x} {\y} \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % ne=2 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % para fazer o ajuste (imperfeito) \advance \auxb by -2 % ao raio da circunferência de centro (x,y) \advance \x by \number\auxa % width+5 \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % e=3 \put{\!pinta} at {\x} {\y} \advance \x by \number\auxa % width+5 \put{#4} at {\x} {\y} \or % se=4 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % para fazer o ajuste (imperfeito) \advance \auxb by -2 % ao raio da circunferência de centro (x,y) \advance \x by \number\auxa % width+5 \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % s=5 \put{\!pinta} at {\x} {\y} \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % sw=6 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % para fazer o ajuste (imperfeito) \advance \auxb by -2 % ao raio da circunferência de centro (x,y) \advance \x by -\number\auxa % width+5 \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % w=7 \put{\!pinta} at {\x} {\y} \advance \x by -\number\auxa % width+5 \put{#4} at {\x} {\y} \or % nw=8 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % para fazer o ajuste (imperfeito) \advance \auxb by -2 % ao raio da circunferência de centro (x,y) \advance \x by -\number\auxa % width+5 \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \fi \or % grafos não dirigidos \ifcase #5 % c=0 \put{#4} at {\x} {\y} \or % n=1 \put{\!pinta} at {\x} {\y} \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % ne=2 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % para fazer o ajuste (imperfeito) \advance \auxb by -2 % ao raio da circunferência de centro (x,y) \advance \x by \number\auxa % width+5 \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % e=3 \put{\!pinta} at {\x} {\y} \advance \x by \number\auxa % width+5 \put{#4} at {\x} {\y} \or % se=4 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % ver acima \advance \auxb by -2 \advance \x by \number\auxa % width+5 \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % s=5 \put{\!pinta} at {\x} {\y} \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % sw=6 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % ver acima \advance \auxb by -2 \advance \x by -\number\auxa % width+5 \advance \y by -\number\auxb % height+depth+5 \put{#4} at {\x} {\y} \or % w=7 \put{\!pinta} at {\x} {\y} \advance \x by -\number\auxa % width+5 \put{#4} at {\x} {\y} \or % nw=8 \put{\!pinta} at {\x} {\y} \advance \auxa by -2 % ver acima \advance \auxb by -2 \advance \x by -\number\auxa % width+5 \advance \y by \number\auxb % height+depth+5 \put{#4} at {\x} {\y} \fi % \or % grafos dirigidos com molduras circulares nos objectos % \advance \auxa by 4 % \put{\circle{\auxa}} [Bl] at {\x} {\y} % \put{#4} at {\x} {\y} % \or % grafos não dirigidos com molduras circulares nos objectos \else % grafos com molduras circulares nos objectos \ifnum\auxa<\auxb % determina a maior das dimensões \aux=\auxb \else \aux=\auxa \fi % se a largura da caixa é menor do que 1em então o tamanho % tamanho é ajustado para esse valor mínimo \ifdim\wd\caixa<1em \dimen99 = 1em \aux=\dimen99 \divide \aux by 131072 \advance \aux by 5 \fi \advance\aux by -2 %folga entre o objecto e a moldura \multiply\aux by 2 % \ifnum\aux<30 \put{\circle{\aux}} [Bl] at {\x} {\y} \else \multiply\auxa by 2 \multiply\auxb by 2 \put{\oval(\auxa,\auxb)} [Bl] at {\x} {\y} \fi \put{#4} at {\x} {\y} \fi } \catcode`!=12 % ***** THIS MUST NEVER BE OMITTED (Ver PiCTeX)