簡體   English   中英

C ++ Vector的修改次數是計算幾何中的兩倍

[英]C++ Vector is modified twice than it should in Computational Geometry

我試圖解決以下問題。 我有2個球狀多面體,如下圖所示,我試圖找到每個模型的三角形,這些三角形要么在另一個模型中,要么與它相交。 為了實現這一點,我開發了一種幾何算法,我從模型的每個頂點開始射線,並檢查它與另一個模型相交的次數。 如果數字是奇數,則頂點在另一個模型內,如果數字是偶數,則它在外面。

2個型號

當我嘗試區分完全在另一個模型中的三角形和相交的三角形時,會出現問題。 為此,我使用以下邏輯:

  • 對於其他模型內的每個頂點,我檢查同一模型的所有三角形,並嘗試找到此頂點所屬的三角形。

  • 當我找到這樣的三角形時,我在計數器向量中向同一個索引添加1。

  • 最后,我想檢查每個三角形與另一個模型的頂點數。 如果它有3,它是一個內三角形,如果它有1-2則是相交的,如果它有0,則它是外三角形。

問題是,下面的代碼似乎模擬了該過程,得到的計數器值最多為6.這不應該發生,因為每個三角形只能有3個頂點。

計數器向量的結果

圖像的格式為ti的counter [ti]值。

如果有人能為我指出問題,我會非常感激! 此外,歡迎任何改進我的代碼的想法。 先感謝您。

    //create a vector to keep how many vertices are inside the other model for each triangle
    std::vector<int> counter(triangles.size());
    for (unsigned i = 0; i < counter.size(); i++){
        counter[i] = 0;
    }

    //check for every vertex of the model whether it is inside the other model
    for (unsigned vi = 0; vi < vertices.size(); vi++)
    {   

        Vec3d &ver = vertices[vi];
        vec myVec(ver.x, ver.y, ver.z);
        Ray myRay(myVec, myVec.Normalized());
        int interCount = 0;
        for (unsigned ti = 0; ti < triangles2.size(); ti++){
            vec v1, v2, v3;
            v1.x = triangles2[ti].v1().x; v1.y = triangles2[ti].v1().y; v1.z = triangles2[ti].v1().z;
            v2.x = triangles2[ti].v2().x; v2.y = triangles2[ti].v2().y; v2.z = triangles2[ti].v2().z;
            v3.x = triangles2[ti].v3().x; v3.y = triangles2[ti].v3().y; v3.z = triangles2[ti].v3().z;
            math::Triangle tri(v1,v2,v3);
            if (myRay.Intersects(tri)){
                interCount++;
            }
        }
        //if it is inside, find the triangles that have this vertex
        //and add 1 to the respective index in the counter
        if (interCount%2!=0){
            for (int ti = 0; ti < triangles.size(); ti++){
                bool isOnTri = false;
                vvr::Triangle &tri = triangles[ti];
                if ((tri.v1().x == ver.x && tri.v1().y == ver.y && tri.v1().z == ver.z) && isOnTri == false){
                    isOnTri = true;
                }
                else if ((tri.v2().x == ver.x && tri.v2().y == ver.y && tri.v2().z == ver.z) && isOnTri == false){
                    isOnTri = true;
                }
                else if ((tri.v3().x == ver.x && tri.v3().y == ver.y && tri.v3().z == ver.z) && isOnTri == false){
                    isOnTri = true;
                }
                if (isOnTri){
                    counter[ti] ++;
                }
                isOnTri = false;
            }
        }
    }

    //put the triangles in the proper struct
    cout << "\n";
    for (int ti = 0; ti < triangles.size(); ti++){
        cout << counter[ti] << " for " << ti << " ";
        vvr::Triangle &tri = triangles[ti];
        vvr::Triangle3D m_tri(tri.v1().x, tri.v1().y, tri.v1().z,
            tri.v2().x, tri.v2().y, tri.v2().z,
            tri.v3().x, tri.v3().y, tri.v3().z, Colour::blue);
        m_tri.setSolidRender(true);
        if (counter[ti]==5 || counter[ti] == 6){
            m_tris_inner.push_back(m_tri);
        }
        else if (counter[ti]>0 && counter[ti]<5){
            m_tris_intersect.push_back(m_tri);
        }
        else if (counter[ti]==0){
            m_tris_outer.push_back(m_tri);
        }
    }

正如評論中所提到的,您的計數器值大於3的一個可能原因是頂點列表中存在重復的頂點,因此在處理這兩個頂點時計數將會更新。 由於當任何頂點等於其任何頂點與對象相交時,三角形的計數器會增加,如果每個頂點有2個副本,並且具有相同的坐標,則計數器將增加6次。

一種可能的方法是,如果您通過從二十面體開始生成模型並使用中點細分遞歸細分其三角形,而不共享相鄰三角形的中點頂點。

修復此問題的方法是在向列表添加新頂點之前生成頂點時檢查重復項,但是您可以對代碼進行一些優化,這將使其無關緊要。

首先,您可以在開始外部循環之前,通過為triangles2中的所有頂點計算邊界框來優化交叉點測試。 你可以通過迭代所有頂點並找到min和max xy和z來做到這一點。 然后,當你正在測試中的每個頂點vertices ,首先檢查其XYZ值是由邊界框給出的范圍內triangles2 ,如果沒有的話它不可能為它相交,你可以跳過這個循環:

for (unsigned ti = 0; ti < triangles2.size(); ti++)

或者,您可以計算邊界球並進行點到球測試。 也可以根據對象的近球形幾何進行一些特殊情況測試 - 所有部分相交的三角形都位於一個平面上。 然而,邊界框是一種很好的通用優化,適用於大多數任意形狀。 如果為兩個對象計算邊界框,則可以測試它們在函數的最開始是否重疊,如果不是,則立即知道沒有任何頂點相交。

您可以進行的第二個更改是將3個索引存儲到triangles內的vertices數組中,而不是存儲3個頂點副本。 找到每個相交的頂點后,不要遍歷所有三角形,而是將interCount存儲到一個數組中,每個頂點都有一個條目。 完成遍歷所有頂點的迭代后,在單獨的循環中迭代三角形:

for (int ti = 0; ti < triangles.size(); ti++)

並使用與每個三角形一起存儲的3個頂點索引來查找interCount的3個對應值,並計算有多少個奇數值。 如果它為0則則三角形完全在另一個對象之外。 如果它是3那么它完全在里面。 如果它是1或2那么它部分地與表面相交。

這樣做會更快,因為您不必為每個頂點檢查每個三角形的每個頂點,而且您不必擔心計算超過3個頂點,因為您只有3個索引。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM