├── .vscode
└── settings.json
├── 备份
├── main.cpp
├── ztKdTree.h
└── ztKdTree.cpp
├── 20180825_gpu_knn
├── ztGpuKnn.cu
├── ztGpuKnn.h
├── ztKdTree.h
├── ztStatisticFilterNoisePoint.cpp
├── ztStatisticFilterNoisePoint.h
├── 20180825_gpu_knn.vcxproj
├── main.cpp
└── ztKdTree.cpp
├── max_heap.cpp
├── 20180825_gpu_knn.sln
├── .gitattributes
└── .gitignore
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "C_Cpp.errorSquiggles": "Disabled"
3 | }
--------------------------------------------------------------------------------
/备份/main.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/备份/main.cpp
--------------------------------------------------------------------------------
/备份/ztKdTree.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/备份/ztKdTree.h
--------------------------------------------------------------------------------
/备份/ztKdTree.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/备份/ztKdTree.cpp
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztGpuKnn.cu:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/20180825_gpu_knn/ztGpuKnn.cu
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztGpuKnn.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/20180825_gpu_knn/ztGpuKnn.h
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztKdTree.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/20180825_gpu_knn/ztKdTree.h
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztStatisticFilterNoisePoint.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/20180825_gpu_knn/ztStatisticFilterNoisePoint.cpp
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztStatisticFilterNoisePoint.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whuxzhsun/quick-kdtree-with-form-of-array/HEAD/20180825_gpu_knn/ztStatisticFilterNoisePoint.h
--------------------------------------------------------------------------------
/max_heap.cpp:
--------------------------------------------------------------------------------
1 |
2 | void buildMaxHeap(int arr[], int n)
3 | {
4 | for (int i = n / 2 - 1; i >= 0; i--)
5 | {
6 | for (int son = i * 2; son <= n; son *= 2)
7 | {
8 | if (son + 1 < n && arr[son] < arr[son + 1])
9 | son++;
10 |
11 | if (arr[i] < arr[son]) // 如果父节点小于子节点,则交换
12 | {
13 | int temp = arr[i];
14 | arr[i] = arr[son];
15 | arr[son] = temp;
16 | }
17 | }
18 | }
19 | }
20 |
21 | // 删除堆顶,将最后一个元素移到堆顶,并且将最后一个元素置为空
22 | void pop(int arr[], int n)
23 | {
24 | arr[0] = arr[n - 1];
25 | arr[n - 1] = -1;
26 | }
27 |
28 | // 遍历堆,寻找合适的插入位置
29 | void push(int arr[], int n, int x)
30 | {
31 | int i = n - 1;
32 | while (i != 0 && x > arr[i / 2])
33 | {
34 | arr[i] = arr[i / 2];
35 | i /= 2;
36 | }
37 |
38 | arr[i] = x;
39 | }
--------------------------------------------------------------------------------
/20180825_gpu_knn.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.40629.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20180825_gpu_knn", "20180825_gpu_knn\20180825_gpu_knn.vcxproj", "{28396411-C6EA-425E-A5F2-38A0B06CB064}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Win32 = Debug|Win32
11 | Debug|x64 = Debug|x64
12 | Release|Win32 = Release|Win32
13 | Release|x64 = Release|x64
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Debug|Win32.ActiveCfg = Debug|Win32
17 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Debug|Win32.Build.0 = Debug|Win32
18 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Debug|x64.ActiveCfg = Debug|x64
19 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Debug|x64.Build.0 = Debug|x64
20 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Release|Win32.ActiveCfg = Release|Win32
21 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Release|Win32.Build.0 = Release|Win32
22 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Release|x64.ActiveCfg = Release|x64
23 | {28396411-C6EA-425E-A5F2-38A0B06CB064}.Release|x64.Build.0 = Release|x64
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 | ipch/
18 | Win32/
19 |
20 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
21 | !packages/*/build/
22 |
23 | # MSTest test Results
24 | [Tt]est[Rr]esult*/
25 | [Bb]uild[Ll]og.*
26 |
27 | *_i.c
28 | *_p.c
29 | *.ilk
30 | *.meta
31 | *.obj
32 | *.pch
33 | *.pdb
34 | *.pgc
35 | *.pgd
36 | *.rsp
37 | *.sbr
38 | *.tlb
39 | *.tli
40 | *.tlh
41 | *.tmp
42 | *.tmp_proj
43 | *.log
44 | *.vspscc
45 | *.vssscc
46 | .builds
47 | *.pidb
48 | *.log
49 | *.scc
50 |
51 | # Visual C++ cache files
52 | ipch/
53 | *.aps
54 | *.ncb
55 | *.opensdf
56 | *.sdf
57 | *.cachefile
58 |
59 | # Visual Studio profiler
60 | *.psess
61 | *.vsp
62 | *.vspx
63 |
64 | # Guidance Automation Toolkit
65 | *.gpState
66 |
67 | # ReSharper is a .NET coding add-in
68 | _ReSharper*/
69 | *.[Rr]e[Ss]harper
70 |
71 | # TeamCity is a build add-in
72 | _TeamCity*
73 |
74 | # DotCover is a Code Coverage Tool
75 | *.dotCover
76 |
77 | # NCrunch
78 | *.ncrunch*
79 | .*crunch*.local.xml
80 |
81 | # Installshield output folder
82 | [Ee]xpress/
83 |
84 | # DocProject is a documentation generator add-in
85 | DocProject/buildhelp/
86 | DocProject/Help/*.HxT
87 | DocProject/Help/*.HxC
88 | DocProject/Help/*.hhc
89 | DocProject/Help/*.hhk
90 | DocProject/Help/*.hhp
91 | DocProject/Help/Html2
92 | DocProject/Help/html
93 |
94 | # Click-Once directory
95 | publish/
96 |
97 | # Publish Web Output
98 | *.Publish.xml
99 |
100 | # NuGet Packages Directory
101 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
102 | #packages/
103 |
104 | # Windows Azure Build Output
105 | csx
106 | *.build.csdef
107 |
108 | # Windows Store app package directory
109 | AppPackages/
110 |
111 | # Others
112 | sql/
113 | *.Cache
114 | ClientBin/
115 | [Ss]tyle[Cc]op.*
116 | ~$*
117 | *~
118 | *.dbmdl
119 | *.[Pp]ublish.xml
120 | *.pfx
121 | *.publishsettings
122 |
123 | # RIA/Silverlight projects
124 | Generated_Code/
125 |
126 | # Backup & report files from converting an old project file to a newer
127 | # Visual Studio version. Backup files are not needed, because we have git ;-)
128 | _UpgradeReport_Files/
129 | Backup*/
130 | UpgradeLog*.XML
131 | UpgradeLog*.htm
132 |
133 | # SQL Server files
134 | App_Data/*.mdf
135 | App_Data/*.ldf
136 |
137 |
138 | #LightSwitch generated files
139 | GeneratedArtifacts/
140 | _Pvt_Extensions/
141 | ModelManifest.xml
142 |
143 | # =========================
144 | # Windows detritus
145 | # =========================
146 |
147 | # Windows image file caches
148 | Thumbs.db
149 | ehthumbs.db
150 |
151 | # Folder config file
152 | Desktop.ini
153 |
154 | # Recycle Bin used on file shares
155 | $RECYCLE.BIN/
156 |
157 | # Mac desktop service store files
158 | .DS_Store
159 |
--------------------------------------------------------------------------------
/20180825_gpu_knn/20180825_gpu_knn.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {28396411-C6EA-425E-A5F2-38A0B06CB064}
23 | _20180825_gpu_knn
24 |
25 |
26 |
27 | Application
28 | true
29 | MultiByte
30 | v120
31 |
32 |
33 | Application
34 | true
35 | MultiByte
36 | v120
37 |
38 |
39 | Application
40 | false
41 | true
42 | MultiByte
43 | v120
44 |
45 |
46 | Application
47 | false
48 | true
49 | MultiByte
50 | v120
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | true
71 |
72 |
73 | true
74 |
75 |
76 | E:\SourceCode\boost_1_62_0_64;E:\SourceCode\las_lib2;$(IncludePath)
77 | E:\SourceCode\boost_1_62_0_64\stage\lib_2013_64;E:\SourceCode\las_lib2\release_64_vs2013_boost_1_62_0_64;$(LibraryPath)
78 |
79 |
80 |
81 | Level3
82 | Disabled
83 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
84 |
85 |
86 | true
87 | Console
88 | cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
89 |
90 |
91 | echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
92 | copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
93 |
94 |
95 |
96 |
97 | Level3
98 | Disabled
99 | WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
100 |
101 |
102 | true
103 | Console
104 | cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
105 |
106 |
107 | echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
108 | copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
109 |
110 |
111 | 64
112 |
113 |
114 |
115 |
116 | Level3
117 | MaxSpeed
118 | true
119 | true
120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 |
122 |
123 | true
124 | true
125 | true
126 | Console
127 | cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
128 |
129 |
130 | echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
131 | copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
132 |
133 |
134 |
135 |
136 | Level3
137 | Disabled
138 | true
139 | true
140 | WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
141 | true
142 |
143 |
144 | true
145 | true
146 | true
147 | Console
148 | cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;liblas.lib;%(AdditionalDependencies)
149 |
150 |
151 | echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
152 | copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)"
153 |
154 |
155 | 64
156 | false
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/20180825_gpu_knn/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "ztKdTree.h"
9 | #include "ztGpuKnn.h"
10 | #include
11 | #include
12 | #include "ztStatisticFilterNoisePoint.h"
13 |
14 | using namespace std;
15 |
16 | struct LasFormat3Point
17 | {
18 | char scanAng;
19 | unsigned char c;
20 | unsigned short id;
21 | unsigned short scandir;
22 | int r, g, b, i;
23 | double x, y, z, t;
24 | };
25 |
26 |
27 | int testKnn();
28 | int testGpuKnn();
29 | int testFilter();
30 |
31 | int main()
32 | {
33 | // testKnn();
34 | testFilter();
35 |
36 | // double sum = 0;
37 |
38 | // clock_t t = clock();
39 | //
40 | // #pragma omp parallel for num_threads(omp_get_num_procs()), reduction(+:sum)
41 | // for (int j = 0; j < 10000000; j++)
42 | // {
43 | // sum += j;
44 | //
45 | // /*printf("\n%d\n", sum);*/
46 | // }
47 | //
48 | // printf("\tcost time of computing: %.3f\n", (clock() - t) / 1000.0);
49 |
50 | // bool *test = new bool[8];
51 | //
52 | // memset(test, 1, 8 * sizeof(bool));
53 | //
54 | // for (int i = 0; i < 8; i++)
55 | // {
56 | // if (test[i])
57 | // {
58 | // printf("%d\n", i);
59 | // }
60 | // }
61 | //
62 | // delete[] test;
63 |
64 | return 0;
65 | }
66 |
67 | int testKnn()
68 | {
69 | printf("Test CPU:\n");
70 | std::string inFile("D:\\20180828_R1000_sanding\\las\\180828_022843_3.las");
71 |
72 | std::ifstream ifs(inFile, std::ios::in | std::ios::binary);
73 | if (!ifs.is_open())
74 | {
75 | std::cout << "can't open " << inFile << endl;
76 |
77 | return 1;
78 | }
79 |
80 | liblas::Reader reader(ifs);
81 | liblas::Header inHeader = reader.GetHeader();
82 |
83 | liblas::Point inPt(&inHeader);
84 |
85 | int m = inHeader.GetPointRecordsCount() / 1000000 + 1;
86 | int n = inHeader.GetPointRecordsCount() / m;
87 | n = (n / ALLTHREADS) * ALLTHREADS;
88 | printf("number of points: %d\n", n);
89 |
90 | unsigned int pointCount = 0;
91 |
92 | for (int j = 0; j < m; j++)
93 | {
94 | clock_t start = clock();
95 |
96 | float *pts = new float[n * 3];
97 |
98 | for (int k = 0; k < n; k++)
99 | {
100 | reader.ReadNextPoint();
101 | inPt = reader.GetPoint();
102 |
103 | pts[k * 3 + 0] = float(inPt.GetX() - inHeader.GetOffsetX());
104 | pts[k * 3 + 1] = float(inPt.GetY() - inHeader.GetOffsetY());
105 | pts[k * 3 + 2] = float(inPt.GetZ() - inHeader.GetOffsetZ());
106 | }
107 |
108 | clock_t end = clock();
109 |
110 | printf("\tcost time of reading points: %.3f\n", (end - start) / 1000.0);
111 |
112 | start = clock();
113 |
114 | zt::ZtKDTree kdt;
115 | kdt.setSize(3, n);
116 | printf_s("\tnumber of points in kdtree: %d\n", n);
117 | kdt.setData(pts);
118 | kdt.buildTree();
119 |
120 | end = clock();
121 |
122 | printf("\tcost time of bulid kdtree: %.3f\n", (end - start) / 1000.0);
123 |
124 | start = clock();
125 |
126 | FILE *fp;
127 | fopen_s(&fp, "D:\\20180419_R1000_ariborne_test_mta\\index_me.txt", "w");
128 | if (!fp)
129 | {
130 | printf("Can.t create file!");
131 | return 1;
132 | }
133 |
134 | float sPt[3] = {
135 | -inHeader.GetOffsetX() + 458127.4,
136 | -inHeader.GetOffsetY() + 4403518.666,
137 | -inHeader.GetOffsetZ() + 23.217
138 | };
139 |
140 | std::vector knn;
141 | int nn = kdt.findNearestRange(sPt, 1.0, knn);
142 |
143 | printf("\tnumber of searched point %d\n", nn);
144 | for (int k = 0; k < nn; k++)
145 | {
146 | fprintf_s(fp, "%.3lf\t%.3lf\t%.3lf\n",
147 | pts[knn[k] * 3 + 0] + inHeader.GetOffsetX(),
148 | pts[knn[k] * 3 + 1] + inHeader.GetOffsetY(),
149 | pts[knn[k] * 3 + 2] + inHeader.GetOffsetZ());
150 | }
151 |
152 | // printf("number of core = %d\n", omp_get_num_procs());
153 | // #pragma omp parallel for num_threads(omp_get_num_procs()/* / 2*/)
154 | // for (int i = 0; i < n; i += 1)
155 | // {
156 | // float sPt[3] = { pts[i * 3 + 0],
157 | // pts[i * 3 + 1],
158 | // pts[i * 3 + 2] };
159 | // /*int nst = kdt.findNearest(sPt);*/
160 | //
161 | // int knn[50];
162 | // float dist[50];
163 | // kdt.findKNearestsNTP(sPt, 50, knn, dist);
164 | //
165 | // /*fprintf_s(fp, "%-6d\t%-6d\n", i, nst);*/
166 | // // fprintf_s(fp, "%d\n", i);
167 | // // for (int k = 0; k < 10; k++)
168 | // // {
169 | // // double dx, dy, dz;
170 | // // dx = sPt[0] - pts[knn[k] * 3 + 0];
171 | // // dy = sPt[1] - pts[knn[k] * 3 + 1];
172 | // // dz = sPt[2] - pts[knn[k] * 3 + 2];
173 | // // fprintf_s(fp, "%-6d\t%5.3f\t", knn[k],
174 | // // sqrt(dx * dx + dy * dy + dz * dz));
175 | // // }
176 | // // fprintf_s(fp, "\n");
177 | // }
178 | fclose(fp);
179 |
180 | printf("\tcost time of knn: %.3f\n", (clock() - start) / 1000.0);
181 |
182 | delete[] pts;
183 | }
184 |
185 | return 0;
186 | }
187 |
188 | int testGpuKnn()
189 | {
190 | /* std::string inFile("D:\\20180419_R1000_ariborne_test_mta\\180419_024813_0.las");
191 |
192 | std::ifstream ifs(inFile, std::ios::in | std::ios::binary);
193 | if (!ifs.is_open())
194 | {
195 | std::cout << "can't open " << inFile << endl;
196 |
197 | return 1;
198 | }
199 |
200 | liblas::Reader reader(ifs);
201 | liblas::Header inHeader = reader.GetHeader();
202 |
203 | liblas::Point inPt(&inHeader);
204 |
205 | int m = inHeader.GetPointRecordsCount() / 1000000 + 1;
206 | int n = inHeader.GetPointRecordsCount() / m;
207 |
208 | int jump = n / ALLTHREADS;
209 | n = (n / ALLTHREADS) * ALLTHREADS;
210 | printf("number of points: %d\n", n);
211 |
212 | unsigned int pointCount = 0;
213 |
214 | for (int j = 0; j < 1; j++)
215 | {
216 | clock_t start = clock();
217 |
218 | float *pts = new float[n * 3];
219 |
220 | for (int k = 0; k < n; k++)
221 | {
222 | reader.ReadNextPoint();
223 | inPt = reader.GetPoint();
224 |
225 | pts[k * 3 + 0] = float(inPt.GetX() - inHeader.GetOffsetX());
226 | pts[k * 3 + 1] = float(inPt.GetY() - inHeader.GetOffsetY());
227 | pts[k * 3 + 2] = float(inPt.GetZ() - inHeader.GetOffsetZ());
228 | }
229 |
230 | clock_t end = clock();
231 |
232 | printf("\tcost time of reading points: %.3f\n", (end - start) / 1000.0);
233 |
234 | start = clock();
235 |
236 | zt::ZtKDTree kdt;
237 | kdt.setSize(3, n);
238 | kdt.setData(pts);
239 | kdt.buildTree();
240 |
241 | end = clock();
242 |
243 | printf("\tcost time of bulid kdtree: %.3f\n", (end - start) / 1000.0);
244 |
245 | start = clock();
246 |
247 |
248 |
249 | FILE *fp;
250 | fopen_s(&fp, "D:\\20180419_R1000_ariborne_test_mta\\index_me_gpu.txt", "w");
251 | if (!fp)
252 | {
253 | printf("Can't create file!");
254 | return 1;
255 | }
256 |
257 | clock_t t1 = clock();
258 |
259 | int nn = 10;
260 | if (kdt.gpuInit(nn))
261 | {
262 | printf("Failed to init gpu!\n");
263 | return 1;
264 | }
265 |
266 | printf("cost time of init gpu: %.3f\n", (clock() - t1) / 1000.0);
267 |
268 | for (int i = 0; i < jump; i += 1)
269 | {
270 | float *sPts = new float[ALLTHREADS * 3];
271 | int *res = new int[ALLTHREADS * nn];
272 |
273 | for (int j = 0; j < ALLTHREADS; j++)
274 | {
275 | sPts[j * 3 + 0] = pts[(j * jump + i) * 3 + 0];
276 | sPts[j * 3 + 1] = pts[(j * jump + i) * 3 + 1];
277 | sPts[j * 3 + 2] = pts[(j * jump + i) * 3 + 2];
278 | }
279 |
280 | if (kdt.gpuFindKNearests(sPts, nn, res))
281 | {
282 | printf("Failed to use gpu!\n");
283 | return 1;
284 | }
285 |
286 | for (int j = 0; j < ALLTHREADS; j++)
287 | {
288 | fprintf_s(fp, "%d\n", j * jump + i);
289 | for (int k = 0; k < nn; k++)
290 | {
291 | double dx, dy, dz;
292 | dx = sPts[j * 3 + 0] - pts[res[j * nn + k] * 3 + 0];
293 | dy = sPts[j * 3 + 1] - pts[res[j * nn + k] * 3 + 1];
294 | dz = sPts[j * 3 + 2] - pts[res[j * nn + k] * 3 + 2];
295 | fprintf_s(fp, "%-6d\t%5.3f\t", res[j * nn + k],
296 | sqrt(dx * dx + dy * dy + dz * dz));
297 | }
298 | fprintf_s(fp, "\n");
299 | }
300 |
301 | delete[] res;
302 | delete[] sPts;
303 | }
304 | fclose(fp);
305 |
306 | printf("\tcost time of knn: %.3f\n", (clock() - start) / 1000.0);
307 |
308 | delete[] pts;
309 | }
310 | //*/
311 | return 0;
312 | }
313 |
314 | int testFilter()
315 | {
316 | std::string inFile("D:\\20180828_R1000_sanding\\las\\180828_022843_5.las");
317 | std::string outFile("D:\\20180828_R1000_sanding\\test\\180828_022843_5_ft.las");
318 |
319 | std::ifstream ifs(inFile, std::ios::in | std::ios::binary);
320 | if (!ifs.is_open())
321 | {
322 | std::cout << "can't open " << inFile << endl;
323 |
324 | return 1;
325 | }
326 |
327 | liblas::Reader reader(ifs);
328 | liblas::Header inHeader = reader.GetHeader();
329 |
330 | liblas::Point inPt(&inHeader);
331 |
332 | int m = inHeader.GetPointRecordsCount() / 1000000 + 1;
333 | int n = inHeader.GetPointRecordsCount() / m;
334 |
335 | printf("number of points: %d\n", m * n);
336 |
337 | std::ofstream ofs(outFile, std::ios::out | std::ios::binary);
338 | if (!ofs.is_open())
339 | {
340 | std::cout << "can't open " << outFile << endl;
341 | return 1;
342 | }
343 |
344 | liblas::Header outHeader;
345 | outHeader.SetVersionMajor(1);
346 | outHeader.SetVersionMinor(2);
347 | outHeader.SetDataFormatId(liblas::ePointFormat3);
348 | outHeader.SetScale(0.001, 0.001, 0.001);
349 | outHeader.SetOffset(inHeader.GetOffsetX(), inHeader.GetOffsetY(), inHeader.GetOffsetZ());
350 |
351 | liblas::Writer writer(ofs, outHeader);
352 | liblas::Point outPt(&outHeader);
353 |
354 | unsigned int pointCount = 0;
355 | unsigned int filterCount = 0;
356 |
357 | clock_t allStart = clock();
358 | for (int j = 0; j < m; j++)
359 | {
360 | clock_t start = clock();
361 |
362 | float *pts = new float[n * 3];
363 | bool *res = new bool[n];
364 |
365 | // std::vector vpts;
366 | // vpts.reserve(n);
367 |
368 | std::vector srcPts;
369 | srcPts.reserve(n);
370 |
371 | LasFormat3Point lf3p;
372 | for (int k = 0; k < n; k++)
373 | {
374 | reader.ReadNextPoint();
375 |
376 | inPt = reader.GetPoint();
377 | lf3p.x = inPt[0];
378 | lf3p.y = inPt[1];
379 | lf3p.z = inPt[2];
380 | lf3p.r = inPt.GetColor().GetRed();
381 | lf3p.g = inPt.GetColor().GetGreen();
382 | lf3p.b = inPt.GetColor().GetBlue();
383 | lf3p.i = inPt.GetIntensity();
384 | lf3p.t = inPt.GetTime();
385 | lf3p.c = inPt.GetClassification().GetClass();
386 | lf3p.id = inPt.GetPointSourceID();
387 | lf3p.scanAng = inPt.GetScanAngleRank();
388 | lf3p.scandir = inPt.GetScanDirection();
389 |
390 | srcPts.push_back(lf3p);
391 |
392 | pts[k * 3 + 0] = float(inPt[0] - inHeader.GetOffsetX());
393 | pts[k * 3 + 1] = float(inPt[1] - inHeader.GetOffsetY());
394 | pts[k * 3 + 2] = float(inPt[2] - inHeader.GetOffsetZ());
395 | }
396 |
397 | clock_t end = clock();
398 |
399 | printf("\ncost time of reading points: %.3f\n", (end - start) / 1000.0);
400 |
401 | start = clock();
402 |
403 | ZtStatisticFilterNoisePoint fnp;
404 | fnp.setParameter(25, 1.0);
405 | fnp.applyFilter_2(n, pts, res);
406 |
407 | end = clock();
408 |
409 | printf("\tcost time of filtering point: %.3f\n", (end - start) / 1000.0);
410 |
411 | start = clock();
412 |
413 | for (int i = 0; i < n; i++)
414 | {
415 | if (!res[i])
416 | {
417 | filterCount++;
418 | outPt.SetClassification(7);
419 | }
420 | else
421 | {
422 | outPt.SetClassification(1);
423 | }
424 |
425 | pointCount++;
426 |
427 | /*outPt = vpts[i];*/
428 |
429 | outPt.SetX(srcPts[i].x);
430 | outPt.SetY(srcPts[i].y);
431 | outPt.SetZ(srcPts[i].z);
432 | outPt.SetColor(liblas::Color(srcPts[i].r, srcPts[i].g, srcPts[i].b));
433 | outPt.SetIntensity(srcPts[i].i);
434 | outPt.SetTime(srcPts[i].t);
435 | outPt.SetClassification(srcPts[i].c);
436 | outPt.SetPointSourceID(srcPts[i].id);
437 | outPt.SetScanAngleRank(srcPts[i].scanAng);
438 | outPt.SetScanDirection(srcPts[i].scandir);
439 |
440 | writer.WritePoint(outPt);
441 | }
442 |
443 | printf("\tcost time of writing point: %.3f\n", (clock() - start) / 1000.0);
444 |
445 | delete[] pts;
446 | }
447 |
448 | outHeader.SetMax(inHeader.GetMaxX(), inHeader.GetMaxY(), inHeader.GetMaxZ());
449 | outHeader.SetMin(inHeader.GetMinX(), inHeader.GetMinY(), inHeader.GetMinZ());
450 | outHeader.SetPointRecordsCount(pointCount);
451 |
452 | writer.SetHeader(outHeader);
453 | writer.WriteHeader();
454 |
455 | printf("\nreserve points : %d, remove points : %d\n", pointCount, filterCount);
456 | printf("\ncost time of filtering all points: %.3f\n", (clock() - allStart) / 1000.0);
457 |
458 | return 0;
459 | }
--------------------------------------------------------------------------------
/20180825_gpu_knn/ztKdTree.cpp:
--------------------------------------------------------------------------------
1 | #include "ztKdTree.h"
2 | #include
3 | #include
4 | #include
5 | /*#include "ztGpuKnn.h"*/
6 |
7 | namespace zt
8 | {
9 | ZtKDTree::ZtKDTree()
10 | : nDimension(0), treeSize(0), offset(0),
11 | tree(0), treePtr(0), data(0), dataPtr(0), isGpuEnable(false)
12 | {
13 |
14 | }
15 |
16 | ZtKDTree::ZtKDTree(int dimension, unsigned int sz)
17 | : nDimension(dimension), treeSize(sz), offset(0),
18 | tree(0), treePtr(0), data(0), dataPtr(0)
19 | {
20 | nDimension = dimension;
21 | treeSize = sz;
22 |
23 | if (nDimension > 0 && treeSize > 0)
24 | {
25 | offset = new double[nDimension];
26 |
27 | tree = new int *[4];
28 | treePtr = new int[4 * treeSize];
29 | for (int i = 0; i < 4; i++)
30 | {
31 | tree[i] = treePtr + i * treeSize;
32 | }
33 |
34 | data = new float *[nDimension];
35 | dataPtr = new float[nDimension * sz];
36 | for (int i = 0; i < nDimension; i++)
37 | {
38 | data[i] = dataPtr + i * treeSize;
39 | }
40 | }
41 | }
42 |
43 | ZtKDTree::~ZtKDTree()
44 | {
45 | if (offset)
46 | {
47 | delete[] offset;
48 | }
49 | if (tree)
50 | {
51 | delete[] tree;
52 | }
53 | if (treePtr)
54 | {
55 | delete[] treePtr;
56 | }
57 | if (data)
58 | {
59 | delete[] data;
60 | }
61 | if (dataPtr)
62 | {
63 | delete[] dataPtr;
64 | }
65 | }
66 |
67 | int ZtKDTree::setSize(int dimension, unsigned int sz)
68 | {
69 | nDimension = dimension; // 数据的维度
70 | treeSize = sz; // 数据的总数
71 |
72 | if (nDimension > 0 && treeSize > 0)
73 | {
74 | offset = new double[nDimension];
75 |
76 | tree = new int *[4];
77 | treePtr = new int[4 * treeSize];
78 | for (int i = 0; i < 4; i++)
79 | {
80 | tree[i] = treePtr + i * treeSize;
81 | }
82 |
83 | data = new float *[nDimension];
84 | dataPtr = new float[nDimension * sz];
85 | for (int i = 0; i < nDimension; i++)
86 | {
87 | data[i] = dataPtr + i * treeSize;
88 | }
89 | }
90 |
91 | return 0;
92 | }
93 |
94 | int ZtKDTree::setOffset(double oft[])
95 | {
96 | for (int i = 0; i < nDimension; i++)
97 | {
98 | offset[i] = oft[i];
99 | }
100 |
101 | return 0;
102 | }
103 |
104 | /*
105 | * indata是一维数组表示多维数组
106 | * 数据排布方式:{[x,y,z……], [x,y,z……], ……}
107 | * dataPtr也是一维数组表示多维数组
108 | * 数据排布方式:{[x1, x2, x3……], [y1, y2, y3……], [z1, z2, z3……], ……}
109 | */
110 | int ZtKDTree::setData(float *indata)
111 | {
112 | for (unsigned int i = 0; i < treeSize; i++)
113 | {
114 | for (int j = 0; j < nDimension; j++)
115 | {
116 | dataPtr[j * treeSize + i] = indata[i * nDimension + j];
117 | }
118 | }
119 |
120 | return 0;
121 | }
122 |
123 | int ZtKDTree::setData(double *indata)
124 | {
125 | for (unsigned int i = 0; i < treeSize; i++)
126 | {
127 | for (int j = 0; j < nDimension; j++)
128 | {
129 | dataPtr[j * treeSize + i] = float(indata[i * nDimension + j] - offset[j]);
130 | }
131 | }
132 |
133 | return 0;
134 | }
135 |
136 | int ZtKDTree::buildTree()
137 | {
138 | std::vector vtr(treeSize);
139 |
140 | for (int i = 0; i < treeSize; i++)
141 | {
142 | vtr[i] = i;
143 | }
144 |
145 | std::random_shuffle(vtr.begin(), vtr.end());
146 |
147 | treeRoot = buildTree(&vtr[0], treeSize, -1); // 根节点的父节点是-1
148 |
149 | return treeRoot;
150 | }
151 |
152 | int ZtKDTree::buildTree(int *indices, int count, int parent)
153 | {
154 | if (count == 1)
155 | {
156 | int rd = indices[0];
157 | tree[0][rd] = 0;
158 | tree[1][rd] = parent;
159 | tree[2][rd] = -1;
160 | tree[3][rd] = -1;
161 |
162 | return rd;
163 | }
164 | else
165 | {
166 | float key = 0;
167 | int split = chooseSplitDimension(indices, count, key);
168 | int idx = chooseMiddleNode(indices, count, split, key);
169 |
170 | // rd 是实际点的下标, idx是点的索引数组的下标
171 | int rd = indices[idx];
172 |
173 | tree[0][rd] = split; // 分割维度
174 | tree[1][rd] = parent;
175 |
176 | if (idx > 0)
177 | {
178 | tree[2][rd] = buildTree(indices, idx, rd);
179 | }
180 | else
181 | {
182 | tree[2][rd] = -1;
183 | }
184 |
185 | if (idx + 1 < count)
186 | {
187 | tree[3][rd] = buildTree(indices + idx + 1, count - idx - 1, rd);
188 | }
189 | else
190 | {
191 | tree[3][rd] = -1;
192 | }
193 |
194 | return rd;
195 | }
196 | }
197 |
198 | int ZtKDTree::findNearest(float *p)
199 | {
200 | int nearestNode;
201 | float minDist = 9999999, distance = 0;
202 |
203 | std::stack paths;
204 |
205 | int node = treeRoot;
206 | while (node > -1)
207 | {
208 | paths.emplace(node);
209 | node = p[tree[0][node]] <= data[tree[0][node]][node] ? tree[2][node] : tree[3][node];
210 | }
211 |
212 | // 回溯路径
213 | while (!paths.empty())
214 | {
215 | node = paths.top();
216 | paths.pop();
217 |
218 | distance = computeDistance(p, node);
219 |
220 | if (distance < minDist)
221 | {
222 | minDist = distance;
223 | nearestNode = node;
224 | }
225 |
226 | // 左右节点都为空,则为叶子节点
227 | if (tree[2][node] + tree[3][node] == -2)
228 | {
229 | continue;
230 | }
231 | else
232 | {
233 | //$$$$$$$$$$$$$$$$$$ 搜索策略 $$$$$$$$$$$$$$$$$$$$$//
234 | // //
235 | // 当前加入路径的节点都是与搜索点在同一空间中的节点 //
236 | // 回溯路径时,如果父节点与当前最大搜索半径相交, //
237 | // 则遍历兄弟空间并加入路径 //
238 | // //
239 | //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//
240 |
241 | int dim = tree[0][node];
242 |
243 | if (fabs(p[dim] - data[dim][node]) < minDist)
244 | {
245 | if (p[dim] < data[dim][node] && tree[3][node] != -1)
246 | {
247 | /*paths.push(tree[3][node]);*/
248 | int reNode = tree[3][node];
249 | while (reNode > -1)
250 | {
251 | paths.emplace(reNode);
252 |
253 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
254 | }
255 | }
256 | else if (p[dim] > data[dim][node] && tree[2][node] != -1)
257 | {
258 | /*paths.push(tree[2][node]);*/
259 | int reNode = tree[2][node];
260 | while (reNode > -1)
261 | {
262 | paths.emplace(reNode);
263 |
264 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
265 | }
266 | }
267 | }
268 | }
269 | }
270 |
271 | return nearestNode;
272 | }
273 |
274 | int ZtKDTree::findNearest(double *p)
275 | {
276 | float *pf = new float[nDimension];
277 |
278 | for (int i = 0; i < nDimension; i++)
279 | {
280 | pf[i] = p[i] - offset[i];
281 | }
282 |
283 | return findNearest(pf);
284 | }
285 |
286 | struct NearestNode
287 | {
288 | int node;
289 | float distance;
290 | NearestNode()
291 | {
292 | node = 0;
293 | distance = 0.0f;
294 | }
295 | NearestNode(int n, float d)
296 | {
297 | node = n;
298 | distance = d;
299 | }
300 | };
301 |
302 | struct cmp // 将最大的元素放在队首
303 | {
304 | bool operator()(NearestNode a, NearestNode b)
305 | {
306 | return a.distance < b.distance;
307 | }
308 | };
309 |
310 | int ZtKDTree::findKNearestsSTL(float *p, int k, int *res)
311 | {
312 | std::priority_queue, cmp> kNeighbors;
313 | std::stack paths;
314 |
315 | // 记录查找路径
316 | int node = treeRoot;
317 | while (node > -1)
318 | {
319 | paths.emplace(node);
320 |
321 | node = p[tree[0][node]] <= data[tree[0][node]][node] ? tree[2][node] : tree[3][node];
322 | }
323 |
324 | // 预先加入一个极大节点
325 | kNeighbors.emplace(-1, 9999999);
326 |
327 | // 回溯路径
328 | float distance = 0;
329 | while (!paths.empty())
330 | {
331 | node = paths.top();
332 | paths.pop();
333 |
334 | distance = computeDistance(p, node);
335 | if (kNeighbors.size() < k)
336 | {
337 | kNeighbors.emplace(node, distance);
338 | }
339 | else
340 | {
341 | if (distance < kNeighbors.top().distance)
342 | {
343 | kNeighbors.pop();
344 | kNeighbors.emplace(node, distance);
345 | }
346 | }
347 |
348 | if (tree[2][node] + tree[3][node] > -2)
349 | {
350 | int dim = tree[0][node];
351 | if (p[dim] > data[dim][node])
352 | {
353 | if (p[dim] - data[dim][node] < kNeighbors.top().distance && tree[2][node] > -1)
354 | {
355 | int reNode = tree[2][node];
356 | while (reNode > -1)
357 | {
358 | paths.emplace(reNode);
359 |
360 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
361 | }
362 | }
363 | }
364 | else
365 | {
366 | if (data[dim][node] - p[dim] < kNeighbors.top().distance && tree[3][node] > -1)
367 | {
368 | int reNode = tree[3][node];
369 | while (reNode > -1)
370 | {
371 | paths.emplace(reNode);
372 |
373 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
374 | }
375 | }
376 | }
377 | }
378 | }
379 |
380 | if (!res)
381 | {
382 | res = new int[k];
383 | }
384 |
385 | int i = kNeighbors.size();
386 | while (!kNeighbors.empty())
387 | {
388 | res[--i] = kNeighbors.top().node;
389 | kNeighbors.pop();
390 | }
391 |
392 | return 0;
393 | }
394 |
395 | int ZtKDTree::findKNearestsNTP(float *p, int k, int *res, float *dit)
396 | {
397 | // 数组形式的最大堆
398 | int *kNeighbors = new int[k];
399 | float *kNDistance = new float[k];
400 | int _currentNNode = 0;
401 |
402 | // 数组形式的路径堆栈
403 | int paths[256];
404 | int _currentPath = 0;
405 |
406 | // 记录查找路径
407 | int node = treeRoot;
408 | while (node > -1)
409 | {
410 | paths[_currentPath++] = node;
411 | if (_currentPath > 255)
412 | {
413 | return 1;
414 | }
415 |
416 | node = p[tree[0][node]] <= data[tree[0][node]][node] ? tree[2][node] : tree[3][node];
417 | }
418 |
419 | kNeighbors[_currentNNode] = -1;
420 | kNDistance[_currentNNode++] = 9999999;
421 |
422 | // 回溯路径
423 | float distance = 0;
424 | while (_currentPath > 0)
425 | {
426 | if (_currentPath > 255)
427 | {
428 | return 1;
429 | }
430 |
431 | node = paths[_currentPath-- - 1];
432 |
433 | distance = computeDistance(p, node);
434 | if (_currentNNode < k)
435 | {
436 | kNeighbors[_currentNNode] = node;
437 | kNDistance[_currentNNode++] = distance;
438 |
439 | // 当达到k个节点后,建立最大堆
440 | if (_currentNNode == k)
441 | {
442 | for (int i = _currentNNode / 2 - 1; i >= 0; i--)
443 | {
444 | int parent = i;
445 |
446 | for (int son = i * 2 + 1; son <= _currentNNode; son = son * 2 + 1)
447 | {
448 | if (son + 1 < _currentNNode && kNDistance[son] < kNDistance[son + 1])
449 | son++;
450 |
451 | if (kNDistance[parent] < kNDistance[son]) // 如果父节点小于子节点,则交换
452 | {
453 | float tempD = kNDistance[parent];
454 | int tempI = kNeighbors[parent];
455 | kNDistance[parent] = kNDistance[son];
456 | kNeighbors[parent] = kNeighbors[son];
457 | kNDistance[son] = tempD;
458 | kNeighbors[son] = tempI;
459 | }
460 |
461 | parent = son;
462 | }
463 | }
464 | }
465 | }
466 | else
467 | {
468 | if (distance < kNDistance[0])
469 | {
470 | // pop
471 | kNeighbors[0] = kNeighbors[_currentNNode - 1];
472 | kNDistance[0] = kNDistance[_currentNNode - 1];
473 |
474 | // 删除堆顶后,要重构最大堆
475 | int parent = 0;
476 | int son = parent * 2 + 1;
477 | for (; son < _currentNNode - 1; son = son * 2 + 1)
478 | {
479 | if (son + 1 < _currentNNode - 1 && kNDistance[son] < kNDistance[son + 1])
480 | son++;
481 |
482 | if (kNDistance[parent] < kNDistance[son]) // 如果父节点小于子节点,则交换
483 | {
484 | float tempD = kNDistance[parent];
485 | int tempI = kNeighbors[parent];
486 | kNDistance[parent] = kNDistance[son];
487 | kNeighbors[parent] = kNeighbors[son];
488 | kNDistance[son] = tempD;
489 | kNeighbors[son] = tempI;
490 | }
491 |
492 | parent = son;
493 | }
494 |
495 | // push
496 | son = _currentNNode - 1;
497 | parent = (son - 1) / 2;
498 | while (son != 0 && distance > kNDistance[parent])
499 | {
500 | kNeighbors[son] = kNeighbors[parent];
501 | kNDistance[son] = kNDistance[parent];
502 | son = parent;
503 | parent = (son - 1) / 2;
504 | }
505 |
506 | kNDistance[son] = distance;
507 | kNeighbors[son] = node;
508 | }
509 | }
510 |
511 | if (tree[2][node] + tree[3][node] > -2)
512 | {
513 | int dim = tree[0][node];
514 | if (p[dim] > data[dim][node])
515 | {
516 | if (p[dim] - data[dim][node] < kNDistance[0] && tree[2][node] > -1)
517 | {
518 | int reNode = tree[2][node];
519 | while (reNode > -1)
520 | {
521 | paths[_currentPath++] = reNode;
522 | if (_currentPath > 255)
523 | {
524 | return 1;
525 | }
526 |
527 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
528 | }
529 | }
530 | }
531 | else
532 | {
533 | if (data[dim][node] - p[dim] < kNDistance[0] && tree[3][node] > -1)
534 | {
535 | int reNode = tree[3][node];
536 | while (reNode > -1)
537 | {
538 | paths[_currentPath++] = reNode;
539 | if (_currentPath > 255)
540 | {
541 | return 1;
542 | }
543 |
544 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
545 | }
546 | }
547 | }
548 | }
549 | }
550 |
551 | // 进行堆排序
552 | for (int i = _currentNNode - 1; i > 0; i--)
553 | {
554 | int tempI = kNeighbors[0];
555 | float tempD = kNDistance[0];
556 | kNeighbors[0] = kNeighbors[i];
557 | kNDistance[0] = kNDistance[i];
558 | kNeighbors[i] = tempI;
559 | kNDistance[i] = tempD;
560 |
561 | int parent = 0;
562 | int son = parent * 2 + 1;
563 | for (; son < i; son = parent * 2 + 1)
564 | {
565 | if (son + 1 < i && kNDistance[son] < kNDistance[son + 1])
566 | son++;
567 |
568 | if (kNDistance[parent] < kNDistance[son])
569 | {
570 | tempD = kNDistance[parent];
571 | tempI = kNeighbors[parent];
572 | kNDistance[parent] = kNDistance[son];
573 | kNeighbors[parent] = kNeighbors[son];
574 | kNDistance[son] = tempD;
575 | kNeighbors[son] = tempI;
576 | }
577 |
578 | parent = son;
579 | }
580 | }
581 |
582 | if (_currentNNode < k)
583 | {
584 | return 1;
585 | }
586 |
587 | if (!res)
588 | {
589 | res = new int[k];
590 | }
591 |
592 | if (!dit)
593 | {
594 | dit = new float[k];
595 | }
596 |
597 | int i = k;
598 | while (i != 0)
599 | {
600 | i--;
601 | res[i] = kNeighbors[i];
602 | dit[i] = kNDistance[i];
603 | }
604 |
605 | delete[] kNeighbors;
606 | delete[] kNDistance;
607 |
608 | return 0;
609 | }
610 |
611 | int ZtKDTree::findKNearests(double *p, int k, int *res)
612 | {
613 | float *pf = new float[nDimension];
614 |
615 | for (int i = 0; i < nDimension; i++)
616 | {
617 | pf[i] = p[i] - offset[i];
618 | }
619 |
620 | findKNearestsSTL(pf, k, res);
621 |
622 | return 0;
623 | }
624 |
625 | int ZtKDTree::findNearestRange(float *p, float range, std::vector &res)
626 | {
627 | std::queue kNeighbors;
628 | std::stack paths;
629 |
630 | // 记录查找路径
631 | int node = treeRoot;
632 | while (node > -1)
633 | {
634 | paths.emplace(node);
635 |
636 | node = p[tree[0][node]] <= data[tree[0][node]][node] ? tree[2][node] : tree[3][node];
637 | }
638 |
639 | // 回溯路径
640 | float distance = 0;
641 | while (!paths.empty())
642 | {
643 | node = paths.top();
644 | paths.pop();
645 |
646 | distance = computeDistance(p, node);
647 | if (distance < range)
648 | {
649 | kNeighbors.emplace(node, distance);
650 | }
651 |
652 | if (tree[2][node] + tree[3][node] > -2)
653 | {
654 | int dim = tree[0][node];
655 | if (p[dim] > data[dim][node])
656 | {
657 | if (p[dim] - data[dim][node] < range && tree[2][node] > -1)
658 | {
659 | int reNode = tree[2][node];
660 | while (reNode > -1)
661 | {
662 | paths.emplace(reNode);
663 |
664 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
665 | }
666 | }
667 | }
668 | else
669 | {
670 | if (data[dim][node] - p[dim] < range && tree[3][node] > -1)
671 | {
672 | int reNode = tree[3][node];
673 | while (reNode > -1)
674 | {
675 | paths.emplace(reNode);
676 |
677 | reNode = p[tree[0][reNode]] <= data[tree[0][reNode]][reNode] ? tree[2][reNode] : tree[3][reNode];
678 | }
679 | }
680 | }
681 | }
682 | }
683 |
684 | res.reserve(kNeighbors.size());
685 |
686 | int i = kNeighbors.size();
687 | int n = i;
688 | while (!kNeighbors.empty())
689 | {
690 | res.push_back(kNeighbors.front().node);
691 | kNeighbors.pop();
692 | }
693 |
694 | return n;
695 | }
696 |
697 | int ZtKDTree::findNearestRange(double *p, float range, std::vector &res)
698 | {
699 | float *pf = new float[nDimension];
700 |
701 | for (int i = 0; i < nDimension; i++)
702 | {
703 | pf[i] = p[i] - offset[i];
704 | }
705 |
706 | return findNearestRange(pf, range, res);
707 | }
708 | /*
709 | int ZtKDTree::gpuInit(int nn)
710 | {
711 | if (getCudaDeviceCount() > 0)
712 | {
713 | if (setCudaStatus(0))
714 | {
715 | return 1;
716 | }
717 | }
718 |
719 | char name[128];
720 | getCudaDeviceNames(0, name);
721 | printf("cuda name = %s\n", name);
722 |
723 | if (initCudaForKdtree(treeSize, nDimension, nn, treePtr, dataPtr))
724 | {
725 | return 1;
726 | }
727 |
728 | isGpuEnable = true;
729 |
730 | return 0;
731 | }
732 |
733 | int ZtKDTree::gpuFindKNearests(float *p, int k,int *res)
734 | {
735 | if (gpuSearchKnnKdtree(treeRoot, nDimension, treeSize, k, p, res))
736 | {
737 | return 1;
738 | }
739 |
740 | return 0;
741 | }
742 |
743 | int ZtKDTree::gpuFindKNearests(double *p, int k, int *res)
744 | {
745 | float *pf = new float[nDimension];
746 |
747 | for (int i = 0; i < nDimension; i++)
748 | {
749 | pf[i] = p[i] - offset[i];
750 | }
751 |
752 | gpuFindKNearests(pf, k, res);
753 |
754 | return 0;
755 | }
756 | //*/
757 | /*
758 | * 建树功能函数
759 | */
760 | int ZtKDTree::chooseSplitDimension(int *ids, int sz, float &key)
761 | {
762 | int split = 0;
763 |
764 | float *var = new float[nDimension];
765 | float *mean = new float[nDimension];
766 |
767 | int cnt = sz/*std::min((int)SAMPLE_MEAN, sz)*/;/* cnt = sz;*/
768 | double rt = 1.0 / cnt;
769 |
770 | for (int i = 0; i < nDimension; i++)
771 | {
772 | double sum1 = 0, sum2 = 0;
773 | for (int j = 0; j < cnt; j++)
774 | {
775 | sum1 += data[i][ids[j]] * data[i][ids[j]];
776 | sum2 += data[i][ids[j]];
777 | }
778 | var[i] = rt * sum1 - rt * sum2 * rt * sum2;
779 | mean[i] = rt * sum2;
780 | }
781 |
782 | double max = -9999999;
783 |
784 | for (int i = 0; i < nDimension; i++)
785 | {
786 | if (var[i] > max)
787 | {
788 | key = mean[i];
789 | max = var[i];
790 | split = i;
791 | }
792 | }
793 |
794 | delete[] var;
795 | delete[] mean;
796 |
797 | return split;
798 | }
799 |
800 | int ZtKDTree::chooseMiddleNode(int *ids, int sz, int dim, float key)
801 | {
802 | int left = 0;
803 | int right = sz - 1;
804 |
805 | while (1)
806 | {
807 | while (left <= right && data[dim][ids[left]] <= key) //左边找比key大的值
808 | ++left;
809 |
810 | while (left <= right && data[dim][ids[right]] >= key) //右边找比key小的值
811 | --right;
812 |
813 | if (left > right)
814 | break;
815 |
816 | std::swap(ids[left], ids[right]);
817 | ++left;
818 | --right;
819 | }
820 |
821 | // int lim1 = left;
822 | //
823 | // right = sz - 1;
824 | // while (1)
825 | // {
826 | // while (left <= right && data[dim][ids[left]] <= key) //左边找比key大的值
827 | // ++left;
828 | //
829 | // while (left <= right && data[dim][ids[right]] > key) //右边找比key小的值
830 | // --right;
831 | //
832 | // if (left > right)
833 | // break;
834 | //
835 | // std::swap(ids[left], ids[right]);
836 | // left++;
837 | // right--;
838 | // }
839 | //
840 | // int index = 0, lim2 = left;
841 | //
842 | // if (lim1 > sz / 2)
843 | // index = lim1;
844 | // else if (lim2 < sz / 2)
845 | // index = lim2;
846 | // else
847 | // index = sz / 2;
848 | //
849 | // if ((lim1 == sz) || (lim2 == 0))
850 | // index = sz / 2;
851 | //
852 | // index = left;
853 |
854 | // 找出左子树的最大值作为根节点
855 | float max = -9999999;
856 | int maxIndex = 0;
857 | for (int i = 0; i < left; i++)
858 | {
859 | if (data[dim][ids[i]] > max)
860 | {
861 | max = data[dim][ids[i]];
862 | maxIndex = i;
863 | }
864 | }
865 |
866 | if (left > 0)
867 | {
868 | if (maxIndex != left - 1)
869 | {
870 | std::swap(ids[maxIndex], ids[left - 1]);
871 | }
872 | }
873 |
874 | return left - 1 > 0 ? left - 1 : 0;
875 | }
876 |
877 | float ZtKDTree::computeDistance(float *p, int n)
878 | {
879 | float sum = 0;
880 |
881 | for (int i = 0; i < nDimension; i++)
882 | {
883 | sum += (p[i] - data[i][n]) * (p[i] - data[i][n]);
884 | }
885 |
886 | return sqrt(sum);
887 | }
888 |
889 | int ZtKDTree::outKdTree(const char *outPath)
890 | {
891 | FILE *fp;
892 | fopen_s(&fp, outPath, "w");
893 | if (!fp)
894 | {
895 | printf("Failed to create: %s", outPath);
896 | return 1;
897 | }
898 |
899 | for (int i = 0; i < treeSize; i++)
900 | {
901 | fprintf_s(fp, "%d\t%7.3f\t%7.3f\t%7.3f\t%d\t%6d\t%6d\n",
902 | i, data[0][i], data[1][i], data[2][i],
903 | tree[0][i], tree[2][i], tree[3][i]);
904 | }
905 |
906 | fclose(fp);
907 |
908 | return 0;
909 | }
910 | }
911 |
--------------------------------------------------------------------------------