4

2 つのクラスをリンクしたいのですが、最適な方法がわかりません。私が持っているのは、ドロネー三角形分割を使用してそれらの間の三角形を見つける一連のポイントです(ポイントは複数の三角形に属することができることに注意してください)。次に、これらのポイントの位置が追跡され、ビデオのいくつかのフレーム全体で更新されます。したがって、三角形の位置も何らかの方法で更新する必要があります。その次に、失われたポイントを削除し、それに関連付けられている三角形を自動的に削除できるようにしたいと考えています。これらのクラスを組み合わせる方法についてアドバイスをいただけますか?

class Point  
{ 
  float x,y;
}

class Triangle
{
  Point p1, pt2, pt3;
}
4

5 に答える 5

1

おそらく、次のデータ構造を使用できます。

struct Point
{
    double x, y;
};

struct Triangle
{
    unsigned int ids[3];
    bool isValid;
};

// Store points for each frame
std::vector<std::vector<Point>> points;
// Store triangles
std::vector<Triangle> triangles;

次のように、各フレームのすべての三角形を保持することもできます。

// Store triangles for each frame
std::vector<std::vector<Triangle>> triangles;

そして、これが「実用的な例」です。3 フレーム中に 4 ポイント、2 つの三角形。頂点がすべて正である三角形のみを出力します。あるフレームから別のフレームへ、ポイント クラウドは Y 軸に沿って -1 だけ変換されます。これは明らかに偽のテストですが、開始するのに役立つことを願っています。

#include <vector>
#include <iostream>

struct Point
{
    double x, y;
};

struct Triangle
{
    unsigned int ids[3];
    bool isValid;
};

void TrackFirstFrame(std::vector<Point> &firstFrame)
{
    Point p1, p2, p3, p4;
    p1.x = 1; p1.y = 0;
    p2.x = 2; p2.y = 1;
    p3.x = 1; p3.y = 2;
    p4.x = 0; p4.y = 1;
    firstFrame[0] = p1;
    firstFrame[1] = p2;
    firstFrame[2] = p3;
    firstFrame[3] = p4;
}

void Delaunay(const std::vector<Point> &points, std::vector<Triangle> &triangles)
{
    Triangle t1;
    t1.ids[0] = 0;
    t1.ids[1] = 1;
    t1.ids[2] = 3;
    triangles.push_back(t1);

    Triangle t2;
    t2.ids[0] = 1;
    t2.ids[1] = 2;
    t2.ids[2] = 3;
    triangles.push_back(t2);
}

// Assumption: all previous frame points give a new tracked point for current frame 
void TrackFrame(const std::vector<Point> &previousFramePoints, unsigned int currentFrame, std::vector<Point> &trackedPoints)
{
    for (unsigned int i = 0; i < previousFramePoints.size(); ++i)
    {
        Point previousPoint = previousFramePoints[i];
        Point trackedPoint;
        trackedPoint.x = previousPoint.x;
        trackedPoint.y = previousPoint.y - 1;
        trackedPoints[i] = trackedPoint;
    }
}

// Assumption: all vertices are positive. If not, triangle is invalid
void UpdateTriangles(const std::vector<Point> &points, std::vector<Triangle> &triangles)
{
    std::vector<Triangle>::iterator trianglesIT = triangles.begin();
    for (; trianglesIT != triangles.end(); ++trianglesIT)
    {
        (*trianglesIT).isValid = true; // By default
        for (unsigned int i = 0; i < 3; ++i)
        {
            Point vertex = points[(*trianglesIT).ids[i]];
            if (vertex.x < 0 || vertex.y < 0)
            {
                (*trianglesIT).isValid = false;
                break;
            }
        }
    }
}

void PrintPoints(const std::vector<Point> &points)
{
    std::cout<<"Points"<<std::endl;
    std::vector<Point>::const_iterator pointsIT = points.begin();
    for (; pointsIT != points.end(); ++pointsIT)
    {
        std::cout<<"("<<pointsIT->x<<", "<<pointsIT->y<<")"<<std::endl;
    }
}

void PrintTriangles(const std::vector<Triangle> &triangles)
{
    std::cout<<"Triangles"<<std::endl;
    std::vector<Triangle>::const_iterator trianglesIT = triangles.begin();
    for (; trianglesIT != triangles.end(); ++trianglesIT)
    {
        if (trianglesIT->isValid)
        {
            std::cout<<"["<<trianglesIT->ids[0]<<", "<<trianglesIT->ids[1]<<", "<<trianglesIT->ids[2]<<"])"<<std::endl;
        }
    }
}

