Làm thế nào tôi nên biểu diễn ma trận trong C ++?


7

Tôi đang tự học toán 3D và trong quá trình xây dựng động cơ thô sơ của riêng mình (thuộc loại). Tôi đã tự hỏi điều gì sẽ là cách tốt nhất để cấu trúc lớp ma trận C ++ của tôi. Có một vài tùy chọn:

  1. Các biến thành viên riêng biệt:

    struct Mat4 {
        float
            m11, m12, m13, m14,
            m21, m22, m23, m24,
            m31, m32, m33, m34,
            m41, m42, m43, m44;
    
        // methods
    
    }
  2. Một mảng đa chiều:

    struct Mat4 {
        float[4][4] m;
    
        // methods
    
    }
  3. Một mảng các vectơ

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

Tôi đoán sẽ có những mặt tích cực và tiêu cực cho mỗi.

Từ 3D Math Primer cho Phát triển đồ họa và trò chơi, Phiên bản 2 tr.155:

ma trận n-by-m.  Nguồn (Wikipedia)

Ma trận sử dụng các chỉ số dựa trên 1, vì vậy hàng và cột đầu tiên được đánh số 1. Ví dụ: a12(đọc amột trong hai, không phải là amười hai 12) là phần tử trong hàng đầu tiên, cột thứ hai. Lưu ý rằng điều này khác với các ngôn ngữ lập trình như C ++ và Java, sử dụng các chỉ số mảng dựa trên 0. Một ma trận không có cột 0 hoặc hàng 0. Sự khác biệt về lập chỉ mục này có thể gây ra một số nhầm lẫn nếu ma trận được lưu trữ bằng cách sử dụng một kiểu dữ liệu mảng thực tế. Vì lý do này, thông thường các lớp lưu trữ ma trận kích thước nhỏ, cố định thuộc loại được sử dụng cho mục đích hình học để cung cấp cho mỗi phần tử biến thành viên có tên riêng của nó, chẳng hạn như float a11, thay vì sử dụng hỗ trợ mảng gốc của ngôn ngữ với thứ gì đó như float elem[3][3].

Vì vậy, đó là một phiếu bầu cho phương pháp một.

Đây thực sự là cách được chấp nhận để làm mọi thứ? Có vẻ khá khó sử dụng nếu lợi ích duy nhất sẽ gắn bó với ký hiệu toán học thông thường.


2
Trước tiên, hãy nghĩ về giao diện của ma trận của bạn (các hàm thành viên công cộng), ví dụ bạn có thể cần một GetRow hoặc GetForwardVector, hãy nghĩ về cách triển khai chúng một cách hiệu quả nhất, sau đó các cơ sở dữ liệu nội bộ rơi vào vị trí một cách tự nhiên
Maik Semder

2
Trong C ++, bạn có thể sử dụng cả mảng và biến thành viên cùng lúc btw, Unions :)
API-Beast

1
Tôi chắc chắn sẽ sử dụng phương pháp một vì rất nhiều đại số tuyến tính, bạn cần một vài ô cụ thể trong ma trận của mình. Các mảng sẽ không bao giờ chỉ chứa những thứ bạn cần, do đó bạn sẽ luôn cần lập chỉ mục nhiều mảng cho các câu hỏi đơn giản, như vectơ chuyển tiếp đã đề cập ở trên. Đây cũng là cách Microsoft thực hiện nó trong khuôn khổ XNA của họ (nhưng tất nhiên một công ty làm điều đó không phải là đối số tốt nhất)
Roy T.

2
Tôi chắc chắn sẽ gắn bó với các mảng không có chỉ mục - Tôi làm rất nhiều tính toán khoa học và việc chuyển đổi các chỉ số khi di chuyển giữa toán học và mã ít hơn so với việc không nhất quán trong mã của bạn. Nếu bạn đi với tùy chọn 2 hoặc 3, sẽ dễ dàng hơn để làm cho thói quen của bạn hoạt động với bất kỳ kích thước ma trận nào, mà cuối cùng bạn có thể cần một cái gì đó (ví dụ, tôi đoán bạn có thể sẽ có thói quen nhân ma trận, mà bạn có thể có thể sử dụng cho ma trận ma trận hoặc vectơ ma trận ).
James

Câu trả lời:


12

Tại sao chọn? Bạn có thể có cả hai. (Không có bất kỳ sự phức tạp nào được thêm vào logic và không có bất kỳ yêu cầu bộ nhớ bổ sung nào nhờ các hiệp hội.)

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
}

1
+1, tôi thường sử dụng float [4] [4] m4x4 và float [16] m16 cũng như các yếu tố riêng lẻ, nhưng đây là thứ mà bạn điều chỉnh theo yêu cầu của chương trình của riêng bạn.
Maximus Minimus

1
Lưu ý rằng bạn thường cần các phần mở rộng dành riêng cho trình biên dịch để làm cho điều cụ thể này hoạt động, vì ISO C ++ không cho phép các cấu trúc ẩn danh (nhưng trong thực tế, nó sẽ hoạt động trên hầu hết các trình biên dịch chính có phần mở rộng).

Tôi đoán bạn sẽ thoát khỏi cách tiếp cận này, nhưng ... Nó có được "cho phép" theo ISO c ++ để đọc nó thành "m" không, khi nó được viết là "m11, m22, ..."?
André

1
@Andre nó không được C ++ cho phép rõ ràng nhưng mọi trình biên dịch chính đều hỗ trợ nó (nó được gọi là kiểu đánh dấu thông qua các hiệp hội ẩn danh) như một phần mở rộng tài liệu. Nó cũng được cho phép rõ ràng trong C.
sam hocevar

1
Bạn có nghĩa là tôi có thể có bánh của tôi và ăn nó?! Cảm ơn một người bạn đời! (nó cũng hoạt động trong D, hehe)
bjz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.