点和三角形之间的链接
Link between points and triangles
我想在两个类之间建立一个链接,但我不确定什么是最好的方法。我有一组点,我使用delaunay三角测量来查找它们之间的三角形(注意,一个点可以属于几个三角形)。接下来,在视频的几个帧中跟踪和更新这些点的位置。因此,三角形的位置也需要以某种方式更新。除此之外,我还希望能够删除丢失的点,并自动删除与之相关的三角形。你们能给我一些如何组合这些类的建议吗?
class Point
{
float x,y;
}
class Triangle
{
Point p1, pt2, pt3;
}
计算机图形中的此类集合交互通常使用索引来实现。
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;
};
当然,还有很多优化空间:首先是容器的类型,但这取决于集合的大小,以及插入/擦除数据的频率。
@slava指的是一个点可以属于几个三角形的事实。考虑到这一点,你的课程应该看起来像:
class Point
{
float x,y;
}
class Triangle
{
Point * p1;
Point * pt2;
Point * pt3;
}
按照你定义三角形类的方式,你会随身携带点的副本。如果修改了这些点,则必须单独更新Triangle类。
请记住,这些不是字面上的类定义(所有内容都是私有的),并且您可能希望使用引用计数指针,如unique_ptr
您可能会使用以下数据结构:
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;
}
三角形不应包含点,而应包含指向点的指针,因为点存在于三角形之外。此外,在每个点中保留相关三角形的列表(当然是指针的列表)可能很方便,但这实际上取决于使用情况。
我认为您需要一些东西来删除(或添加)三角形。我的代码有点像
std::vector<Triangle> update_triangles(const std::vector<Point> & points)
{
//...
}
此代码将重新查找新点集合的delaunay三角形。这可能会被证明是缓慢的,并且可能有一些聪明的算法可以在以后用来加快速度。
- 文件删除(使用取消链接)与释放所有磁盘空间之间的延迟
- 如何在这两个分类的链接列表之间获得开关的位置
- 链接时,"grab what you need" 和 "grab all" 之间是否有某些内容(-wl,--whole-archive)?
- unordered_set与链接列表之间的性能比较
- 链接列表C 类,这两个添加节点实现之间的差异是什么?
- C 在与.o链接和.A文件之间有所不同:不同的行为,原因
- 如何使用C#或C 之间创建文本框之间的链接
- C# 和 C++ 代码之间的链接在 64 位计算机中不起作用
- Delphi链接器和C++链接器之间的区别
- Qt在文件夹之间创建链接
- C++ 中编译器、链接器和调试器之间的区别
- 文件之间的链接 - 它究竟是如何工作的
- Natty Narwhal和Oneiric Ocelot之间共享对象链接的差异
- 如何在树模型中维护父 QStandardItems 和数据库行 ID 之间的链接
- 链接和绑定之间的区别是什么
- matlab R2013a与MS VC++2013之间的链接错误
- 链接列表中的节点、&node 和 node->next 之间的区别
- 点和三角形之间的链接
- C++如何在VS 2015中设置文件之间的链接
- 库设计:允许用户在"header-only"和动态链接之间做出决定?