package puzzle.puzzleClasses; import java.awt.Color; import java.awt.Frame; import java.awt.Image; import java.awt.image.BufferedImage; import java.util.Random; import jv.anim.PsAnimation; import jv.anim.PsTimeEvent; import jv.anim.PsTimeListenerIf; import jv.geom.PgElementSet; import jv.geom.PgTexture; import jv.number.PuDouble; import jv.object.PsConfig; import jv.object.PsDebug; import jv.objectGui.PsImage; import jv.project.PjProject; import jv.project.PvCameraEvent; import jv.project.PvCameraIf; import jv.project.PvCameraListenerIf; import jv.project.PvDisplayIf; import jv.project.PvPickEvent; import jv.project.PvPickListenerIf; import jv.project.PvViewerIf; import jv.vecmath.PdVector; import jv.vecmath.PuVectorGeom; /** * * @author agoncalves * * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */ public class Puzzle3D extends PjProject implements PvPickListenerIf ,PvCameraListenerIf,PsTimeListenerIf, Runnable{ private static final long serialVersionUID = 1L; protected double Pi = Math.PI; /**Margem de erro.*/ protected double eps = 0.0001; /**Cor do applet.*/ protected Color corFundo; /*As janelas de visualização*/ /**A janela que aparece visível, da vista esquerda.*/ protected PvDisplayIf m_dispDef; /**A janela que aparece visível, da vista direita.*/ protected PvDisplayIf m_dispDefVD; /*............................................................*/ /*Para o plano:*/ /**As faces do objecto "plano".*/ protected PgElementSet[] facesPlano; protected Color corPlano; /**Se mostra o plano.*/ protected boolean mostraPlano; /**Se mostra as faces do plano.*/ protected boolean mostraFacesPlano; /**Se mostra as arestas do plano.*/ protected boolean mostraArestasPlano; /*......................................................*/ /*Para o cilindro:*/ /**As faces do cilindro.*/ protected PgElementSet[] facesCili; /**Ponto central na base do cilindro.*/ protected PdVector ptoCilindroB; /**Ponto central no topo do cilindro.*/ protected PdVector ptoCilindroT; /**Raio do cilindro.*/ protected double raioCilindro; /**Nº de linhas na horizontal do cilindro.*/ protected int numXLinesCili; /**Cor das faces do cilindro.*/ protected Color corCilindro; /**Se mostra o cilindro.*/ protected boolean mostraCili; /**Nº de linhas na horizontal do cilindro.*/ protected int numYLinesCili; /**Se mostra as faces do cilindro.*/ protected boolean mostraFacesCili; /**Se mostra as arestas.*/ protected boolean mostraArestasCili; /**Cor das arestas das partes do cilindro que não estão seleccionadas.*/ static Color corArestas; /**Grossura das arestas que não estão seleccionadas.*/ static double sizeArestas; /**Cor das arestas das partes do cilindro que estão seleccionadas.*/ protected Color corBordo; /**Grossura das arestas que estão seleccionadas.*/ protected double sizeBordo; /**A cor da selecção.*/ protected Color corSele; /**Grossura da selecção.*/ protected double sizeSele; /**Grossura da linha que aparece às vezes nas faces da garrafa de Klein e da tira de Moebius*/ static double sizeLinhaDiv; /*.................................................*/ /*Para o toro:*/ /**As faces do toro, ie, as peças do puzzle.*/ protected PgElementSet[] facesToro; /**Ponto central do toro.*/ protected double distCentroToro; /**Raio do toro.*/ protected double raioMenorToro; /**Nº de linhas na horizontal do toro.*/ protected int numXLinesToro; /**Nº de linhas na horizontal do toro.*/ protected int numYLinesToro; /**Cor das faces do toro.*/ protected Color corToro; /**Se mostra o toro.*/ protected boolean mostraToro; /**Se mostra as faces do toro.*/ protected boolean mostraFacesToro; /**Se mostra as arestas do toro.*/ protected boolean mostraArestasToro; /*.................................................*/ /*Para o tira de Moebius:*/ /**As faces da tira de Moebius.*/ protected PgElementSet[] facesTiraM; /**Comprimento da tira de Moebius.*/ protected double comprimentoTiraM; /**Largura da tira de Moebius.*/ protected double larguraTiraM; /**Nº de linhas na horizontal da tira de Moebius.*/ protected int numXLinesTiraM; /**Nº de linhas na horizontal da tira de Moebius.*/ protected int numYLinesTiraM; /**Cor das faces da tira de Moebius.*/ protected Color corTiraM; /**Se mostra a tira de Moebius.*/ protected boolean mostraTiraM; /**Se mostra as faces da tira de Moebius.*/ protected boolean mostraFacesTiraM; /**Se mostra as arestas da tira de Moebius.*/ protected boolean mostraArestasTiraM; /*.................................................*/ /*Para a garrafa de Klein:*/ /**As faces da garrafa de Klein.*/ protected PgElementSet[] facesGarrafaK; /**Linha divisória na face da garrafa de klein ou na tira de MOebius que dá para virar para os dois lados.*/ protected PgElementSet linha; /**Raio maior da garrafa de Klein.*/ protected double rMaiorGarrafaK; /**Raio menor da garrafa de Klein.*/ protected double rMenorGarrafaK; /**Nº de linhas na horizontal da garrafa de Klein.*/ protected int numXLinesGarrafaK; /**Nº de linhas na horizontal da garrafa de Klein.*/ protected int numYLinesGarrafaK; /**Cor das faces da garrafa de Klein.*/ protected Color corGarrafaK; /**Se mostra a garrafa de Klein.*/ protected boolean mostraGarrafaK; /**Se mostra as faces da garrafa de Klein.*/ protected boolean mostraFacesGarrafaK; /**Se mostra as arestas da garrafa de Klein.*/ protected boolean mostraArestasGarrafaK; /*.................................................*/ /*Para o nº de linhas e de colunas:*/ /**Valor do nº de colunas, modifica em comprimento (XLines).*/ protected static int valorM; /**Ao mudar o valorM, conserva o valor anterior dele até que todas as peças tenham tenham sido calculadas com o novo valor.*/ protected int[] valorMAntigo; /**Valor do nº de linhas, modifica em largura (YLines).*/ protected static int valorN; /**Ao mudar o valorN, conserva o valor anterior dele até que todas as peças tenham tenham sido calculadas com o novo valor.*/ protected int[] valorNAntigo; /*.......................................*/ /**Pares ordenados que indicam as cores as posições das cores.*/ static int[][] distCores; /**Estado das placas quanto às reflexões*/ protected boolean[][] Flip ; /**Indica as posições das peças do puzzle após terem sido baralhadas.*/ protected Random aleatorio; /**Se o baralhar é par ou ímpar.*/ protected int paridade ; /**Cria.*/ protected boolean cria; /**Prim*/ protected boolean prim ; /**Posições das placas contíguas à peça que tem o buraco.*/ protected int[][] indPlacasContiguas; /**Valor da transparência pra cada placa.*/ protected double[][] transp; /**Transparência mínima, para as placas que naquele momento do jogo não podem ser movidas.*/ static double transpMin = 0.; /**Transparência máxima, para as placas que naquele momento do jogo podem ser movidas.*/ protected double transpMax = 0.2; /**Nome da figura que está seleccionada.*/ static String nome; /*Para o objecto que é sensível à acção do rato:*/ /**Objecto sensível ao pick do rato.*/ protected PgElementSet objPick; /**Valor que multiplico ao valorM para ter mais definição no objPick.*/ protected int multM; /**Valor que multiplico ao valorM para ter mais definição no objPick.*/ protected int multN; /*......................................................*/ /*Para as imagens:*/ /**array das imagens que compõem as placas*/ protected BufferedImage[] BImg ; /**As imagens que vão estar em cada peça.*/ protected PsImage [] m_image; /*...................................*/ /*Para a animação que obtém a melhor posição:*/ /**A animação da câmera, que consiste na mudança direcção e do "interest" da camera.*/ protected PsAnimation anim; /**O valor de deformação: valor que orienta a animação.*/ protected PuDouble m_a; /**Número de passos da animação, isto é nº de posições que a câmera passa desde a sua posição inicial até à posição final.*/ protected final double nPassos = 30; /*Para a das deformações:*/ /**O valor de deformação das transformações: valor que orienta a animação.*/ static PuDouble m_aDef; /**Número de passos da animação das transformações.*/ protected final double nPassosDef = 25; /**Valor acrescentado ao tempo da animação para que tenha a distância final e o Interest final.*/ protected int dif = 10; /*.....................................................*/ /*Para que haja a rotação da câmera de forma a que a sua direcção permita ver a peça do puzzle vazia:*/ /**Ponto de vista da câmera.*/ protected PdVector intAntigo; /**Novo ponto de vista da câmera.*/ protected PdVector intActual; /**Direcção da câmera.*/ protected PdVector dirAntiga; /**A nova direcção da câmera.*/ protected PdVector dirActual; /**Interest ideal para a camêra.*/ protected PdVector intActualPos = new PdVector(0,0,0); /**Interest da camêra antes de ser actualizado.*/ static PdVector intAntes; /**Interest da camêra antes de ser actualizado.*/ static PdVector intAntesPos; protected double distActualPos ; protected double distAntes ; protected double distActual; /*..................................................*/ /**Informa quando já há informação sobre as imagens, após o Puzzle ter sido corrido.*/ protected boolean inicio = false; /**O conjunto das partes da superfície em qualquer um dos seus estados.*/ protected static PgElementSet[] ciliDefs; /**O vector normal a cada uma das partes da superfície.*/ protected static PdVector[] normalCiliDefs; /**O ângulo entre o vector dado pela posição da camêra e o vector normal à parte da superfície correspondente à posição vazia.*/ protected double ang; /**O "cross" entre o vector dado pela posição da camêra e o vector normal à parte da superfície correspondente à posição vazia.*/ protected PdVector c; /**Nº de linhas para calcular a superfície.*/ protected final int numXLinesDef = 12; /**Nº de linhas para calcular a superfície.*/ protected final int numYLinesDef = 12; static boolean update = false; public Puzzle3D(){ super("O puzzle."); anim = new PsAnimation();// Criaçao da animação (which sends timer events) anim.setName("Inversão"); anim.addTimeListener(this); m_a = new PuDouble("Deformação:", this); m_aDef = new PuDouble("Deformação das transformações.", this); linha = new PgElementSet(3); objPick = new PgElementSet(3); if (getClass() == Puzzle3D.class){ init(); } } public void init() { //System.out.println("Inicio!!!!"); update = false; anim.setTimeInterval(0, nPassos+dif,1,1); anim.setRepeat(0);//A animação faz LOOP (LOOP = 1), outros: para ONE_WAY = 0 ou para BACK_FORTH = 2. anim.setSleepInterval(150);anim.update(anim); m_a.setDefBounds(0.,nPassos, 1, 1); m_a.setDefValue(0.); m_a.init(); m_aDef.setDefBounds(0.,nPassosDef, 1, 1); m_aDef.setDefValue(1.); m_aDef.init(); corFundo = Metodos.corRGB(196,177,128); corArestas = new Color(1.f,1.f,1.f); sizeArestas = 1.; corBordo = corArestas; sizeBordo = sizeArestas; corSele = Color.YELLOW; sizeSele = 3.; sizeLinhaDiv = 1.5; multM = 2; multN = 2; valorM = 4; valorN = 4; valorMAntigo = new int[5]; valorNAntigo = new int[5]; for(int i=0;i<5;i++){valorMAntigo[i] = valorM; valorNAntigo[i] = valorN;} aleatorio = new Random(); paridade = valorM*valorN*4; cria = true; prim = false; int cont = 1; distCores = new int[valorM*valorN][2]; distCores[0][0] = valorM-1; distCores[0][1] = valorN-1; for(int i=0; i0&&distCores[0][0]0&&distCores[0][1]0&&distCores[0][0]0&&distCores[0][1]0&&distCores[0][1]0&&distCores[0][1]0&&cores[0][0]0&&cores[0][1]0&&distCores[0][0]0&&distCores[0][1]0&&distCores[0][1]0&&distCores[0][0]0&&distCores[0][1]0.5){ n = "cilindro"; } } indPlacasContiguas = Contig(n,distCores[0]); for(int i=0;i0.5){ n = "cilindro"; } } indPlacasContiguas = Contig(n,distCores[0]); for(int i=0;i0.5){ n = "cilindro"; }else if(m_aDef.getValue()==1){ n = "toro"; } } if(AppletPuzzle.Klein[AppletPuzzle.menuS].isSelected()&&m_aDef.getValue()>0.5){ n = "klein"; } } } indPlacasContiguas = Contig(n,distCores[0]); int ind = 0; for(int i=0;i0.5)){mudancaCor();tudoRun();} if(AppletPuzzle.Rect[AppletPuzzle.menuS].isSelected()){ int ind = 0; for(int i=0;i6&&valorM>6){ numXLinesTiraM = 10; numYLinesTiraM = 5; }else { numXLinesTiraM = 10; numYLinesTiraM = 5; } mostraFacesTiraM = true; mostraArestasTiraM = true; facesTiraM = new PgElementSet[valorM*valorN]; int ind = 0; double[] ang = {0,0}; double larg = 0; double pAng = 2*Pi/valorM;//Passos do ângulo double pLarg = larguraTiraM/(double)valorN;//Passos do comprimento (que tem como mínimo 0 e máximo 1) for(int i=0;i=1.1*Pi){ if(AppletPuzzle.luzes[AppletPuzzle.menuS].isSelected()){ bordo(valorM-1-i,j); Metodos.computePartesGarrafaKlein(facesGarrafaK[ind],rMaiorGarrafaK,rMenorGarrafaK,numXLinesGarrafaK,numYLinesGarrafaK,angX,angY,corGarrafaK,corBordo,sizeBordo,transpMax,mostraFacesGarrafaK,mostraArestasGarrafaK,mostraGarrafaK); }else { Metodos.computePartesGarrafaKlein(facesGarrafaK[ind],rMaiorGarrafaK,rMenorGarrafaK,numXLinesGarrafaK,numYLinesGarrafaK,angX,angY,corGarrafaK,corArestas,sizeArestas,transpMax,mostraFacesGarrafaK,mostraArestasGarrafaK,mostraGarrafaK); } }else { if(AppletPuzzle.luzes[AppletPuzzle.menuS].isSelected()){ bordo(valorM-1-i,j); Metodos.computePartesGarrafaKlein(facesGarrafaK[ind],rMaiorGarrafaK,rMenorGarrafaK,numXLinesGarrafaK,numYLinesGarrafaK,angX,angY,corGarrafaK,corBordo,sizeBordo,transpMin,mostraFacesGarrafaK,mostraArestasGarrafaK,mostraGarrafaK); }else { Metodos.computePartesGarrafaKlein(facesGarrafaK[ind],rMaiorGarrafaK,rMenorGarrafaK,numXLinesGarrafaK,numYLinesGarrafaK,angX,angY,corGarrafaK,corArestas,sizeArestas,transpMin,mostraFacesGarrafaK,mostraArestasGarrafaK,mostraGarrafaK); facesGarrafaK[ind].showTransparency(false);facesGarrafaK[ind].update(facesGarrafaK[ind]); } } } } } } /**Calcular o vector normal a cada face.*/ public PdVector vNormal(PdVector[] vert,PdVector ptoInterior){ PdVector normal; PdVector u = Metodos.uv(vert[0],vert[1]); PdVector v = Metodos.uv(vert[1],vert[2]); PdVector vectInt = Metodos.uv(ptoInterior,vert[0]); PdVector c = Metodos.cross(u,v); if(Metodos.produtoEscalar(vectInt,c)>=0){ normal = Metodos.uni(c); }else { normal = Metodos.uni(Metodos.cross(Metodos.uv(vert[2],vert[1]),Metodos.uv(vert[1],vert[0]))); } return normal; } /*Métodos de apoio à mudança das peças:*/ /**Estado inicial das placas quanto às reflexões*/ public boolean[][] FlipI(int M,int N){//faz corresponder a cada placa o par (false, false) boolean[][] Result = new boolean[M*N][2]; for(int i=0; i0.5){ R[1][0]=R[2][0]; } }else{R[1][0]=mn[0]+1;} if((nome=="moebius"||nome=="klein")&&(mn[0]==Dados.M-1)){ R[1][1]=(Dados.N-mn[1]-1); if((mn[0]==Dados.M-1)&&nome.equals("klein")&&m_aDef.getValue()<1&&m_aDef.getValue()>0.5){ R[1][1]=R[2][1]; } }else{ R[1][1]=mn[1]; } if((nome=="moebius")&&(mn[1]==Dados.N-1)){ R[3][0]=Dados.M-mn[0]-1; }else{R[3][0]=mn[0];} if(nome=="toro"||nome=="klein"){ R[3][1]=(mn[1]+1+Dados.N)%Dados.N; }else{R[3][1]=mn[1]+1;} if((mn[0]==0)&&nome.equals("klein")&&m_aDef.getValue()<1&&m_aDef.getValue()>0.5){ R[0][0]=R[2][0];R[0][1]=R[2][1]; } return R; } /**retorna o numero da placa correspondente posição pos na lista Placas*/ public static int invPlacas(int[] pos, int[][] Placas){ int Result=-1; for(int i=0; (i0.5){ quoc = in/(valorN*valorM*multM*multN); if(in<((double)valorN*valorM*multM*multN)/2-1){//dá 0 if(in<((double) valorN*multN*((double)multM/2))){ quoc = 0; }else { quoc = 1; } }else { if(in<((double) (valorM*multM*valorN*multN-valorN*multN*((double)multM/2)))){ quoc = 0; }else { quoc = 1; } } int[] aa = Metodos.indParOrd(in,valorM*multM,valorN*multN); aa[1] = valorN*multN-1-aa[1]; int ini = Metodos.parOrdInd(aa,valorM*multM,valorN*multN); indice = Metodos.nPlaca(ini,multM,valorM,multN,valorN); }else { indice = Metodos.parOrdInd(Metodos.invConj(Metodos.indParOrd(Metodos.nPlaca(in,multN,valorN,multM,valorM),valorN,valorM)),valorM,valorN); } }else if(nome.equals("moebius")){ quoc = in/(valorN*valorM*multM*multN); if(in<((double)valorN*valorM*multM*multN)/2-1){//dá 0 if(in<((double) valorN*multN*((double)multM/2))){ quoc = 0; }else { quoc = 1; } }else { if(in<((double) (valorM*multM*valorN*multN-valorN*multN*((double)multM/2)))){ quoc = 0; }else { quoc = 1; } } indice = Metodos.nPlaca(in,multM,valorM,multN,valorN); }else if(nome.equals("toro")){ if(m_aDef.getValue()<=0.5){ indice = Metodos.nPlaca(in,multM,valorM,multN,valorN); } else {indice = Metodos.parOrdInd(Metodos.invConj(Metodos.indParOrd(Metodos.nPlaca(in,multN,valorN,multM,valorM),valorN,valorM)),valorM,valorN); } }else if(nome.equals("cilindro")){ indice = Metodos.nPlaca(in,multM,valorM,1,valorN); double q = Math.floor(indice/valorN); double r = indice%valorN; indice = (int)(valorN*q+((valorN-1)-r)); }else { indice = Metodos.nPlaca(in,multM,valorM,1,valorN); } if(pos.getGeometry().equals(objPick)){ for(int i=0;i<4;i++){ if(indice==Metodos.parOrdInd(indPlacasContiguas[i],valorM,valorN)){ if(mostraPlano){ Permuta(distCores,invPlacas(Contig(nome,distCores[0])[i],distCores),0); mudancaCor(); tudoPick(); for(int j=0;j