Add PathFinder algorithm using SPFA
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene3d / utc-Dali-PathFinding.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include "dali-scene3d/public-api/algorithm/navigation-mesh.h"
19 #include "dali-scene3d/public-api/algorithm/path-finder.h"
20 #include "dali-scene3d/public-api/loader/navigation-mesh-factory.h"
21 #include <dali-test-suite-utils.h>
22
23 using namespace Dali;
24 using namespace Dali::Scene3D::Algorithm;
25 using namespace Dali::Scene3D::Loader;
26
27 bool CompareResults( const std::vector<uint32_t>& nodes, const WayPointList& waypoints )
28 {
29   if(nodes.size() != waypoints.size())
30   {
31     std::ostringstream oss;
32     oss << "expect indexs : [";
33     for(const auto& index : nodes)
34     {
35       oss << index << ", ";
36     }
37     oss << "]\n";
38     oss << "your indexs : [";
39     for(const auto& waypoint : waypoints)
40     {
41       oss << waypoint.GetNavigationMeshFaceIndex() << ", ";
42     }
43     oss << "]\n";
44     tet_printf("%s\n",oss.str().c_str());
45     return false;
46   }
47   for(auto i = 0u; i < nodes.size(); ++i )
48   {
49     if(nodes[i] != waypoints[i].GetNavigationMeshFaceIndex())
50     {
51       std::ostringstream oss;
52       oss << "expect indexs : [";
53       for(const auto& index : nodes)
54       {
55         oss << index << ", ";
56       }
57       oss << "]\n";
58       oss << "your indexs : [";
59       for(const auto& waypoint : waypoints)
60       {
61         oss << waypoint.GetNavigationMeshFaceIndex() << ", ";
62       }
63       oss << "]\n";
64       tet_printf("%s\n",oss.str().c_str());
65       return false;
66     }
67   }
68   return true;
69 }
70
71 int UtcDaliPathFinderNewP(void)
72 {
73   auto navmesh = NavigationMeshFactory::CreateFromFile( "resources/navmesh-test.bin");
74
75   auto pathfinder = PathFinder::New( *navmesh, PathFinderAlgorithm::DEFAULT );
76
77   DALI_TEST_CHECK(navmesh);
78   DALI_TEST_CHECK(pathfinder);
79
80   END_TEST;
81 }
82
83 int UtcDaliPathFinderNewFail(void)
84 {
85   auto navmesh = NavigationMeshFactory::CreateFromFile( "resources/navmesh-test.bin");
86
87   auto pathfinder = PathFinder::New( *navmesh, static_cast<PathFinderAlgorithm>(-1) );
88
89   DALI_TEST_CHECK(navmesh);
90   DALI_TEST_CHECK(!pathfinder);
91
92   END_TEST;
93 }
94
95 void printWaypointForPython( WayPointList& waypoints)
96 {
97   tet_printf( "size: %d\n", waypoints.size());
98   tet_printf( "[");
99   for(auto& wp : waypoints)
100   {
101     auto index = wp.GetNavigationMeshFaceIndex();
102     tet_printf("%d, ", index);
103   }
104   tet_printf( "]");
105 }
106
107 int UtcDaliPathFinderFindShortestPath0(void)
108 {
109   auto navmesh = NavigationMeshFactory::CreateFromFile( "resources/navmesh-test.bin");
110
111   std::vector<PathFinderAlgorithm> testAlgorithms = {
112     PathFinderAlgorithm::DJIKSTRA_SHORTEST_PATH,
113     PathFinderAlgorithm::SPFA,
114   };
115
116   for(const auto& algorithm : testAlgorithms)
117   {
118     tet_printf("Test algorithm type : %d\n", static_cast<int>(algorithm));
119     auto pathfinder = PathFinder::New( *navmesh, algorithm );
120
121     DALI_TEST_CHECK(navmesh);
122     DALI_TEST_CHECK(pathfinder);
123
124     {
125       auto waypoints = pathfinder->FindPath(18, 139);
126       DALI_TEST_NOT_EQUALS(int(waypoints.size()), 0, 0, TEST_LOCATION);
127
128       // Results are verified in the Blender
129       std::vector<uint32_t> expectedResults =
130         {18, 97, 106, 82, 50, 139};
131
132       DALI_TEST_EQUALS(CompareResults(expectedResults, waypoints), true, TEST_LOCATION);
133     }
134     //printWaypointForPython(waypoints);
135
136     {
137       // Top floor middle to the tree
138
139       auto waypoints = pathfinder->FindPath(18, 157);
140       DALI_TEST_NOT_EQUALS(int(waypoints.size()), 0, 0, TEST_LOCATION);
141
142       //printWaypointForPython(waypoints);
143
144       // Results are verified in the Blender
145       std::vector<uint32_t> expectedResults =
146         {18, 97, 106, 82, 50, 6, 89, 33, 157};
147
148       DALI_TEST_EQUALS(CompareResults(expectedResults, waypoints), true, TEST_LOCATION);
149
150     }
151   }
152
153   END_TEST;
154 }
155
156 int UtcDaliPathFinderFindShortestPath1(void)
157 {
158   auto navmesh = NavigationMeshFactory::CreateFromFile( "resources/navmesh-test.bin");
159   // All coordinates in navmesh local space
160   navmesh->SetSceneTransform( Matrix(Matrix::IDENTITY));
161
162   std::vector<PathFinderAlgorithm> testAlgorithms = {
163     PathFinderAlgorithm::DJIKSTRA_SHORTEST_PATH,
164     PathFinderAlgorithm::SPFA,
165     PathFinderAlgorithm::SPFA_DOUBLE_WAY, /* Note : Even this algorithm doesn't found shortest path, UTC will pass. */
166   };
167
168   for(const auto& algorithm : testAlgorithms)
169   {
170     tet_printf("Test algorithm type : %d\n", static_cast<int>(algorithm));
171     auto pathfinder = PathFinder::New( *navmesh, algorithm );
172
173     DALI_TEST_CHECK(navmesh);
174     DALI_TEST_CHECK(pathfinder);
175
176     {
177       Vector3 from(-6.0767, -1.7268, 0.1438); // ground floor
178       Vector3 to(-6.0767, -1.7268, 4.287); // first floor
179
180       auto waypoints = pathfinder->FindPath(from, to);
181       DALI_TEST_NOT_EQUALS(int(waypoints.size()), 0, 0, TEST_LOCATION);
182
183       // Results are verified in the Blender
184       std::vector<uint32_t> expectedResults =
185       {154, 58, 85, 106, 128, 132, 137};
186
187       DALI_TEST_EQUALS(CompareResults(expectedResults, waypoints), true, TEST_LOCATION);
188
189       // Verify last and first points by finding floor points
190       {
191         Vector3  verifyPos = Vector3::ZERO;
192         uint32_t verifyIndex  = NavigationMesh::NULL_FACE;
193         auto     result = navmesh->FindFloor(from, verifyPos, verifyIndex);
194
195         DALI_TEST_EQUALS(result, true, TEST_LOCATION);
196         DALI_TEST_EQUALS(verifyPos, waypoints[0].GetScenePosition(), TEST_LOCATION);
197         DALI_TEST_EQUALS(verifyIndex, waypoints[0].GetNavigationMeshFaceIndex(), TEST_LOCATION);
198
199         // Verified with Blender
200         Vector2 local(1.064201f, -0.273200f);
201         DALI_TEST_EQUALS(local, waypoints[0].GetFaceLocalSpacePosition(), TEST_LOCATION);
202       }
203
204       {
205         Vector3  verifyPos = Vector3::ZERO;
206         uint32_t verifyIndex  = NavigationMesh::NULL_FACE;
207         auto     result = navmesh->FindFloor(to, verifyPos, verifyIndex);
208
209         DALI_TEST_EQUALS(result, true, TEST_LOCATION);
210         DALI_TEST_EQUALS(verifyPos, waypoints.back().GetScenePosition(), TEST_LOCATION);
211         DALI_TEST_EQUALS(verifyIndex, waypoints.back().GetNavigationMeshFaceIndex(), TEST_LOCATION);
212
213         // Verified with Blender
214         Vector2 local(0.165907f, 0.142597f);
215         DALI_TEST_EQUALS(local, waypoints.back().GetFaceLocalSpacePosition(), TEST_LOCATION);
216       }
217     }
218   }
219
220   END_TEST;
221 }