点和三角形之间的链接

时间:2013-07-08 08:28:30

标签: c++

我想在2个类之间建立链接,我不确定它的最佳方法是什么。我所拥有的是一组点,我使用delaunay三角测量来找到它们之间的三角形(注意一个点可以属于几个三角形)。接下来,在视频的几个帧中跟踪和更新这些点的位置。因此,三角形的位置也需要以某种方式更新。接下来,我还希望能够删除丢失的点并自动删除与之关联的三角形。你们能给我一些如何组合这些课程的建议吗?

class Point  
{ 
  float x,y;
}

class Triangle
{
  Point p1, pt2, pt3;
}

5 个答案:

答案 0 :(得分:1)

@slava指的是你说一个点可以属于几个三角形的事实。考虑到这一点,您的类应该类似于:

class Point  
{ 
  float x,y;
}

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

你定义Triangle课程的方式,你本来可以随身携带这些分数的副本。如果这些点已被修改,那么你的Triangle类必须单独更新。

请记住,这些不是文字类定义(一切都是私有的),并且你可能想要使用引用计数指针,如unique_ptr

答案 1 :(得分: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;
};

当然,还有很多优化空间:首先是一种容器类型,但它取决于集合的大小,以及插入/删除数据的频率。

答案 2 :(得分: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;

这是一个“工作实例”。 4帧,3帧中有2个三角形。它仅输出顶点为ALL为正的三角形。从一帧到另一帧,点云沿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;
}

答案 3 :(得分:0)

三角形不应包含点,而应包含指向点的指针,因为点存在于三角形之外。另外,在每个点保留关联三角形列表(当然是指针列表)可能很方便,但这实际上取决于使用情况。

答案 4 :(得分:0)

我认为您需要删除三角形(或将其添加到)。 我的代码有点像

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

此代码将重新找到新的点集合的delaunay三角形。 这可能会很慢,并且可能会有一些聪明的algos可以用来加速它。