CuraEngine之代码阅读(2)之getClosestPointInPolygon(找最短顶点)函数源码
注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构
C++ 的 STL
- CuraEngine之代码阅读(2)之getClosestPointInPolygon(找最短顶点)函数源码
- 一、PathOrderOptimizer::getClosestPointInPolygon(找最短顶点)
- 1、源代码
- 2、流程详解
- 总结
提示:本文为curaengine 中 多边形函数代码
一、PathOrderOptimizer::getClosestPointInPolygon(找最短顶点)
CuraEngine的功能:用于3D打印,接受STL文件(或其他格式的文件,如AMF文件)作为输入,并输出G代码(GCode)。G代码类似于汇编代码,可以直接在底层硬件上运行,控制电机等运动单元动作。
1、源代码
PathOrderOptimizer::getClosestPointInPolygon
,它的作用是在给定的多边形中找到与指定点的距离最短的的顶点的索引。
函数接受两个参数:
prev_point
:一个Point
类型的对象,表示之前的一个点。poly_idx
:一个整数,表示多边形在多边形集合中的索引。
函数首先根据poly_idx
获取对应的多边形对象poly
。然后,它通过遍历多边形的所有顶点,找到与指定点focus_fixed_point
距离最近的顶点,并将其作为起始点。
接下来,函数使用循环遍历多边形的所有顶点,并根据一些条件计算每个顶点的得分。这些条件包括顶点与前一个点的距离、顶点的角度以及用户指定的偏好设置等。
最后,函数返回得分最高的顶点索引。
int PathOrderOptimizer::getClosestPointInPolygon(Point prev_point, int poly_idx)
{
ConstPolygonRef poly = *polygons[poly_idx];
// Find most extreme point in one direction*. For the 'actual loop' (see below), start from this point,
// so it can act as a 'tie breaker' if all differences in dist-score for a polygon fall within epsilon.
// *) Direction/point should be equal to user-specified point if available, should be an arbitrary point outside of the BP otherwise.
constexpr coord_t EPSILON = 25; // = 5^2 square micron
unsigned int start_from_pos = 0;
const Point focus_fixed_point =
(config.type == EZSeamType::USER_SPECIFIED) ?
config.pos :
Point(0, std::sqrt(std::numeric_limits<coord_t>::max())); // NOTE: Use sqrt, so the squared size can be used when comparing distances.
coord_t smallest_dist_sqd = std::numeric_limits<coord_t>::max();
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
const coord_t dist_sqd = vSize2(focus_fixed_point - poly[point_idx]);
if (dist_sqd < smallest_dist_sqd)
{
start_from_pos = point_idx;
smallest_dist_sqd = dist_sqd;
}
}
const unsigned int end_before_pos = poly.size() + start_from_pos;
// Loop over the polygon to find the 'best' index given all the parameters.
int best_point_idx = -1;
float best_point_score = std::numeric_limits<float>::infinity();
Point p0 = poly.back();
for (unsigned int point_idx_without_modulo = start_from_pos; point_idx_without_modulo < end_before_pos; point_idx_without_modulo++)
{
const unsigned int point_idx = point_idx_without_modulo % poly.size();
const Point& p1 = poly[point_idx];
const Point& p2 = poly[(point_idx + 1) % poly.size()];
// when type is SHARPEST_CORNER, actual distance is ignored, we use a fixed distance and decision is based on curvature only
float dist_score = (config.type == EZSeamType::SHARPEST_CORNER && config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) ? MM2INT(10) : vSize2(p1 - prev_point);
const float corner_angle = LinearAlg2D::getAngleLeft(p0, p1, p2) / M_PI; // 0 -> 2
float corner_shift;
if (config.type == EZSeamType::SHORTEST)
{
// the more a corner satisfies our criteria, the closer it appears to be
// shift 10mm for a very acute corner
corner_shift = MM2INT(10) * MM2INT(10);
}
else
{
// the larger the distance from prev_point to p1, the more a corner will "attract" the seam
// so the user has some control over where the seam will lie.
// the divisor here may need adjusting to obtain the best results (TBD)
corner_shift = dist_score / 10;
}
switch (config.corner_pref)
{
case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_INNER:
if (corner_angle > 1)
{
// p1 lies on a concave curve so reduce the distance to favour it
// the more concave the curve, the more we reduce the distance
dist_score -= (corner_angle - 1) * corner_shift;
}
break;
case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_OUTER:
if (corner_angle < 1)
{
// p1 lies on a convex curve so reduce the distance to favour it
// the more convex the curve, the more we reduce the distance
dist_score -= (1 - corner_angle) * corner_shift;
}
break;
case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_ANY:
// the more curved the region, the more we reduce the distance
dist_score -= fabs(corner_angle - 1) * corner_shift;
break;
case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_WEIGHTED:
{
//More curve is better score (reduced distance), but slightly in favour of concave curves.
float dist_score_corner = fabs(corner_angle - 1) * corner_shift;
if (corner_angle < 1)
{
dist_score_corner *= 2;
}
dist_score -= dist_score_corner;
break;
}
case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE:
default:
// do nothing
break;
}
if ((dist_score - EPSILON) < best_point_score)
{
best_point_idx = point_idx;
best_point_score = dist_score;
}
p0 = p1;
}
return best_point_idx;
}
2、流程详解
PathOrderOptimizer::getClosestPointInPolygon
的函数,它的作用是在给定的多边形中找到最接近指定点的顶点索引。下面是对代码中每一行的解释:
-
int PathOrderOptimizer::getClosestPointInPolygon(Point prev_point, int poly_idx)
:定义了一个名为getClosestPointInPolygon
的成员函数,它接受两个参数:一个Point
类型的对象prev_point
表示之前的一个点,一个整数poly_idx
表示多边形在多边形集合中的索引。 -
ConstPolygonRef poly = *polygons[poly_idx];
:从多边形集合中获取指定索引的多边形,并将其存储在poly
变量中。 -
constexpr coord_t EPSILON = 25;
:定义一个常量EPSILON
,其值为25,用于后续的距离比较。 -
unsigned int start_from_pos = 0;
:定义一个无符号整数变量start_from_pos
,初始值为0,用于记录起始位置。 -
const Point focus_fixed_point = (config.type == EZSeamType::USER_SPECIFIED) ? config.pos : Point(0, std::sqrt(std::numeric_limits<coord_t>::max()));
:根据配置类型,确定一个固定的焦点点focus_fixed_point
。如果配置类型为USER_SPECIFIED
,则使用用户指定的点;否则,使用一个具有最大坐标值的点。 -
coord_t smallest_dist_sqd = std::numeric_limits<coord_t>::max();
:定义一个坐标类型变量smallest_dist_sqd
,初始值为坐标类型的最大值,用于记录最小距离的平方。 -
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
:遍历多边形的所有顶点。 -
const coord_t dist_sqd = vSize2(focus_fixed_point - poly[point_idx]);
:计算当前顶点与固定焦点点之间的距离的平方。 -
if (dist_sqd < smallest_dist_sqd)
:如果当前距离的平方小于最小距离的平方,则更新最小距离的平方和起始位置。 -
const unsigned int end_before_pos = poly.size() + start_from_pos;
:计算循环结束的位置。 -
int best_point_idx = -1;
:定义一个整数变量best_point_idx
,初始值为-1,用于记录最佳顶点索引。 -
float best_point_score = std::numeric_limits<float>::infinity();
:定义一个浮点数变量best_point_score
,初始值为无穷大,用于记录最佳顶点得分。 -
Point p0 = poly.back();
:将多边形的最后一个顶点赋值给变量p0
。 -
for (unsigned int point_idx_without_modulo = start_from_pos; point_idx_without_modulo < end_before_pos; point_idx_without_modulo++)
:遍历多边形的所有顶点,使用取模运算避免越界。 -
const unsigned int point_idx = point_idx_without_modulo % poly.size();
:计算当前顶点的索引。 -
const Point& p1 = poly[point_idx];
:获取当前顶点的引用。 -
const Point& p2 = poly[(point_idx + 1) % poly.size()];
:获取下一个顶点的引用。 -
float dist_score = (config.type == EZSeamType::SHARPEST_CORNER && config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) ? MM2INT(10) : vSize2(p1 - prev_point);
:根据配置类型和用户偏好设置,计算当前顶点的得分。 -
const float corner_angle = LinearAlg2D::getAngleLeft(p0, p1, p2) / M_PI;
:计算当前顶点的角度。 -
float corner_shift;
:定义一个浮点数变量corner_shift
,用于记录角度偏移。 -
if (config.type == EZSeamType::SHORTEST)
:如果配置类型为SHORTEST
,则计算角度偏移。 -
else
:否则,根据距离和用户偏好设置计算角度偏移。 -
switch (config.corner_pref)
:根据用户偏好设置,调整当前顶点的得分。 -
if ((dist_score - EPSILON) < best_point_score)
:如果当前顶点的得分小于最佳顶点得分加上一个很小的值(EPSILON),则更新最佳顶点索引和最佳顶点得分。 -
return best_point_idx;
:返回最佳顶点索引。