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