int main()
{
    unsigned int nbFrames = 3;
    unsigned int nbPoints = 4;

    // Init 2D points
    std::vector<std::vector<Point>> points;
    points.resize(nbFrames);
    std::vector< std::vector<Point> >::iterator framesIT = points.begin();
    for (; framesIT != points.end(); ++framesIT)
    {
        framesIT->resize(nbPoints);
    }

    TrackFirstFrame(points[0]);
    std::cout<<"Frame 0"<<std::endl;
    PrintPoints(points[0]);

    // Init triangles with Delaunay. 4 points => 2 triangles;
    std::vector<Triangle> triangles;
    Delaunay(points[0], triangles);
    PrintTriangles(triangles);

    for (unsigned int i = 1; i < nbFrames; ++i)
    { 
        std::cout<<"Track frame #"<<i<<std::endl;
        TrackFrame(points[i-1], i, points[i]);
        PrintPoints(points[i]);
        UpdateTriangles(points[i], triangles);
        PrintTriangles(triangles);
    }

    char c;
    std::cin >> c;
}
于 2013-07-08T12:55:49.003 に答える
1

コンピュータ グラフィックスにおけるこのようなコレクションの相互作用は、通常、インデックスを使用して実装されます。

class Point
{ 
  float x,y;
}

class Triangle
{
  unsigned int indices[3]; // indices in std::vector<Points>
}

std::vector<Points> points;
std::vector<Triangle> triangles;

ポインター ソリューションと比較した場合の主な利点は、シェーダー プログラムでこのようなインデックス参照を使用できることです。

編集: 既知のインデックスで頂点を削除するコード例 (テストされていません)。インデックスを消去するときにインデックスを壊さないように、頂点を std::map に保存することに注意してください。

class Mesh
{
public:
    struct Vertex
    {
        float x, y;
    };

    struct Triangle
    {
        bool Contains(unsigned int index) const 
        { 
            return ((indices[0] == index) || (indices[1] == index) || (indices[2] == index));
        }

        unsigned int indices[3];
    };

    // Removes vertex and corresponding triangles
    void RemoveByIndex(unsigned int index)
    {
        for (auto it = triangles.begin(); it != triangles.end(); ++it)
        {
            if (it->Contains(index))
                triangles.erase(it);
        }

        vertices.erase(index);
    }

private:
    std::map<unsigned int, Vertex> vertices;
    std::vector<Triangle> triangles;
};

もちろん、最適化の余地はたくさんあります。最初はコンテナの種類ですが、コレクションのサイズと、データを挿入/消去する頻度によって異なります。

于 2013-07-08T10:09:45.010 に答える
1

@slavaは、ポイントが複数の三角形に属することができると言ったという事実に言及しています。それを念頭に置いて、クラスは次のようになります。

class Point  
{ 
  float x,y;
}

class Triangle
{
  Point * p1;
  Point * pt2;
  Point * pt3;
}

Triangle クラスを定義した方法では、ポイントのコピーを持ち歩いていたでしょう。ポイントが変更された場合、Triangle クラスを個別に更新する必要がありました。

これらはリテラル クラス定義 (すべてが非公開) ではないことに注意してください。おそらく、unique_ptr のような参照カウント ポインターを使用する必要があります。

于 2013-07-08T08:48:18.563 に答える
0

三角形には、ポイントではなくポイントへのポインターが含まれている必要があります。これは、ポイントが三角形の外側に存在するためです。また、関連付けられた三角形のリスト (もちろんポインターのリスト) を各ポイントに保持すると便利な場合もありますが、それは実際には使用法に依存します。

于 2013-07-08T08:39:36.533 に答える
0

三角形を削除する(または追加する)何かが必要だと思います。コードは少し似ています

std::vector<Triangle> update_triangles(const std::vector<Point> & points)
{
//...
}

このコードは、ポイントの新しいコレクションのドローネ三角形を再検索します。これは遅いことが判明する可能性があり、後で高速化するために使用できる巧妙なアルゴリズムがいくつかあるかもしれません.

于 2013-07-08T09:03:56.267 に答える