码迷,mamicode.com
首页 > 编程语言 > 详细

将三维空间的点按照座标排序(兼谈为std::sort写compare function的注意事项)

时间:2015-08-12 08:57:46      阅读:697      评论:0      收藏:0      [点我收藏+]

标签:

最近碰到这样一个问题:我们从文件里读入了一组三维空间的点,其中有些点的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的比较函数要满足的三个条件:

  • For all a, comp(a,a)==false
  • If comp(a,b)==true then comp(b,a)==false
  • if comp(a,b)==true and comp(b,c)==true then comp(a,c)==true

详细信息见这里: 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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!