// Last edited on 2000-09-04 21:12:40 by stolfi // Ferramentas para desenhar mapas (na tela ou em papel) import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.Color; import Ponto; import Planta; import Escala; import Escala; import Trecho; import Servico; import Esquina; import Nodo; public class Desenhar { // Desenhos elementares private static Point pTela = new Point(); private static Point qTela = new Point(); private static Ponto pTmp = new Ponto(); private static Ponto qTmp = new Ponto(); private static Rectangle rTela = new Rectangle(); // Os métodos abaixo desenham as figuras indicadas no contexto "g" com // escala "e". Todos os parâmetros são em unidades do mapa, exceto // onde indicado. public static final void bola(Graphics g, Escala e, Ponto p, int raio) // Um círculo preenchido. O "raio" é em pixels. { e.mapaParaTela(p, pTela); g.fillOval(pTela.x - raio, pTela.y - raio, 2*raio+1, 2*raio+1); } public static final void linha(Graphics g, Escala e, Ponto p, Ponto q, double raio) // Um segmento de reta, engordado por "raio" (em pixels!) // em todas as direcoes. { e.mapaParaTela(p, pTela); e.mapaParaTela(q, qTela); if (raio < 1.0) { g.drawLine(pTela.x, pTela.y, qTela.x, qTela.y); } else { // Solução porca e lenta - desenha múltiplas linhas. // Cuidado - altera temporariamente "g" int dMax = (int) raio; int r2 = (int)(raio*raio); for (int dx = -dMax; dx <= dMax; dx++) { for (int dy = -dMax; dy <= dMax; dy++) { if (dx*dx + dy*dy <= r2) { g.translate(+dx, +dy); g.drawLine(pTela.x, pTela.y, qTela.x, qTela.y); g.translate(-dx, -dy); } } } } } public static final void poligono(Graphics g, Escala e, Ponto[] p, boolean enche) // Um polígono preenchido ou não. { int np = p.length; int[] x = new int[np]; int[] y = new int[np]; for (int i = 0; i < np; i++) { e.mapaParaTela(p[i], pTela); x[i] = pTela.x; y[i] = pTela.y; } if (enche) { g.fillPolygon(x, y, np); } else { g.drawPolygon(x, y, np); } } public static final void retangulo(Graphics g, Escala e, Retangulo r, boolean enche) // Um retângulo, preenchido ou não. { e.mapaParaTela(r, rTela); if (enche) { g.fillRect(rTela.x, rTela.y, rTela.width, rTela.height); } else { g.drawRect(rTela.x-1, rTela.y-1, rTela.width+2, rTela.height+2); g.drawRect(rTela.x, rTela.y, rTela.width, rTela.height); } } // MÉTODOS PARA DESENHAR PLANTAS E ACESSÓRIOS // Níveis do desenho: public static int NIVEL_CONTORNO = 1; // Desenhe o contorno dos elementos public static int NIVEL_RECHEIO = 2; // Preencha o interior dos elementos public static int NIVEL_DESTAQUE = 3; // Destaque os elementos public static int NIVEL_ROTULO = 3; // Escreva o rotulo do elemento public static void desenhaPlanta( Graphics g, Escala e, Trecho[] T, Esquina[] Q, Servico[] S ) // Desenha a parte da planta que consiste dos elementos // indicados no contexto "g"e escala "e". { g.setColor(Color.black); for(int i=0; i < T.length; i++) { T[i].desenha(g, e); } for(int i=0; i < Q.length; i++) { Q[i].desenha(g, e); } for(int i=0; i < S.length; i++) { g.setColor(S[i].tipo().cor()); S[i].desenha(g, e); } } public static final void destacaElementos( Graphics g, Escala e, Elemento[] t, double raio ) // Desenha os elementos dados no contexto gráfico "g". // Presentemente, elementos são destacados com bolas no seu centro. // { for (int i= 0; i< t.length; i++) { bola(g, e, t[i].centro(), raio); } } // ROTINAS AUXILIARES private static void desenhaElementos( Graphics g, Escala e, Trecho[] T, Esquina[] Q, Servico[] S ) // Desenha a parte da planta que consiste dos elementos // indicados no contexto "g"e escala "e". { g.setColor(Color.black); for(int i=0; i < T.length; i++) { T[i].desenha(g, e); } for(int i=0; i < Q.length; i++) { Q[i].desenha(g, e); } for(int i=0; i < S.length; i++) { g.setColor(S[i].tipo().cor()); S[i].desenha(g, e); } } public static final void destacaElementos( Graphics g, Escala e, Elemento[] t, double raio ) // Desenha os elementos dados no contexto gráfico "g". // Presentemente, elementos são destacados com bolas no seu centro. // { for (int i= 0; i< t.length; i++) { bola(g, e, t[i].centro(), raio); } } public static final void destacaNodo(Graphics g, Escala e, Nodo u, double raio) // Pinta o nodo "u" no contexto "g" na escala "e". { bola(g, e, u.posicao(), raio); } public static final void destacaCaminho(Graphics g, Escala e, Nodo fin) // Pinta o caminho de custo mínimo até o nodo "fin" no contexto // "g" na escala "e". O caminho é definido implicitamente // pelos campos "prev"(que são preenchidos pelo Otimizador, por // exemplo). { double raioNodo = 3.0; // Em pixels double largTrecho = 1.0; // Em pixels if (fin != null) { destacaNodo(g, e, fin, raioNodo); Nodo v = fin; while (v.prev != null) { linha(g, e, v.posicao(), v.prev.posicao(), largTrecho/2); v = v.prev; } if (v != fin) { destacaNodo(g, e, v, raioNodo); } } } private double larguraDoTrechoEmPixels(Trecho tr, Escala e, int nivel) // Largura nominal de um trecho EM PIXELS, quando desenhado // na escala "e" no nível indicado. Retorna -1 se o // trecho não deve ser desenhado neste nível. { double np = (double)tr.numeroDePistas(); double lp = Trecho.LARGURA_NOMINAL; double larg = np * lp / e.tamanhoDoPixel(); select (nivel) { case NIVEL_CONTORNO: larg += 1; break; case NIVEL_RECHEIO: larg = -1; break; case NIVEL_DESTAQUE: larg -= 1; break; case NIVEL_ROTULO: larg = 10; break; } return larg; } public static final desenhaTrecho(Graphics g, Escala e, Trecho tr, int nivel) // Desenha o trecho "tr" no contexto gráfico "g", em estilo normal. { if (nivel <= NIVEL_DESTAQUE) { double larg = larguraDoTrechoEmPixels(tr, e); if (larg >= 0) { linha(g, e, tr.origPos(), tr.destPos(), larg/2); } } } public static void desenhaEsquina(Graphics g, Escala e, Esquina esq, int nivel) // Desenha as conexoes da uma esquina. { if (nivel <= NIVEL_DESTAQUE) { double larg = larguraDoTrechoEmPixels(tr, e); if (larg >= 0) { Conexao con = esq.conexoes(); for(int i = 0; i < con.length; i++) { linha(g, e, con[i].t1.destPos(), con[i].t2.origPos(), larg/2); } } } } public void desenhaServico(Graphics g, Escala e, Servico sv, int nivel) { if desenhaContornoDoServico(g, e, sv, nivel); desenhaLigacoesDoServico(g, e, sv, nivel); } private void desenhaContornoDoServico(Graphics g, Escala e, Servico sv, int nivel) // Desenha o contorno (preenchido) do serviço { g.setColor(tipo().cor()); Desenhar.poligono(g, e, vertices(), true); } private void desenhaLigacoesDoServico(Graphics g, Escala e, Servico sv, int nivel) // Desenha as ligações entre trechos e serviços. { Ponto[] lig = sv.ligacoes(); int ng = lig.length; double larg = 0.75*Trecho.LARGURA_NOMINAL/e.tamanhoDoPixel(); for (int i = 0; i < ng; i += 2) { linha(g, e, lig[i], lig[i+1, larg/2]); } } public static final void destacaTrechos(Graphics g, Escala e, Trecho[] t, int nivel) // Desenha os trechos dados no contexto gráfico "g". // Sempre que dois trechos consecutivos estiverem conectados, // desenha também a conexão. { Esquina eOrig = null; Ponto mOrig = null; Point tOrig = new Point(); Esquina eDest = null; Ponto mDest = null; Point tDest = new Point(); for (int i= 0; i< t.length; i++) { eOrig = t[i].orig(); mOrig = t[i].origPos(); e.mapaParaTela(mOrig, tOrig); if ((mDest != null) && (eDest == eOrig)) { g.drawLine(tDest.x, tDest.y, tOrig.x, tOrig.y); } eDest = t[i].dest(); mDest = t[i].destPos(); e.mapaParaTela(mDest, tDest); g.drawLine(tOrig.x, tOrig.y, tDest.x, tDest.y); } } }