先从简单的入手,二维曲线求交。
读者也可以当个学习的Demo来用。
首先看看我们的对标产品实现的怎么样。
说明:整个测试过程中只测试用圆生成的通用曲线求交。之所以用圆是因为圆很直观;之所以只测试通用曲线求交,因为特殊曲线求交可以特殊实现(例如圆和圆求交),代码难度不大,不是技术难点,只是工作量问题。
先做一个普通测试:
#include <iostream>
#include <Geom2d_Circle.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2dAPI_InterCurveCurve.hxx>
#include <Geom2dConvert.hxx>
#include "prof.h"
int main()
{
//定义两个圆
Handle(Geom2d_Circle) circle1 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d(1, 0)), 100);
Handle(Geom2d_Circle) circle2 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(50, 0), gp_Dir2d(1, 0)), 100);
//转成Nurbs,这样能测试通用曲线求交
Handle(Geom2d_BSplineCurve) curve1 = Geom2dConvert::CurveToBSplineCurve(circle1);
Handle(Geom2d_BSplineCurve) curve2 = Geom2dConvert::CurveToBSplineCurve(circle2);
//运算1000次并计时,计时器代码贴到最后
Stopwatch sw;
sw.Resume();
for (int i = 0; i < 1000; ++i) {
Geom2dAPI_InterCurveCurve intCurveCurve(curve1, curve2);
}
sw.Suspend();
Geom2dAPI_InterCurveCurve intCurveCurve(curve1, curve2);
int point_count = intCurveCurve.NbPoints();
int segment_count = intCurveCurve.NbSegments();
//简单输出结果情况和1000次的时间。
std::cout << point_count << "\n";
std::cout << segment_count << "\n";
std::cout << sw.GetTotalTime() << "\n";
}
运行结果:
2
0
0.065093
1000次用时0.065093秒,还是不错的。
再试试重合的情况:
//定义两个圆
Handle(Geom2d_Circle) circle1 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d(1, 0)), 100);
Handle(Geom2d_Circle) circle2 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d(1, 0)), 100);
运行结果:
2
1
3.08635
结果非常不理想,求出2个点和1段重合线,和我预期不太一致,用时方面这次1000次用了3.08635秒,算是非常慢了,可能OpenCASECADE有检测重合的算法,但即使有,每次求交都调重合监测,也不好。
最后测试一下接近重合
//定义两个圆
Handle(Geom2d_Circle) circle1 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d(1, 0)), 100);
Handle(Geom2d_Circle) circle2 = new Geom2d_Circle(gp_Ax2d(gp_Pnt2d(1, 0), gp_Dir2d(1, 0)), 100);
运行结果:
0
0
1.68328
接近重合情况还是很常见的,也是最容易出错的,可见OpenCASECADE表现的并不好,计算结果错误,没有找到交点,耗时也不少,1000次耗时1.68328秒。
总的来说,在求交很明显情况下,效率还是可以的;接近重合情况处理的很不好。
所以优化空间还是很大的!
附录:时间测量类
#include <chrono>
class Stopwatch {
public:
Stopwatch() {
m_is_running = false;
Reset();
}
void Reset() {
if (m_is_running) {
throw;
}
m_total_count = 0;
m_total_time = std::chrono::high_resolution_clock::now() - std::chrono::high_resolution_clock::now();
}
void Resume() {
if (m_is_running) {
throw;
}
m_is_running = true;
m_start_time = std::chrono::high_resolution_clock::now();
}
void Suspend() {
if (!m_is_running) {
throw;
}
++m_total_count;
m_total_time += std::chrono::high_resolution_clock::now() - m_start_time;
m_is_running = false;
}
double GetTotalTime() {
if (m_is_running) {
throw;
}
return m_total_time.count() * 1E-9;
}
double GetTotalCount() {
if (m_is_running) {
throw;
}
return m_total_count;
}
private:
bool m_is_running;
int m_total_count;
std::chrono::steady_clock::time_point m_start_time;
std::chrono::nanoseconds m_total_time;
};