前言
始于2024年1月14日,我打算从0,从三种语言的方式,实现计算几何的相关知识,如凸包、向量、三角剖分、线性规划、 kd-树一直到计算机图形学,即使用计算机语言描述几何学的知识。
点是基本元素。
如何表示一个点,用C的数组和结构体,C++的vector或者类,python的numpy array。
总结一下就是:
double point[3] = {0, 0, 1};C的数组
struct Vertex vertex = {12, 1, 10};C的结构体
std::vector<std::array<double, 3>> points;C++的vector,以C++的数组为类型
std::vector<Vertex> vertex;C++的vector,以C的结构体为类型
C++的类,核心属性就是点云:std::vector<Vertex> vertex
class MyPoint
{
public:
MyPoint(/* args */);
~MyPoint();
std::vector<Vertex> points;//点云
};
C 使用数组表示点
使用一维数组存储一个点,多维数组存多个点
单个点: double point[3] = {0, 0, 1};
三个点:double pointss[3][3] = {
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0},
{7.0, 8.0, 9.0}};
数组有个缺点就是容量是固定不变的,这就为使用C++的vector或者类做铺垫。
#include <stdio.h>
int main()
{
//---------------------------one point----------------------------
// array point
double point[3] = {0, 0, 1};
printf("X=%lf, Y=%lf, Z=%lf, nice to meet you!\n", point[0], point[1], point[2]);
//---------------------------more point----------------------------
// more array point
double pointss[3][3] = {
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0},
{7.0, 8.0, 9.0}};
// 获取数组的行数和列数
int rows = sizeof(pointss) / sizeof(pointss[0]);
int cols = sizeof(pointss[0]) / sizeof(pointss[0][0]);
return 0;
}
C 使用struct表示点
经安哥点拨,在视频中是这样表示角点的
【48】C++的stdvector使用优化_哔哩哔哩_bilibili
简化一下就是
struct Vertex
{
float x, y, z;
};
int main()
{
struct Vertex vertex = {12, 1, 10};
printf("X=%lf, Y=%lf, Z=%lf, struct Vertex!\n", vertex.x, vertex.y, vertex.z);
return 0;
}
C++ 使用vector表示点
在容器里装一堆 一维数组,表示点云
std::vector<std::array<double, 3>> points;
或者在vector中装上文的C结构体
std::vector<Vertex> vertexList;
为什么用vector?
因为vector容量大小可变,而数组不可变,并且vector被C++封装了各种遍历、排序、增删改的功能,方便使用。
为什么不用C的数组作为类型
因为:这边初始Vector不设置死他的容量,否则不如用c的数组来的简洁,要的就是他的灵活大小。
所以:采用默认初始化:
vector<T> v1 ; v1 是一个元素类型为 T 的空 vector
又因为:C++ 的标准库中的 vector 不直接支持数组作为元素类型,所以不能写为vector<double[3
>
所以:如果一定要添加C的数组到vector中是没有办法的,最多就是用C的数组初始化array
double point1[3] = {1.0, 1.0, 5.0};
std::vector<double> pointVector1(point1, point1 + sizeof(point1) / sizeof(point1[0]));
需要注意的是:
std::array 是一个 C++ 类模板,它封装了数组并提供了许多实用的成员函数,如 .size() 以获取数组大小。
double point[3] = {0, 0, 1}; 是一个简单的数组声明,不封装任何额外的信息。它在 C++ 中被允许,但不提供与数组大小相关的信息。
关于vector的其他知识,请移步
https://blog.csdn.net/Flag_ing/article/details/123380655
#include <vector>
#include <array>
#include <iostream>
struct Vertex
{
float x, y, z;
};
int main()
{
// vector point
std::vector<std::array<double, 3>> points;
std::vector<Vertex> vertexList;
//---------------------------three point----------------------------
std::array<double, 3> point = {1.0, 1.0, 5.0};
points.push_back(point);
points.push_back(point);
points.push_back(point);
// 打印第一个点的坐标
int i = 1;
for (auto pt : points)
{
std::cout << "Point: " << std::endl;
for (double coordinate : pt)
{
std::cout << coordinate << " ";
}
std::cout << std::endl;
i++;
}
//---------------------------three point----------------------------
struct Vertex vertex01 = {251.0, 100.0, -7.0};
struct Vertex vertex02 = {14.0, 8.0, -100.0};
struct Vertex vertex03 = {99.0, 69.0, 45.0};
vertexList.push_back(vertex01);
vertexList.push_back(vertex02);
vertexList.push_back(vertex03);
// 打印第一个点的坐标
for (auto pt : vertexList)
{
std::cout << "Point: " << i << std::endl;
std::cout << pt.x << " ";
std::cout << pt.y << " ";
std::cout << pt.z << " ";
std::cout << std::endl;
i++;
}
return 0;
}
C++ 使用类表示点云
思路是这样的,上文里用了vector表示点云,但是作为一个点云对象,有一些点云库具备各种实例方法方便大家使用,还可以重载运算符如 + ,两个点云相加就非常明了了。(心虚,其实我就是想搞个类重现一下点云库而已)
这里设置一个class MyPoint,里面关键的属性就是点云std::vector<Vertex> points;然后自定义一个添加其他点云的add函数,和一个打印点云坐标的函数,解析如下,基础知识放在本章最后:
结构体 Vertex
struct Vertex: 这里定义了一个结构体 Vertex,包含三个浮点型成员变量 x、y 和 z,用于表示一个三维点的坐标。
struct Vertex
{
float x, y, z;
};
class MyPoint
class MyPoint: 这是一个类的定义,表示一个点云。类中包含一个私有数据成员(private data member)和一些公有成员函数(public member functions)。
核心就在 std::vector<Vertex> points; // 公有成员变量,存储 Vertex 结构体的向量
class code
struct Vertex
{
float x, y, z;
};
class MyPoint
{
private:
/* data */ // 这里可以声明私有成员变量
public:
MyPoint(/* args */); // 构造函数的声明
~MyPoint(); // 析构函数的声明
MyPoint add(MyPoint); // add 成员函数的声明
void print(); // print 成员函数的声明
std::vector<Vertex> points; // 公有成员变量,存储 Vertex 结构体的向量
};
MyPoint MyPoint::add(MyPoint a)
{
for (auto pt : a.points)
{
// 将另一个点的坐标逐个加到当前点的坐标上
this->points.push_back(pt);
}
// 返回修改后的当前点
return *this;
}
void MyPoint::print()
{
// 注意,这里是->访问而不是 . 访问
int i = 1;
for (auto pt : this->points)
{
// 将另一个点的坐标逐个加到当前点的坐标上
std::cout << "class Point: " << i << std::endl;
std::cout << pt.x << " ";
std::cout << pt.y << " ";
std::cout << pt.z << " ";
std::cout << std::endl;
i++;
// 返回修改后的当前点
}
}
MyPoint::MyPoint(/* args */)
{
}
MyPoint::~MyPoint()
{
}
函数解析
MyPoint::add(MyPoint a): 这是 MyPoint 类中 add 函数的实现。该函数接受一个 MyPoint 类型的参数 a,将其成员变量 points 中的点逐个添加到当前点的 points 向量中。该函数返回修改后的当前点。
void MyPoint::print(): 这是 MyPoint 类中 print 函数的实现。该函数用于打印当前点的坐标。在函数中,通过循环遍历 points 向量,逐个打印每个点的坐标。
MyPoint::MyPoint(/* args */): 这是 MyPoint 类中构造函数的实现。构造函数是在对象创建时被调用的函数,这里的构造函数没有实现特殊的逻辑。
MyPoint::~MyPoint(): 这是 MyPoint 类中析构函数的实现。析构函数是在对象销毁时被调用的函数,这里的析构函数没有实现特殊的逻辑。
C和C++中类的基础知识:
构造函数和析构函数:
构造函数是在对象创建时被调用的特殊成员函数,用于初始化对象的成员变量。
析构函数是在对象销毁时被调用的特殊成员函数,用于清理对象的资源。
成员函数:
成员函数是定义在类中的函数,它们可以访问类的私有成员。
成员函数可以有返回值,也可以是 void(无返回值)。
成员变量:
成员变量是类中的数据成员,可以是各种数据类型,包括基本数据类型和自定义的结构体、类等。
访问修饰符:
private、public 和 protected 是访问修饰符,用于指定成员的访问权限。
private 表示只能在类的内部访问,public 表示可以在类的外部访问。
this 指针:
this 指针是一个隐含在每个成员函数中的指针,指向调用该函数的对象。
通过 this 指针,可以访问对象的成员变量和其他成员函数。
标准库容器:
std::vector 是C++标准库中的一个动态数组容器,可以动态增长或缩小。
在这个例子中,points 是一个存储 Vertex 结构体的向量,用于保存点的坐标。
C++、C struct 类的可运行代码:
#include <vector>
#include <array>
#include <iostream>
struct Vertex
{
float x, y, z;
};
class MyPoint
{
private:
/* data */
public:
MyPoint(/* args */);
~MyPoint();
MyPoint add(MyPoint);
void print();
std::vector<Vertex> points;
};
MyPoint MyPoint::add(MyPoint a)
{
for (auto pt : a.points)
{
// 将另一个点的坐标逐个加到当前点的坐标上
this->points.push_back(pt);
}
// 返回修改后的当前点
return *this;
}
void MyPoint::print()
{
// 注意,这里是->访问而不是 . 访问
int i = 1;
for (auto pt : this->points)
{
// 将另一个点的坐标逐个加到当前点的坐标上
std::cout << "class Point: " << i << std::endl;
std::cout << pt.x << " ";
std::cout << pt.y << " ";
std::cout << pt.z << " ";
std::cout << std::endl;
i++;
// 返回修改后的当前点
}
}
MyPoint::MyPoint(/* args */)
{
}
MyPoint::~MyPoint()
{
}
int main()
{
// vector point
std::vector<std::array<double, 3>> points;
std::vector<Vertex> vertexList;
MyPoint pointCloud;
//---------------------------three point----------------------------
std::array<double, 3> point = {1.0, 1.0, 5.0};
points.push_back(point);
points.push_back(point);
points.push_back(point);
// 打印第一个点的坐标
int i = 1;
for (auto pt : points)
{
std::cout << "arry Point: " << std::endl;
for (double coordinate : pt)
{
std::cout << coordinate << " ";
}
std::cout << std::endl;
i++;
}
//---------------------------three point----------------------------
struct Vertex vertex01 = {251.0, 100.0, -7.0};
struct Vertex vertex02 = {14.0, 8.0, -100.0};
struct Vertex vertex03 = {99.0, 69.0, 45.0};
vertexList.push_back(vertex01);
vertexList.push_back(vertex02);
vertexList.push_back(vertex03);
// 打印第一个点的坐标
for (auto pt : vertexList)
{
std::cout << "struct Point: " << i << std::endl;
std::cout << pt.x << " ";
std::cout << pt.y << " ";
std::cout << pt.z << " ";
std::cout << std::endl;
i++;
}
//---------------------------three point----------------------------
pointCloud.points.push_back(vertex01);
pointCloud.points.push_back(vertex02);
pointCloud.points.push_back(vertex03);
// 打印第一个点的坐标
pointCloud.add(pointCloud);
pointCloud.print();
return 0;
}
python 使用numpy表示点云
numpy数组表示点云有诸多好处,因为numpy中有大量的数学库,后面都会用到,这里先做一个点意思一下。
pt = np.array([10, 2, 3])
import numpy as np
pt = np.array([10, 2, 3])
print(pt)
至此,三种语言描述点元素暂时完成,文件夹如下。需要注意的是,由于混合了py和c在同一环境,这里运行py文件还需要切换到conda的有numpy环境下用命令行运行
更新日志
更新日志:2024年1月20日新增C的结构体点表示,新增C++ std::vector<Vertex> vertexList;新增C++的class表达,新增numpy点云表达