Como devo representar matrizes em C ++?

7

Estou me ensinando matemática 3D e, no processo, construindo meu próprio mecanismo rudimentar (das sortes). Eu queria saber qual seria a melhor maneira de estruturar minha classe de matriz C ++. Existem algumas opções:

  1. Variáveis ​​de membro separadas:

    struct Mat4 {
        float
            m11, m12, m13, m14,
            m21, m22, m23, m24,
            m31, m32, m33, m34,
            m41, m42, m43, m44;
    
        // methods
    
    }
  2. Uma matriz multidimensional:

    struct Mat4 {
        float[4][4] m;
    
        // methods
    
    }
  3. Uma matriz de vetores

    struct Mat4 {
        Vec4[4] m;
    
        // methods
    
    }

Eu estou supondo que haveria pontos positivos e negativos para cada um.

Do 3D Math Primer para desenvolvimento de gráficos e jogos, 2ª edição, p.155:

matriz n-por-m.  Fonte (Wikipedia)

As matrizes usam índices com base em 1; portanto, a primeira linha e a coluna são numeradas 1. Por exemplo, a12(leia “ aum dois”, não “ adoze”) é o elemento na primeira linha, segunda coluna. Observe que isso é diferente das linguagens de programação como C ++ e Java, que usam índices de matriz baseados em 0. Uma matriz não possui uma coluna 0 ou linha 0. Essa diferença na indexação pode causar alguma confusão se as matrizes forem armazenadas usando um tipo de dados de matriz real. Por esse motivo, é comum que as classes que armazenam matrizes pequenas e de tamanho fixo do tipo usado para fins geométricos forneçam a cada elemento sua própria variável de membro nomeada, como float a11, em vez de usar o suporte de matriz nativa da linguagem com algo como float elem[3][3].

Então esse é um voto para o método um.

Essa é realmente a maneira aceita de fazer as coisas? Parece bastante complicado se o único benefício seria manter a notação matemática convencional.

bjz
fonte
2
Pense sobre a interface do seu matriz de primeira (as funções de membro público), por exemplo, você pode precisar de um getRow ou GetForwardVector, pense sobre como implementá-los de forma mais eficiente, em seguida, as estruturas de dados internos apenas cair no lugar naturalmente
Maik Semder
2
Em C ++ você pode usar ambas as matrizes e variáveis de membro, ao mesmo tempo btw, Sindicatos :)
API-Fera
11
Definitivamente, eu iria para o método um, pois para muita álgebra linear você precisa de algumas células específicas em sua matriz. As matrizes nunca conterão apenas as que você precisa, portanto sempre será necessário indexar várias matrizes para perguntas simples, como o vetor avançado acima mencionado. Esta é também a forma como a Microsoft faz isso em seu quadro XNA (mas é claro que uma empresa a fazê-lo não é o melhor argumento)
Roy T.
2
Eu definitivamente ficaria com matrizes com índice zero - eu faço muita computação científica e é muito menos confuso converter os índices ao mover entre matemática e código do que ser inconsistente no seu código. Se você optar pela opção 2 ou 3, será mais fácil fazer com que suas rotinas funcionem com qualquer tamanho de matriz, o que você pode precisar de algo (por exemplo, acho que você provavelmente terá uma rotina de multiplicação de matrizes, que você pode ser usado para matriz de matriz ou vetor de matriz ).
James

Respostas:

12

Por que escolher? Você pode ter os dois. (Sem nenhuma complexidade adicional à lógica e sem nenhum requisito adicional de memória graças às uniões.)

struct Mat4
{
    union
    {
        struct
        {
          float m11, m12, m13, m14,
                m21, m22, m23, m24,
                m31, m32, m33, m34,
                m41, m42, m43, m44;
        };
        float[4][4] m;
    };
// methods
}
API-Beast
fonte
11
+1, normalmente uso float [4] [4] m4x4 e float [16] m16, bem como os elementos individuais, mas isso é algo que você adapta aos requisitos do seu próprio programa.
Maximus Minimus
11
Observe que muitas vezes você precisa de extensões específicas do compilador para fazer esse trabalho específico, pois o ISO C ++ não permite estruturas anônimas (mas na prática ele funcionará na maioria dos principais compiladores com extensões).
Eu acho que você se safaria dessa abordagem, mas ... É "permitido", de acordo com a ISO c ++, lê-la como "m", quando foi escrita como "m11, m22, ..."?
André
11
@ Além disso, não é explicitamente permitido pelo C ++, mas todos os principais compiladores o suportam (é chamado de punção de tipo através de uniões anônimas) como uma extensão documentada. É também permitido explicitamente em C.
sam Hocevar
11
Você quer dizer que eu posso comer meu bolo e comê-lo também ?! Obrigado um companheiro de bando! (D em que funciona bem, rs)
BJZ