// CÁLCULOS: // EixosEntrada*mt[3,3]=EixosOrigem. // mt[3,3]=MatrizInversa(EixosEntrada)*EixosOrigem. // como EixosOrigem=I3, mt[3,3]=MatrizInversa(EixosEntrada). // EixosOrigemRotacionados=rotaciona(EixosOrigem). // EixosSaida=EixosOrigemRotacionados*MatrizInversa(mt[3,3]. /// <summary> /// construtor. Constroi os eixos 3D e rotaciona estes eixos com os /// três angulo Euler de entrada. /// </summary> /// <param name="cena">imagem cujos eixos serão aplicados.</param> /// <param name="eixoXAparente">representa o eixo X aparente, retirado da imagem de entrada.</param> /// <param name="anguloX">ângulo X Euler.</param> /// <param name="anguloY">ângulo Y Euler.</param> /// <param name="anguloZ">ângulo Z Euler.</param> /// <param name="dimCells">dimensões da imagem final, já processada.</param> public Bitmap rotacionaComAngulosEuler(Bitmap cena, vetor2 eixoXAparente, double anguloX, double anguloY, double anguloZ, Size dimCells) { // inicializa o eixo X com o parâmetro de entrada [eixoXAparente]. vetor3 eixoX = new vetor3(eixoXAparente.X, eixoXAparente.Y, 0.0); // calcula o eixo Y como rotação de 90.0F graus do eixo X. vetor2 ey = angulos.rotacionaVetor(90.0F, eixoXAparente); // guarda o eixo Y num objeto [vetor3]. vetor3 eixoY = new vetor3(ey.X, ey.Y, 0.0); // inicializa o eixo Z, como produto vetorial do eixo X e eixo Y. vetor3 eixoZ = new vetor3(); // calcula o produto vetorial com o eixo X e o eixo Y. eixoZ.X = eixoX.Y * eixoY.Z - eixoX.Z * eixoY.Y; eixoZ.Y = eixoX.Z * eixoY.X - eixoX.X * eixoY.Z; eixoZ.Z = eixoX.X * eixoY.Y - eixoX.Y * eixoY.X; // faz a rotação nos três eixos. vetor3[] eixosTransformados = rotacaoEuler(anguloX, anguloY, anguloZ, eixoX, eixoY, eixoZ); // calcula o eixo X aparente através da perspectiva isométrica dos três eixos. vetor2 eixoX2D = new vetor2((eixosTransformados[0].X + eixosTransformados[1].X + eixosTransformados[2].X) + (eixosTransformados[0].Z + eixosTransformados[1].Z + eixosTransformados[2].Z) / this.szPerspectiva, (eixosTransformados[0].Y + eixosTransformados[1].Y + eixosTransformados[2].Y) + (eixosTransformados[0].Z + eixosTransformados[1].Z + eixosTransformados[2].Z) / this.szPerspectiva); // o angulo de rotação é zero porque a rotação foi feita no eixo X Aparente [eixoX2D]. return(rotaciona.rotacionaImagemComUmEixo2D(cena, 0.0F, eixoX2D, dimCells)); } // void entradaEixosAparente()
}// drawLegend() /// <summary> /// desenha no dispositivo gráfico do gzimo eixos, um plano quase /// transparente, útil para visualização qual plano é qual. /// </summary> /// <param name="g">dispositivo gráfico para desenho.</param> /// <param name="corQ1">cor do plano. Deve ser bem transparente.</param> /// <param name="numerosIndicesEixoeixos">índices do eixos gráfico, que determina o plano.</param> public void drawATransparentPlane(PointF location, Graphics g, Color corQ1, vetor2 locOffset, params int[] numeroIndicesEixoeixos) { if (numeroIndicesEixoeixos.Length != 0) { List <PointF> pontosPlano = new List <PointF>(); for (int x = 0; x < numeroIndicesEixoeixos.Length; x++) { vetor3 v = this.cordsGzimoEixos[numeroIndicesEixoeixos[x]].Clone(); v.multiplicaPorUmaBase(this.eixoXGzimo, this.eixoYGzimo, this.eixoZGzimo); pontosPlano.Add(vetor2ToPointF(this.perspectiva( v, this.fatorPerspectiva), new PointF((float)locOffset.X, (float)locOffset.Y))); } // for x GraphicsPath path = new GraphicsPath(pontosPlano.ToArray(), new byte[] { (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line }); Region rg = new Region(path); g.FillRegion(new SolidBrush(corQ1), rg); } // if numeroIndicesEixoeixos.Length!=0 } // drawATransparentPlane()
} // void DrawGzimo(). /// <summary> /// desenha uma legenda de orientação dos eixos cartesianos. /// desenha também retângulos coloridos de acordo com cada plano e letras indicando o nome do plano (XZ,YZ, ou XY). /// </summary> /// <param name="g">dispositivo gráfico para desenho da legenda.</param> /// <param name="locLegenda">posição da legenda, em relação ao Control pai.</param> /// <param name="vOrigemLegenda">origem dos eixos legenda.</param> private void drawLegend(Graphics g, vetor2 locLegenda, vetor3 vOrigemLegenda) { Pen pincel = new Pen(Color.Black, 2.5F); vetor2 v2ini = vetor3.transformacaoPerspectivaIsometrica(vOrigemLegenda, fatorPerspectiva); vetor2 v2fini = vetor3.transformacaoPerspectivaIsometrica(eixoXLegenda, fatorPerspectiva); pincel.Color = Color.Green; g.DrawLine(pincel, (float)locLegenda.X + (float)v2ini.X, (float)locLegenda.Y - (float)v2ini.Y, (float)locLegenda.X + (float)v2fini.X, (float)locLegenda.Y - (float)v2fini.Y); g.DrawString("X", this.fonteGzimo, new SolidBrush(Color.Green), new PointF((float)locLegenda.X + (float)v2fini.X + 5, (float)locLegenda.Y - (float)v2fini.Y)); v2fini = vetor3.transformacaoPerspectivaIsometrica(eixoYLegenda, fatorPerspectiva); pincel.Color = Color.Red; g.DrawLine(pincel, (float)locLegenda.X + (float)v2ini.X, (float)locLegenda.Y - (float)v2ini.Y, (float)locLegenda.X + (float)v2fini.X, (float)locLegenda.Y - (float)v2fini.Y); g.DrawString("Y", this.fonteGzimo, new SolidBrush(Color.Red), new PointF((float)locLegenda.X + (float)v2fini.X, (float)locLegenda.Y - (float)v2fini.Y - 5)); v2fini = vetor3.transformacaoPerspectivaIsometrica(eixoZLegenda, fatorPerspectiva); pincel.Color = Color.Blue; g.DrawLine(pincel, (float)locLegenda.X + (float)v2ini.X, (float)locLegenda.Y - (float)v2ini.Y, (float)locLegenda.X + (float)v2fini.X, (float)locLegenda.Y - (float)v2fini.Y); g.DrawString("Z", this.fonteGzimo, new SolidBrush(Color.Blue), new PointF((float)locLegenda.X + (float)v2fini.X + 6, (float)locLegenda.Y - (float)v2fini.Y - 6)); }// drawLegend()
} // drawLinePerspective() /// <summary> /// constrói os eixos que formarão o eixos tridimensional necessário /// para mensurar as rotações que corrigirão a posição do objeto /// 3D alvo. /// </summary> /// <returns></returns> public void constroiGzimo() { // inicializa os eixos da base ortonormal. this.eixoXGzimo = new vetor3(1.0, 0.0, 0.0); this.eixoYGzimo = new vetor3(0.0, 1.0, 0.0); this.eixoZGzimo = new vetor3(0.0, 0.0, 1.0); // cálculos utilizados para as cordenadas do Gzimo eixos. this.eixoXGzimo = this.szLadoGzimo * this.eixoXGzimo; this.eixoYGzimo = this.szLadoGzimo * this.eixoYGzimo; this.eixoZGzimo = this.szLadoGzimo * this.eixoZGzimo; if (this.cordsGzimoEixos == null) { this.cordsGzimoEixos = new List <vetor3>(); } // constrói as cordenadas do Gzimo eixos. this.cordsGzimoEixos.Clear(); this.cordsGzimoEixos.Add(new vetor3(0.0, 0.0, 0.0)); this.cordsGzimoEixos.Add(this.eixoXGzimo); this.cordsGzimoEixos.Add(this.eixoYGzimo); this.cordsGzimoEixos.Add(this.eixoXGzimo + this.eixoYGzimo); this.cordsGzimoEixos.Add(this.eixoZGzimo); this.cordsGzimoEixos.Add(this.eixoXGzimo + this.eixoZGzimo); this.cordsGzimoEixos.Add(this.eixoYGzimo + this.eixoZGzimo); this.cordsGzimoEixos.Add(this.eixoXGzimo + this.eixoYGzimo + this.eixoZGzimo); // eixos de rotação e de base ortonormal. this.eixoXGzimo = new vetor3(1.0, 0.0, 0.0); this.eixoYGzimo = new vetor3(0.0, 1.0, 0.0); this.eixoZGzimo = new vetor3(0.0, 0.0, 1.0); // fixa os eixos de legenda. this.eixoXLegenda = new vetor3(this.eixoXGzimo); this.eixoYLegenda = new vetor3(this.eixoYGzimo); this.eixoZLegenda = new vetor3(this.eixoZGzimo); // redimensiona os eixos de legenda. this.eixoXLegenda = 45.0 * this.eixoXLegenda; this.eixoYLegenda = 45.0 * this.eixoYLegenda; this.eixoZLegenda = 45.0 * this.eixoZLegenda; this.calculaCentroEAtualiza(); this.indicesPontosCordsGzimoEixos.Add(new int[] { 1, 0 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 2, 0 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 1, 3 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 2, 3 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 4, 6 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 1, 5 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 4, 6 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 4, 5 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 5, 7 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 6, 7 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 2, 6 }); this.indicesPontosCordsGzimoEixos.Add(new int[] { 3, 7 }); } // constroieixos
} // rotacionaVetorComAnguloAbsoluto() /// <summary> /// rotaciona o vetor 3D em um determinado ângulo em seu plano XY, e detêrminado ângulo em seu eixo Z. /// Tais ângulos são absolutos. A rotação é feita em coordenadas esféricas. /// ATENÇÃO: O PLANO XY ORIGINAL FOI TROCADO PELO PLANO XZ, POIS A COORDENADA Z É A COORDENADA DE PROFUNDIDADE NOS DESENHOS. /// </summary> /// <param name="anguloXYEmGraus">ângulo absoluto para o plano XY, em Graus.</param> /// <param name="anguloZEmGraus">ângulo absoluto para o eixo Z.</param> /// <param name="v"></param> /// <returns></returns> public static vetor3 rotacionaVetorComAnguloAbsoluto(double anguloXYEmGraus, double anguloZEmGraus, vetor3 v) { vetor3 vf = new vetor3(0.0, 0.0, 0.0); double angleXY = vetor3.toRadianos((double)anguloXYEmGraus); double angleZ = vetor3.toRadianos((double)anguloZEmGraus); double raio = Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z); vf.X = raio * Math.Sin(angleZ) * Math.Cos(angleXY); vf.Z = raio * Math.Sin(angleZ) * Math.Sin(angleXY); vf.Y = raio * Math.Cos(angleZ); return(vf); } // rotacionaVetorComAnguloAbsoluto()
} // btnPlanoXY_Click() /// <summary> /// desenha uma linha reta, componente do gzimo eixos. /// </summary> /// <param name="g">dispositivo gráfico da imagem do gzimo eixos.</param> /// <param name="v1">vetor 3D inicial.</param> /// <param name="v2">vetor 3D final.</param> /// <param name="pincel">Caneta para o desenho da linha, determina a cor da linha.</param> private void drawLinePerspective(Graphics g, vetor3 v1, vetor3 v2, Pen pincel) { vetor2 v2_i = perspectiva(v1, fatorPerspectiva); vetor2 v2_f = perspectiva(v2, fatorPerspectiva); // desenha a linha currente do Gzimo eixos. g.DrawLine(pincel, (float)posicao.X + (float)v2_i.X, (float)posicao.Y + (float)v2_i.Y, (float)posicao.X + (float)v2_f.X, (float)posicao.Y + (float)v2_f.Y); } // drawLinePerspective()
} // iniciaMatriz3D() public Bitmap calcImagemComMatrix3D(vetor3 eixoX, vetor3 eixoY, vetor3 eixoZ, Matriz3DparaImagem2D.transformacaoPerspectiva funcPerspectiva, double fatorPerspectiva, Bitmap cenaRotacionada, Bitmap cena, double profundidadeObjeto, ref string msgErro) { try { Bitmap cenaSaida = null; int x, y, z; v2_0 = null; if (!this.isMatrizJaGerada) { this.iniciaMatriz3D(eixoX, eixoY, eixoZ, cena, profundidadeObjeto, fatorPerspectiva, funcPerspectiva, ref msgErro); } // malha principal, mapeia a matriz rotacionada e seta as cores das coordenadas calculadas. for (z = 0; z < this.matrix.GetLength(2); z++) { for (y = 0; y < this.matrix.GetLength(1); y++) { for (x = 0; x < this.matrix.GetLength(0); x++) { v3 = new vetor3(this.matrix[x, y, z]); v3.multiplicaPorUmaBase(eixoX, eixoY, eixoZ); v2_0 = funcPerspectiva(v3, fatorPerspectiva); if (((int)(v2_0.X - xmin) < cena.Width) && ((int)(v2_0.Y - ymin) < cena.Height) && ((v2_0.X - xmin) >= 0) && ((v2_0.Y - ymin) >= 0)) { // seta a cor na coordenada 2D perspectiva isométrica calculada a partir do ponto 3D matrix[x,y,z]. cenaRotacionada.SetPixel((int)(v2_0.X - this.xmin), (int)(v2_0.Y - this.ymin), this.matrix[x, y, z].cor); } } // for x } } msgErro = ""; cenaSaida = Utils.UtilsImage.recortaImagem(cenaRotacionada); return(cenaSaida); } // try catch (Exception ex) { msgErro = "Erro no processamento da imagem, em sua inicialização. Mensagem de Erro: " + ex.Message; return(null); } // catch } // calcImagemComMatrix3D()
} // constroieixos /// <summary> /// calcula o centro, e retira o centro de todos /// os pontos que formam o GzimoEixos currente. /// </summary> public void calculaCentroEAtualiza() { int x; this.centro = new vetor3(0.0, 0.0, 0.0); for (x = 0; x < this.cordsGzimoEixos.Count; x++) { this.centro.X += this.cordsGzimoEixos[x].X; this.centro.Y += this.cordsGzimoEixos[x].Y; this.centro.Z += this.cordsGzimoEixos[x].Z; } // for x this.centro.X /= (double)this.cordsGzimoEixos.Count; this.centro.Y /= (double)this.cordsGzimoEixos.Count; this.centro.Z /= (double)this.cordsGzimoEixos.Count; for (x = 0; x < this.cordsGzimoEixos.Count; x++) { this.cordsGzimoEixos[x] = this.cordsGzimoEixos[x] - centro; } } // calculaCentro
} // calcImagemComMatrix3D() /// <summary> /// retira de uma matriz de vetores [vetor3] o valor de seu centro de massa. /// Isto permite uam rotação centralizada. /// </summary> private void centralizaMatriz() { media = new vetor3(0.0, 0.0, 0.0); int x, y, z; for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { if (matrix[x, y, z] != null) { // calcula a soma do vetores para depois mensurar a média final. media = media + matrix[x, y, z]; } } } } double n = matrix.GetLength(0) * matrix.GetLength(1) * matrix.GetLength(2); // calcla o produto entre um numero [1/n] e o vetor 3D [media], para calcular a média final. media = (1 / n) * media; for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { if (matrix[x, y, z] != null) { matrix[x, y, z] = matrix[x, y, z] - media; } } } } } // centralizaMatriz();
/// <summary> /// constroi e rotaciona uma lista de vetores 3D a partir de uma imagem e vetor3 eixos determinados pelo aplicativo, e alguns parâmetros. /// </summary> /// <param name="eixoX">eixo X 3D calculado com ferramentas como o gzimo eixos.</param> /// <param name="eixoY">eixo Y 3D calculado com ferramentas como o gzimo eixos.</param> /// <param name="eixoZ">eixo Z 3D calculado com ferramentas como o gzimo eixos.</param> /// <param name="cena">imagem a ser processada.</param> /// <param name="profundidadeObjeto">profundidade imaginada pelo usuário para a imagem 3D a ser rotacionada.</param> /// <param name="anguloXYEmGraus">ângulo de rotação do plano XY.</param> /// <param name="anguloYZEmGraus">ângulo de rotação do plano YZ.</param> /// <param name="anguloXZEmGraus">ângulo de rotação do plano XZ.</param> /// <param name="msgErro">mensagens de erro durante o processamento da imagem para matriz rotacionada.</param> /// <param name="isAnguloAbsoluto">se [true], os ângulos não são incrementos, mas marcam posições absolutas.</param> /// <param name="isUsaEixoZCalculado">se [true], o eixo Z é calculado pelo produto vetorial entre os /// eixos X e Y, e o ângulo entre esses eixos.</param> /// <param name="funcPerspecitva">função de transformação para o efeito de perspectiva (transformação de dados 3D para geometria 2D.</param> /// <param name="fatorPerspectiva">utiliza o fator de perspectiva para incrementar o método de transformação de perspectiva.</param> ///<returns>retorna a imagem rotacionada.</returns> public Bitmap rotacionaMatriz3D( vetor3 eixoX, vetor3 eixoY, vetor3 eixoZ, Bitmap cena, double profundidadeObjeto, double anguloXYEmGraus, double anguloYZEmGraus, double anguloXZEmGraus, ref string msgErro, bool isAnguloAbsoluto, bool isUsaEixoZCalculado, transformacaoPerspectiva funcPerspectiva, double fatorPerspectiva) { vetor3 eixo_i = new vetor3(eixoX); vetor3 eixo_j = new vetor3(eixoY); vetor3 eixo_k = new vetor3(eixoZ); msgErro = ""; if (msgErro != "") { return(null); } if (isUsaEixoZCalculado) { // calcula o eixo Z a partir do produto vetorial e do ângulo entre os eixos X e Y.É um grande avanço! double anguloXY = Math.Acos(1 / ((eixoX.modulo() * eixoY.modulo())) * (eixoX * eixoY)); // faz o produto vetorial e divide pelos modulos dos eixos X e Y. eixoZ = (Math.Sin(anguloXY) / (eixoX.modulo() * eixoY.modulo())) * (eixoX & eixoY); } // if isUsaEixoZCalculado // normaliza os três eixos. eixo_i.normaliza(); eixo_j.normaliza(); eixo_k.normaliza(); // inicia a imagem a ser rotacionada. Bitmap cenaRotacionada = new Bitmap(6 * cena.Width, 6 * cena.Height); if (isAnguloAbsoluto) { // calcula os ângulos iniciais, que são retirados para formar um ângulo absoluto com os ângulos parâmetros. double anguloXYEixoXinicial = angulos.toGraus(eixo_i.encontraAnguloOmega(vetor3.planoRotacao.XY)); double anguloXZEixoXinicial = angulos.toGraus(eixo_i.encontraAnguloOmega(vetor3.planoRotacao.XZ)); double anguloYZEixoXInicial = angulos.toGraus(eixo_i.encontraAnguloOmega(vetor3.planoRotacao.YZ)); double anguloXYEixoYinicial = angulos.toGraus(eixo_j.encontraAnguloOmega(vetor3.planoRotacao.XY)); double anguloXZEixoYinicial = angulos.toGraus(eixo_j.encontraAnguloOmega(vetor3.planoRotacao.XZ)); double anguloYZEixoYInicial = angulos.toGraus(eixo_j.encontraAnguloOmega(vetor3.planoRotacao.YZ)); double anguloXYEixoZinicial = angulos.toGraus(eixo_k.encontraAnguloOmega(vetor3.planoRotacao.XY)); double anguloXZEixoZinicial = angulos.toGraus(eixo_k.encontraAnguloOmega(vetor3.planoRotacao.XZ)); double anguloYZEixoZInicial = angulos.toGraus(eixo_k.encontraAnguloOmega(vetor3.planoRotacao.YZ)); // rotaciona os eixos cartesianos com acrescimos de ângulos, que também são ângulos absolutos. eixo_i.rotacionaVetorAnguloAbsoluto(anguloXYEmGraus + anguloXYEixoXinicial, -anguloYZEmGraus + anguloYZEixoXInicial, -anguloXZEmGraus + anguloXZEixoXinicial); eixo_j.rotacionaVetorAnguloAbsoluto(anguloXYEmGraus + anguloXYEixoYinicial, -anguloYZEmGraus + anguloYZEixoYInicial, -anguloXZEmGraus + anguloXZEixoYinicial); eixo_k.rotacionaVetorAnguloAbsoluto(anguloXYEmGraus + anguloXYEixoZinicial, -anguloYZEmGraus + anguloYZEixoZInicial, -anguloXZEmGraus + anguloXZEixoZinicial); // normaliza os três eixos. eixo_i.normaliza(); eixo_j.normaliza(); eixo_k.normaliza(); if (!this.isMatrizJaGerada) { this.iniciaMatriz3D( eixoX, eixoY, eixoZ, cena, profundidadeObjeto, fatorPerspectiva, funcPerspectiva, ref msgErro); } // if !isMatrizJaGerada } // if isAnguloAbsoluto else { // cálculo ângulo relativo. // rotaciona os eixos-base, portanto uma rotação com acréscimos de ângulos. eixo_i.rotacionaVetor(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixo_j.rotacionaVetor(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixo_k.rotacionaVetor(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); if (!this.isMatrizJaGerada) { this.iniciaMatriz3D( eixo_i, eixo_j, eixo_k, cena, profundidadeObjeto, fatorPerspectiva, funcPerspectiva, ref msgErro); } // if !isMatrizJaGerada if (msgErro != "") { return(null); } } // else return(this.calcImagemComMatrix3D( eixo_i, eixo_j, eixo_k, funcPerspectiva, fatorPerspectiva, cenaRotacionada, cena, profundidadeObjeto, ref msgErro)); } // rotacionaMatriz3D()
} // rotacionaMatriz3D() /// <summary> /// constrói a matriz 3D associado à imagem 2D de entrada. /// </summary> /// <param name="eixoX">eixo X, imaginado com o gzimo eixos.</param> /// <param name="eixoY">eixo Y, imaginado com o gzimo eixos.</param> /// <param name="eixoZ">eixo Z, imaginado com o gzimo eixos.</param> /// <param name="isUsaEixoZCalculado">calcula o eixo Z, se [true];</param> /// <param name="profundidadeObjeto">cumprimento no eixo Z da matriz 3D.</param> /// <param name="fatorPerspectiva">parâmetro de cálculo da perspectiva (isométrica ou geométrica).</param> /// <param name="funcPerspectiva">método a ser utilizada na perspectiva (isométrica ou geométrica).</param> /// <param name="msgErro">string guardando mensagens de erro geradas pelo método.</param> public void iniciaMatriz3D( vetor3 eixoX, vetor3 eixoY, vetor3 eixoZ, Bitmap cena, double profundidadeObjeto, double fatorPerspectiva, Matriz3DparaImagem2D.transformacaoPerspectiva funcPerspectiva, ref string msgErro) { this.isMatrizJaGerada = true; int x, y, z; vetor2 v2_0 = new vetor2(0.0, 0.0); try { Rectangle rectOldBordas = new Rectangle(0, 0, cena.Width, cena.Height); this.matrix = new vetor3[cena.Width, cena.Height, (int)profundidadeObjeto]; xmin = 100000.0; ymin = 100000.0; // calcula o ponto mínimo (xmin,ymin) for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { // inicia o ponto 3D. matrix[x, y, z] = new vetor3(x, y, z); vetor3 v3_0 = new vetor3(matrix[x, y, z]); v3_0.multiplicaPorUmaBase(eixoX, eixoY, eixoZ); v2_0 = funcPerspectiva(v3_0, fatorPerspectiva); if (v2_0.X < xmin) { xmin = v2_0.X; } if (v2_0.Y < ymin) { ymin = v2_0.Y; } } // for z } } // faz a ida, calculando o ponto 3D e através da perspectiva neste ponto, calcula a cor da imagem neste ponto 3D. for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { vetor3 v3_0 = new vetor3(matrix[x, y, z]); v3_0.multiplicaPorUmaBase(eixoX, eixoY, eixoZ); // calcula a perspectiva sobe o ponto 3D. v2_0 = funcPerspectiva(v3_0, fatorPerspectiva); if (((v2_0.X - xmin) < cena.Width) && ((v2_0.Y - ymin) < cena.Height) && ((v2_0.X - xmin) >= 0) && ((v2_0.Y - ymin) >= 0)) { Color cor = cena.GetPixel((int)(v2_0.X - xmin), (int)(v2_0.Y - ymin)); matrix[x, y, z].cor = cor; } // if } // for z } } } // try catch (Exception ex) { msgErro = "Erro ao iniciar o objeto 3D associado à imagem de entrada. Mensagem de erro: " + ex.Message; } // catch } // iniciaMatriz3D()
} // rotacionaVetorComAnguloAbsoluto() /// <summary> /// rotaciona o vetor com acréscimos de ângulos.A rotação é feita em coordenadas /// esféricas modificadas (eixo altura: Y, plano base: plano XZ). /// </summary> /// <param name="anguloXYEmGraus">acréscimo de ângulo no plano XY em Graus.</param> /// <param name="anguloZEmGraus">ácrescimo de ângulo no eixo Z.</param> /// <param name="v">vetor 3D a ser rotacionado.</param> /// <returns>retorna o vetor [v] rotacionado com acréscimos em graus.</returns> public static vetor3 rotacionaVetorComAnguloRelativo(double anguloXYEmGraus, double anguloZEmGraus, vetor3 v) { // calcula os ângulos iniciais, para somar aos ângulos parâmetros para um cálculo final de [rotacionaVetorComAnguloAbsoluto] double anguloZEmGrausInicial = v.encontraAnguloTeta(); double anguloXYEmGRausInicial = v.encontraAnguloOmega(); return(rotacionaVetorComAnguloAbsoluto(anguloXYEmGraus + anguloXYEmGRausInicial, anguloZEmGraus + anguloZEmGrausInicial, v)); } // rotacionaVetorComAnguloRelativo()
} // void entradaEixosAparente() /// <summary> /// rotaciona os eixos 3D, extraidos da imagem, com três angulos de rotação. /// </summary> /// <param name="anguloX">rotaciona o plano YZ, em radianos.</param> /// <param name="anguloY">rotaciona o plano XZ, em radianos.</param> /// <param name="anguloZ">rotaciona o plano XY, em radianos.</param> /// <param name="ex">eixo X a ser rotacionado.</param> /// <param name="ey">eixo Y a ser rotacionado.</param> /// <param name="ez">eixo Z a ser rotacionado.</param> public static vetor3[] rotacaoEuler(double anguloX, double anguloY, double anguloZ, vetor3 ex, vetor3 ey, vetor3 ez) { // guarda numa só matriz os eixos X,Y e Z retirados da Imagem Matriz mtzEixosEntrada = new Matriz(3, 3); mtzEixosEntrada.setElemento(0, 0, ex.X); mtzEixosEntrada.setElemento(1, 0, ex.Y); mtzEixosEntrada.setElemento(2, 0, ex.Z); mtzEixosEntrada.setElemento(0, 1, ey.X); mtzEixosEntrada.setElemento(1, 1, ey.Y); mtzEixosEntrada.setElemento(2, 1, ey.Z); mtzEixosEntrada.setElemento(0, 2, ez.X); mtzEixosEntrada.setElemento(1, 2, ez.Y); mtzEixosEntrada.setElemento(2, 2, ez.Z); // faz o calculo da matriz de transformação. Matriz mtzTransformacao = Matriz.MatrizInversa(mtzEixosEntrada); // inicializa os eixos Origem. vetor3 eixoXOrigem = new vetor3(1.0F, 0.0F, 0.0F); vetor3 eixoYOrigem = new vetor3(0.0F, 1.0F, 0.0F); vetor3 eixoZOrigem = new vetor3(0.0F, 0.0F, 1.0F); double anguloX_Z = Math.Acos(eixoXOrigem.Z / vetor3.raio(eixoXOrigem)); double anguloY_Z = Math.Acos(eixoYOrigem.Z / vetor3.raio(eixoYOrigem)); double anguloZ_Z = Math.Acos(eixoZOrigem.Z / vetor3.raio(eixoZOrigem)); // rotaciona o plano YZ, em cordenadas de ângulo absoluto. eixoYOrigem = angulos.rotacionaVetorComAnguloAbsoluto(anguloX, anguloY_Z, eixoYOrigem); eixoZOrigem = angulos.rotacionaVetorComAnguloAbsoluto(anguloX, anguloZ_Z, eixoZOrigem); // rotaciona o plano XZ. eixoXOrigem = angulos.rotacionaVetorComAnguloAbsoluto(anguloY, anguloX_Z, eixoXOrigem); // a próxima rotação é feita sobre a rotação anterior no [eixoZOrigem]. eixoZOrigem.rotacionaVetor(anguloY, anguloZ_Z); // rotaciona o plano XY. // a próxima rotação é feita sobre a rotação anterior no [eixoXOrigem]. eixoXOrigem.rotacionaVetor(anguloZ, anguloX_Z); // a próxima rotação é feita sobre a rotação anterior no [eixoYOrigem]. eixoYOrigem.rotacionaVetor(anguloZ, anguloY_Z); // guarda nesta matriz os angulos de Origem rotacionados. Matriz mtEixosOrigemRotacionados = new Matriz(3, 3); mtEixosOrigemRotacionados.setElemento(0, 0, eixoXOrigem.X); mtEixosOrigemRotacionados.setElemento(1, 0, eixoXOrigem.Y); mtEixosOrigemRotacionados.setElemento(2, 0, eixoXOrigem.Z); mtEixosOrigemRotacionados.setElemento(0, 1, eixoYOrigem.X); mtEixosOrigemRotacionados.setElemento(1, 1, eixoYOrigem.Y); mtEixosOrigemRotacionados.setElemento(2, 1, eixoYOrigem.Z); mtEixosOrigemRotacionados.setElemento(0, 2, eixoZOrigem.X); mtEixosOrigemRotacionados.setElemento(1, 2, eixoZOrigem.Y); mtEixosOrigemRotacionados.setElemento(2, 2, eixoZOrigem.Z); // calcula a matriz que guarda os eixos de Origem rotacionados. Matriz mtEixosSaida = mtEixosOrigemRotacionados * mtzTransformacao; // atribui para os eixos de entrada os eixos rotacionados com ângulos Euler. ex = new vetor3(mtEixosSaida.getElemento(0, 0), mtEixosSaida.getElemento(1, 0), mtEixosSaida.getElemento(2, 0)); ey = new vetor3(mtEixosSaida.getElemento(0, 1), mtEixosSaida.getElemento(1, 1), mtEixosSaida.getElemento(2, 1)); ez = new vetor3(mtEixosSaida.getElemento(0, 2), mtEixosSaida.getElemento(1, 2), mtEixosSaida.getElemento(2, 2)); return(new vetor3[] { ex, ey, ez }); } // rotacionaComAngulosEuler()
/// <summary> /// constroi uma lista de vetores 3D a partir de uma imagem em perspectiva isométrica, e alguns parâmetros. /// </summary> /// <param name="eixo2DX">vetor 2D representando o eixo X.</param> /// <param name="eixo2DZ">vetor 2D representando o eixo Z (profundidade)</param> /// <param name="cena">imagem a ser processada para gerar a lista de vetores 3D.</param> /// <param name="fatorPerspetivaIsometrica">fator de compactação para gerar as cordenadas 2D isométricas.</param> /// <param name="profundidadeImaginada">altura imaginária da imagem 3D.</param> /// <param name="anguloXYEmGraus">ângulo de rotação do plano XY.</param> /// <param name="anguloYZEmGraus">ângulo de rotação do plano YZ.</param> /// <param name="anguloXZEmGraus">ângulo de rotação do plano XZ.</param> /// <param name="msgErro">mensagens de erro que surgirem no processamento da imagem a ser rotacionada.</param> /// <returns></returns> public Bitmap rotacionaMatriz3D(vetor2 eixo2DX, vetor2 eixo2DY, Bitmap cena, double fatorPerspetivaIsometrica, int profundidadeImaginada, double anguloXYEmGraus, double anguloYZEmGraus, double anguloXZEmGraus, ref string msgErro) { try { this.matrix = new vetor3[cena.Width + 6, cena.Height + 6, profundidadeImaginada + 5]; vetor3 eixoX = new vetor3(0.0, 0.0, 0.0); vetor3 eixoY = new vetor3(0.0, 0.0, 0.0); vetor3 eixoZ = new vetor3(0.0, 0.0, 0.0); int x, y, z; for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { matrix[x, y, z] = new vetor3(x, y, z); vetor2 v2 = matrix[x, y, z].transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); Color cor = cena.GetPixel((int)v2.X, (int)v2.Y); matrix[x, y, z].cor = cor; if (v2.Equals(eixo2DX)) { eixoX = new vetor3(matrix[x, y, z]); } if (v2.Equals(eixo2DY)) { eixoY = new vetor3(matrix[x, y, z]); } } // for z } } eixoZ = eixoX & eixoY; eixoX.normaliza(); eixoY.normaliza(); eixoZ.normaliza(); eixoX.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixoY.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixoZ.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { matrix[x, y, z].multiplicaPorUmaBase(eixoX, eixoY, eixoZ); } } } vetor3 dims3 = new vetor3(cena.Width, cena.Height, profundidadeImaginada); vetor2 dims2 = dims3.transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); Bitmap cenaRotacionada = new Bitmap((int)dims2.X, (int)dims2.Y); for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { vetor2 v2_0 = matrix[x, y, z].transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); cenaRotacionada.SetPixel((int)v2_0.X, (int)v2_0.Y, matrix[x, y, z].cor); } //for z } } return(cenaRotacionada); } // try catch (Exception ex) { msgErro = "Erro no processamento da imagem a ser rotacionada. Motivo: " + ex.Message; return(null); } } // constroiMatriz3D()
} // constroiMatriz3D() /// <summary> /// constroi e rotaciona uma lista de vetores 3D a partir de uma imagem e vetor3 eixos determinados pelo aplicativo, e alguns parâmetros. /// </summary> /// <param name="eixoX">eixo X 3D calculado com ferramentas como o gzimo cubo.</param> /// <param name="eixoY">eixo Y 3D calculado com ferramentas como o gzimo cubo.</param> /// <param name="eixoZ">eixo Z 3D calculado com ferramentas como o gzimo cubo.</param> /// <param name="cena">imagem a ser processada.</param> /// <param name="fatorPerspetivaIsometrica">fator de divisão do eixo projetado para formar o eixo 2D.</param> /// <param name="profundidadeObjeto">profundidade imaginada pelo usuário para a imagem 3D a ser rotacionada.</param> /// <param name="anguloXYEmGraus">ângulo de rotação do plano XY.</param> /// <param name="anguloYZEmGraus">ângulo de rotação do plano YZ.</param> /// <param name="anguloXZEmGraus">ângulo de rotação do plano XZ.</param> /// <param name="msgErro">mensagens de erro durante o processamento da imagem para matriz rotacionada.</param> /// public Bitmap rotacionaMatriz3D(vetor3 eixoX, vetor3 eixoY, vetor3 eixoZ, Bitmap cena, double fatorPerspetivaIsometrica, double profundidadeObjeto, double anguloXYEmGraus, double anguloYZEmGraus, double anguloXZEmGraus, ref string msgErro) { try { int x, y, z; for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { matrix[x, y, z] = new vetor3(x, y, z); vetor2 v2 = matrix[x, y, z].transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); Color cor = cena.GetPixel((int)v2.X, (int)v2.Y); matrix[x, y, z].cor = cor; } // for z } } eixoZ = eixoX & eixoY; eixoX.normaliza(); eixoY.normaliza(); eixoZ.normaliza(); eixoX.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixoY.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); eixoZ.rotacionaVetorComPlanos(anguloXZEmGraus, anguloYZEmGraus, anguloXYEmGraus); for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { matrix[x, y, z].multiplicaPorUmaBase(eixoX, eixoY, eixoZ); } } } vetor3 dims3 = new vetor3(cena.Width, cena.Height, profundidadeObjeto); vetor2 dims2 = dims3.transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); Bitmap cenaRotacionada = new Bitmap((int)dims2.X, (int)dims2.Y); Rectangle rectBordas = new Rectangle(0, 0, cenaRotacionada.Width, cenaRotacionada.Height); for (x = 0; x < matrix.GetLength(0); x++) { for (y = 0; y < matrix.GetLength(1); y++) { for (z = 0; z < matrix.GetLength(2); z++) { vetor2 v2_0 = matrix[x, y, z].transformacaoPerspecctivaIsometrica(fatorPerspetivaIsometrica); if (this.validaVetor2(rectBordas, v2_0)) { cenaRotacionada.SetPixel((int)v2_0.X, (int)v2_0.Y, matrix[x, y, z].cor); } } //for z } } return(cenaRotacionada); } // try catch (Exception ex) { msgErro = "Erro no processamento da imagem a ser rotacionada em 3D. Motivo: " + ex.Message; return(null); } // catch } // constroiMatriz3D()
} // vetor2ToPointF() /// <summary> /// desenha num dispositivo gráfico o Gzimo na forma de um eixos, /// para auxiliar as rotações. /// </summary> /// <param name="g">dispositivo gráfico para desenho.</param> /// <param name="cor">cor do Gzimo.</param> /// <param name="perspectiva">ponteiro para função de cálculo da perspectiva.</param> public override void drawGzimo(Graphics g, Color cor, Matriz3DparaImagem2D.transformacaoPerspectiva perspectiva) { // desenho ds plano XZ no gzimo. if (this.showPlanoXZ) { this.drawATransparentPlane(new Point((int)this.locTransparentPlanesAndLegends.X + 45 * 0 + 0 * 3, (int)this.locTransparentPlanesAndLegends.Y), g, Color.FromArgb(35, Color.Green), new vetor2(this.posicao.X, this.posicao.Y), 6, 2, 3, 7); } // desenho do plano YZ no gzimo. if (this.showPlanoYZ) { this.drawATransparentPlane(new PointF((int)this.locTransparentPlanesAndLegends.X + 45 * 1 + 1 * 3, (int)this.locTransparentPlanesAndLegends.Y), g, Color.FromArgb(35, Color.Blue), new vetor2(this.posicao.X, this.posicao.Y), 6, 2, 0, 4); } // desenho do plano XY no gzimo. if (this.showPlanoXY) { this.drawATransparentPlane(new PointF((int)this.locTransparentPlanesAndLegends.X + 45 * 2 + 2 * 3, (int)this.locTransparentPlanesAndLegends.Y), g, Color.FromArgb(35, Color.Red), new vetor2(this.posicao.X, this.posicao.Y), 2, 3, 1, 0); } // desenha a legenda de orientaçâo do gzimo. this.drawLegend(g, new vetor2(this.locTransparentPlanesAndLegends.X - 45 - 20, this.locTransparentPlanesAndLegends.Y + 45 + 20), new vetor3(0.0, 0.0, 0.0)); Pen pincel = new Pen(cor, (float)this.sizeLine); for (int x = 0; x < this.indicesPontosCordsGzimoEixos.Count; x++) { // destaca o ponto que representa o eixo Z. if ((indicesPontosCordsGzimoEixos[x][0] == 0) || (indicesPontosCordsGzimoEixos[x][1] == 0)) { pincel.Color = Color.Blue; } else { // destaca os pontos que se ligam até a origem dos eixos do Gzimo eixos. if ((this.indicesPontosCordsGzimoEixos[x][0] == 6) || (this.indicesPontosCordsGzimoEixos[x][1] == 6)) { if ((indicesPontosCordsGzimoEixos[x][0] == 4) || (indicesPontosCordsGzimoEixos[x][1] == 4)) { pincel.Color = Color.Red; } if ((indicesPontosCordsGzimoEixos[x][0] == 7) || (indicesPontosCordsGzimoEixos[x][1] == 7)) { pincel.Color = Color.Green; } if ((indicesPontosCordsGzimoEixos[x][0] == 2) || (indicesPontosCordsGzimoEixos[x][1] == 2)) { pincel.Color = Color.Blue; } } // if indicesPontosCordsGzimoEixos[x][0]==0 else { // partes do eixos que não são eixos pincel.Color = cor; } // else } // else if (((this.indicesPontosCordsGzimoEixos[x][0] == 6) || (this.indicesPontosCordsGzimoEixos[x][1] == 6)) && ((this.indicesPontosCordsGzimoEixos[x][0] == 4) || (this.indicesPontosCordsGzimoEixos[x][1] == 4) || (this.indicesPontosCordsGzimoEixos[x][0] == 7) || (this.indicesPontosCordsGzimoEixos[x][1] == 7) || (this.indicesPontosCordsGzimoEixos[x][0] == 2) || (this.indicesPontosCordsGzimoEixos[x][1] == 2))) { // inicializa os vetores para desenho. vetor3 v3_0 = new vetor3(this.cordsGzimoEixos[indicesPontosCordsGzimoEixos[x][0]]); vetor3 v3_1 = new vetor3(this.cordsGzimoEixos[indicesPontosCordsGzimoEixos[x][1]]); // multiplica os vetores para desenho pela base ortonormal currente. v3_0.multiplicaPorUmaBase(this.eixoXGzimo, this.eixoYGzimo, this.eixoZGzimo); v3_1.multiplicaPorUmaBase(this.eixoXGzimo, this.eixoYGzimo, this.eixoZGzimo); // desenha a linha entre os vetores para desenho. this.drawLinePerspective(g, v3_0, v3_1, pincel); } // if } // for x pincel.Dispose(); } // void DrawGzimo().