标签:
最近碰到这样一个问题:我们从文件里读入了一组三维空间的点,其中有些点的X,Y,Z座标只存在微小的差别,远小于我们后续数据处理的精度,可以认为它们是重复的。所以我们要把这些重复的点去掉。因为数据量不大,这里不准备使用划分包围盒或者建立k-d tree这样的重型武器,我们简单的把点按照其三维坐标进行排序就好。
我们准备使用STL的std::sort来做这个排序。它要求提供一个符合如下签名的比较函数:
bool cmp(const Type1 &a, const Type2 &b)
怎么样写这个比较函数呢?基本的思路是首先按照点的X座标排序,X座标在误差范围内相等就比较Y,再相等就比较Z。
于是我很快写出第一版:
1 bool compare(const Point& p1, const Point& p2) 2 { 3 if (fabs(p1.x - p2.x) < numeric_tol) 4 { 5 if (fabs(p1.y - p2.y) < numeric_tol) 6 { 7 if (fabs(p1.z - p2.z) < numeric_tol) 8 return true; 9 else if (p1.z < p2.z) 10 return true; 11 else 12 return false; 13 } 14 else if (p1.y < p2.y) 15 return true; 16 else 17 return false; 18 } 19 else if (p1.x < p2.x) 20 return true; 21 else 22 return false; 23 }
运行时居然发现有弹出一个"invalid operator <"的对话框。
于是Google了一下,找到了std::sort的比较函数要满足的三个条件:
a
, comp(a,a)==false详细信息见这里: http://en.cppreference.com/w/cpp/concept/Compare
明显我们的比较函数不符合第一个条件。于是把第8行改成return false就可以工作了。
后来又想,可不可以在比较函数里面不使用tolerance,而只在对排序好的数组进行扫描时使用呢?又尝试了一些思路,发现这样是不行的。完整的测试代码如下:
1 // consle_app_sort_points.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include <vector> 6 #include <algorithm> 7 #include "stdio.h" 8 9 using namespace std; 10 11 struct Point { 12 double x; 13 double y; 14 double z; 15 }; 16 17 double numeric_tol = 1e-6; 18 19 // this compare function results in run time error "invalid operator <" because for below cases it will produce both p1 < p2 and p2 < p1 20 // p1 = (1.1, 1.2, 0) 21 // p2 = (1.2, 1.1, 0) 22 bool compare1(const Point& p1, const Point& p2) 23 { 24 if (p1.x < p2.x) 25 return true; 26 else { 27 if (p1.y < p2.y) 28 return true; 29 else 30 { 31 if(p1.z < p2.z) 32 return true; 33 else 34 return false; 35 } 36 } 37 } 38 39 // compare function with tolerance 40 // 41 bool compare2(const Point& p1, const Point& p2) 42 { 43 if (fabs(p1.x - p2.x) < numeric_tol) 44 { 45 if (fabs(p1.y - p2.y) < numeric_tol) 46 { 47 if (fabs(p1.z - p2.z) < numeric_tol) 48 return false; 49 else if (p1.z < p2.z) 50 return true; 51 else 52 return false; 53 } 54 else if (p1.y < p2.y) 55 return true; 56 else 57 return false; 58 } 59 else if (p1.x < p2.x) 60 return true; 61 else 62 return false; 63 } 64 65 // compare function without tolerance 66 // 67 bool compare3(const Point& p1, const Point& p2) 68 { 69 if (p1.x == p2.x) 70 { 71 if (p1.y == p2.y) 72 { 73 if (p1.z == p2.z) 74 return false; 75 else if (p1.z < p2.z) 76 return true; 77 else 78 return false; 79 } 80 else if (p1.y < p2.y) 81 return true; 82 else 83 return false; 84 } 85 else if (p1.x < p2.x) 86 return true; 87 else 88 return false; 89 } 90 91 // compare function without tolerance 92 // essentially the same with compare3 93 bool compare4(const Point& p1, const Point& p2) 94 { 95 if (p1.x < p2.x) 96 return true; 97 else if (p1.x > p2.x) 98 return false; 99 else { 100 if (p1.y < p2.y) 101 return true; 102 else if (p1.y > p2.y) 103 return false; 104 else { 105 if (p1.z < p2.z) 106 return true; 107 else if (p1.z > p2.z) 108 return false; 109 else 110 return false; 111 } 112 } 113 } 114 115 116 void print(const std::vector<Point>& v) 117 { 118 std::vector<Point>::const_iterator it = v.begin(); 119 for (; it != v.end(); ++it) 120 printf("{%1.7f, %1.7f, %1.7f}\n", it->x, it->y, it->z); 121 } 122 123 int _tmain(int argc, _TCHAR* argv[]) 124 { 125 Point p1 = {1.0000001, 1.2000003, 0.0}; 126 Point p2 = {1.0000002, 1.0, 0.0}; 127 Point p3 = {1.0000002, 1.1, 0.0}; 128 Point p4 = {1.0000002, 1.2000003, 0.0}; 129 130 std::vector<Point> v1; 131 v1.push_back(p1); 132 v1.push_back(p2); 133 v1.push_back(p3); 134 v1.push_back(p4); 135 136 std::vector<Point> v2(v1); 137 138 printf("vector before sort:\n"); 139 print(v1); 140 141 std::sort(v1.begin(), v1.end(), compare2); 142 143 printf("sort using compare function with tolerance:\n"); 144 print(v1); 145 146 printf("\n\n"); 147 148 printf("vector before sort:\n"); 149 print(v2); 150 151 std::sort(v2.begin(), v2.end(), compare4); 152 153 printf("sort using compare function without tolerance:\n"); 154 print(v2); 155 156 return 0; 157 }
运行结果如下。可以发现在比较函数里不使用tolerance确实是不行的。
points vector before sort: {1.0000001, 1.2000003, 0.0000000} {1.0000002, 1.0000000, 0.0000000} {1.0000002, 1.1000000, 0.0000000} {1.0000002, 1.2000003, 0.0000000} sort using compare function with tolerance: {1.0000002, 1.0000000, 0.0000000} {1.0000002, 1.1000000, 0.0000000} {1.0000001, 1.2000003, 0.0000000} // 这两个点被放在一起,是对的
{1.0000002, 1.2000003, 0.0000000} sort using compare function without tolerance: {1.0000001, 1.2000003, 0.0000000} // 第一个点和第四个点不在一起,不行
{1.0000002, 1.0000000, 0.0000000} {1.0000002, 1.1000000, 0.0000000} {1.0000002, 1.2000003, 0.0000000} // 第一个点和第四个点不在一起,不行
将三维空间的点按照座标排序(兼谈为std::sort写compare function的注意事项)
标签:
原文地址:http://www.cnblogs.com/kaige/p/sort_3d_points_array.html