主要用该算法解决直线在区间内的截取
理论部分可参考: https://www.cnblogs.com/fortunely/p/17739080.html
代码实现:
1、 区域划分
// CODING SCHEME
//
// | ABOVE |
// | 0x08 |
// 1001 | 1000 | 1010
// ----+------------+----
// LEFT | INSIDE | RIGHT
// 0x01 | 2D RANGE | 0x02
// | |
// 0001 | 0000 | 0010
// ----+------------+----
// | BELOW |
// 0101 | 0x04 | 0110
// | 0100 |
#define RANGE_INSIDE 0
#define RANGE_LEFT 0x01
#define RANGE_RIGHT 0x02
#define RANGE_BELOW 0x04
#define RANGE_ABOVE 0x08
顶部首位为1,底部第二位为1,右边第3位为1,左边第4位为1 。
按照井字形划分为9个区域;
2、定义区域结构体
typedef struct Range_
{
float x_min;
float x_max;
float y_min;
float y_max;
} Range;
3、定义线段
typedef struct Point_
{
float x;
float y;
} Point;
typedef struct Line_
{
Point P1;
Point P2;
} Line;
4、计算点落在区域内
uint_8 get_region_code(Range const * range,Point const * point){
uint_32 result_region = VOX_ROI_INSIDE;
if (point->x < range->x_min){
result_region |= VOX_ROI_BIT_LEFT;
}else if (point->x > range->x_max){
result_region |= VOX_ROI_BIT_RIGHT;
}
if (point->y < range->y_min){
result_region |= VOX_ROI_BIT_BELOW;
}else if (point->y > range->y_max){
result_region |= VOX_ROI_BIT_ABOVE;
}
return (uint_8) result_region;
}
5、Cohen Sutherland Clipping 科恩-萨瑟兰算法
bool LineSegmentInOrIntersectRangeBox(const Range* range_box,Line* line_segment){
uint_8 p1_in_region;
uint_8 p2_in_region;
bool result = false;
if((range_box == NULL) || (line_segment == NULL)) return result;
p1_in_region = get_region_code(range_box, &line_segment->P1_st);
p2_in_region = get_region_code( range_box, &line_segment->P2_st );
// Trivial case 1: one of the points is inside the rectangle
if(p1_in_region == VOX_ROI_INSIDE && p2_in_region == VOX_ROI_INSIDE){
result = false;
}else if (
((p1_in_region | p2_in_region) == (VOX_ROI_BIT_ABOVE | VOX_ROI_BIT_BELOW)) || // trivial case 3 - horizontal crossing: one point is LEFT, one point is RIGHT
((p1_in_region | p2_in_region) == (VOX_ROI_BIT_RIGHT | VOX_ROI_BIT_LEFT )) || // trivial case 4 - vertical crossing: one point is ABOVE, one point is BELOW
((p1_in_region | p2_in_region) == (VOX_ROI_BIT_ABOVE | VOX_ROI_BIT_BELOW | VOX_ROI_BIT_RIGHT | VOX_ROI_BIT_LEFT )) ){ //diagonal crossing
result = true;
}else{
float tmp_x, tmp_y;
point P0, P1;
if (line_segment->P1.x <= line_segment->P2.x){
P0 = line_segment->P1;
P1 = line_segment->P2;
}else{
P0 = line_segment->P2;
P1 = line_segment->P1;
}
if (((p1_in_region | p2_in_region) & (UInt8)VOX_ROI_BIT_LEFT) != (UInt8)VOX_ROI_INSIDE){
tmp_y = (P1.y - P0.y) * (range_box->x_min - P0.x) / (P1.x - P0.x);
tmp_y += P0_st.Y_f32;
if ((tmp_y > range_box->y_min) && (tmp_y < range_box->y_max)){
result = true;
}
}
if (((p1_in_region | p2_in_region) & (UInt8)VOX_ROI_BIT_RIGHT) != (UInt8)VOX_ROI_INSIDE){
tmp_y = (P1.y - P0.y) * (range_box->x_max - P0.x) / (P1.x - P0.x);
tmp_y += P0.Y_f32;
if ((tmp_y > range_box->y_min) && (tmp_y < range_box->y_max)){
result = true;
}
}
if (((p1_in_region | p2_in_region) & (UInt8)VOX_ROI_BIT_ABOVE) != (UInt8)VOX_ROI_INSIDE){
tmp_x = (P1.X_f32 - P0.X_f32) * (range_box->YMax_f32 - P0.Y_f32) / P1.Y_f32 - P0.Y_f32;
tmp_x += P0_st.X_f32;
if ((tmp_x > range_box->XMin_f32) && (tmp_x < range_box->XMax_f32)){
result = true;
}
}
if (((p1_in_region | p2_in_region) & (UInt8)VOX_ROI_BIT_BELOW) != (UInt8)VOX_ROI_INSIDE)
{
tmp_x = (P1.x - P0.x) * (range_box->y_min - P0.y) / (P1.y - P0.y);
tmp_x += P0.x;
if ((tmp_x > range_box->x_min) && (tmp_x < range_box->x_max)){
result = true;
}
}
}
return result;
}