1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2020, Oracle and/or its affiliates.
4
5 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
6
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9
10 #include <geometry_test_common.hpp>
11
12 #include <boost/geometry/algorithms/correct.hpp>
13 #include <boost/geometry/algorithms/equals.hpp>
14 #include <boost/geometry/algorithms/difference.hpp>
15 #include <boost/geometry/geometries/geometries.hpp>
16 #include <boost/geometry/io/wkt/wkt.hpp>
17 #include <boost/geometry/strategies/cartesian/area.hpp>
18 #include <boost/geometry/strategies/cartesian/intersection.hpp>
19 #include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
20 #include <boost/geometry/strategies/cartesian/point_in_point.hpp>
21
22 #include <boost/tuple/tuple.hpp>
23
24 typedef bg::model::point<double, 2, bg::cs::cartesian> Pt;
25 typedef bg::model::linestring<Pt> Ls;
26 typedef bg::model::polygon<Pt> Po;
27 typedef bg::model::ring<Pt> R;
28 typedef bg::model::multi_point<Pt> MPt;
29 typedef bg::model::multi_linestring<Ls> MLs;
30 typedef bg::model::multi_polygon<Po> MPo;
31
32 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
33
34 #include <tuple>
35
36 #endif
37
38 template <typename G>
check(std::string const & wkt1,std::string const & wkt2,G const & g,std::string const & expected)39 inline void check(std::string const& wkt1,
40 std::string const& wkt2,
41 G const& g,
42 std::string const& expected)
43 {
44 G expect;
45 bg::read_wkt(expected, expect);
46 bg::correct(expect);
47 if (! boost::empty(g) || ! boost::empty(expect))
48 {
49 BOOST_CHECK_MESSAGE(
50 // Commented out becasue the output in reversed case may be slightly different
51 // e.g. different number of duplicated points in MultiPoint
52 //boost::size(g) == boost::size(expect) &&
53 bg::equals(g, expect),
54 wkt1 << " \\ " << wkt2 << " -> " << bg::wkt(g)
55 << " different than expected: " << expected
56 );
57 }
58 }
59
60 template <int I>
check(std::string const & wkt1,std::string const & wkt2,boost::tuple<MPt,MLs,MPo> const & tup,std::string const & out_str)61 inline void check(std::string const& wkt1,
62 std::string const& wkt2,
63 boost::tuple<MPt, MLs, MPo> const& tup,
64 std::string const& out_str)
65 {
66 check(wkt1, wkt2, boost::get<I>(tup), out_str);
67 }
68
69 template <int I>
check(std::string const & wkt1,std::string const & wkt2,std::pair<MPt,MLs> const & pair,std::string const & out_str)70 inline void check(std::string const& wkt1,
71 std::string const& wkt2,
72 std::pair<MPt, MLs> const& pair,
73 std::string const& out_str)
74 {
75 if (BOOST_GEOMETRY_CONDITION(I == 0))
76 check(wkt1, wkt2, pair.first, out_str);
77 else
78 check(wkt1, wkt2, pair.second, out_str);
79 }
80
81 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
82
83 template <int I>
check(std::string const & wkt1,std::string const & wkt2,std::tuple<MPt,MLs,MPo> const & tup,std::string const & out_str)84 inline void check(std::string const& wkt1,
85 std::string const& wkt2,
86 std::tuple<MPt, MLs, MPo> const& tup,
87 std::string const& out_str)
88 {
89 check(wkt1, wkt2, std::get<I>(tup), out_str);
90 }
91
92 #endif
93
94 template <typename Geometry>
95 struct out_id
96 : boost::mpl::if_c
97 <
98 boost::is_base_of<bg::pointlike_tag, typename bg::tag<Geometry>::type>::value,
99 boost::mpl::int_<0>,
100 typename boost::mpl::if_c
101 <
102 boost::is_base_of<bg::linear_tag, typename bg::tag<Geometry>::type>::value,
103 boost::mpl::int_<1>,
104 boost::mpl::int_<2>
105 >::type
106 >::type
107 {};
108
109 template <typename In1, typename In2, typename Tup>
test_one(std::string const & in1_str,std::string const & in2_str,std::string const & out1_str,std::string const & out2_str)110 inline void test_one(std::string const& in1_str,
111 std::string const& in2_str,
112 std::string const& out1_str,
113 std::string const& out2_str)
114 {
115 In1 in1;
116 bg::read_wkt(in1_str, in1);
117 bg::correct(in1);
118
119 In2 in2;
120 bg::read_wkt(in2_str, in2);
121 bg::correct(in2);
122
123 {
124 Tup result;
125 bg::difference(in1, in2, result);
126 check<out_id<In1>::value>(in1_str, in2_str, result, out1_str);
127 }
128 {
129 Tup result;
130 bg::difference(in2, in1, result);
131 check<out_id<In2>::value>(in2_str, in1_str, result, out2_str);
132 }
133 }
134
135 template <typename Tup>
test_pp()136 inline void test_pp()
137 {
138 test_one<Pt, Pt, Tup>(
139 "POINT(0 0)",
140 "POINT(0 0)",
141 "MULTIPOINT()",
142 "MULTIPOINT()");
143
144 test_one<Pt, Pt, Tup>(
145 "POINT(0 0)",
146 "POINT(1 1)",
147 "MULTIPOINT(0 0)",
148 "MULTIPOINT(1 1)");
149
150 test_one<Pt, MPt, Tup>(
151 "POINT(0 0)",
152 "MULTIPOINT(0 0, 1 1)",
153 "MULTIPOINT()",
154 "MULTIPOINT(1 1)");
155
156 test_one<Pt, MPt, Tup>(
157 "POINT(2 2)",
158 "MULTIPOINT(0 0, 1 1)",
159 "MULTIPOINT(2 2)",
160 "MULTIPOINT(0 0, 1 1)");
161
162 test_one<MPt, MPt, Tup>(
163 "MULTIPOINT(0 0, 1 1, 2 2)",
164 "MULTIPOINT(1 1, 3 3, 4 4)",
165 "MULTIPOINT(0 0, 2 2)",
166 "MULTIPOINT(3 3, 4 4)");
167 }
168
169 template <typename Tup>
test_pl()170 inline void test_pl()
171 {
172 test_one<Pt, Ls, Tup>(
173 "POINT(0 0)",
174 "LINESTRING(0 0, 1 1)",
175 "MULTIPOINT()",
176 "MULTILINESTRING((0 0, 1 1))");
177
178 test_one<Pt, MLs, Tup>(
179 "POINT(0 1)",
180 "MULTILINESTRING((0 0, 1 1),(1 1, 2 2),(4 4, 5 5))",
181 "MULTIPOINT(0 1)",
182 "MULTILINESTRING((0 0, 1 1),(1 1, 2 2),(4 4, 5 5))");
183
184 test_one<MPt, Ls, Tup>(
185 "MULTIPOINT(0 0, 1 1, 2 2, 3 3)",
186 "LINESTRING(0 0, 1 1)",
187 "MULTIPOINT(2 2, 3 3)",
188 "MULTILINESTRING((0 0, 1 1))");
189
190 test_one<MPt, MLs, Tup>(
191 "MULTIPOINT(0 0, 1 1, 2 2, 3 3)",
192 "MULTILINESTRING((0 0, 1 1),(1 1, 2 2),(4 4, 5 5))",
193 "MULTIPOINT(3 3)",
194 "MULTILINESTRING((0 0, 1 1),(1 1, 2 2),(4 4, 5 5))");
195 }
196
197 template <typename Tup>
test_pa()198 inline void test_pa()
199 {
200 test_one<Pt, R, Tup>(
201 "POINT(0 0)",
202 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
203 "MULTIPOINT()",
204 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)))");
205
206 test_one<Pt, Po, Tup>(
207 "POINT(0 0)",
208 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
209 "MULTIPOINT()",
210 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)))");
211
212 test_one<Pt, Po, Tup>(
213 "POINT(3 3)",
214 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
215 "MULTIPOINT(3 3)",
216 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)))");
217
218 test_one<Pt, MPo, Tup>(
219 "POINT(2 2)",
220 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))",
221 "MULTIPOINT()",
222 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))");
223
224 test_one<Pt, MPo, Tup>(
225 "POINT(3 3)",
226 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))",
227 "MULTIPOINT(3 3)",
228 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))");
229
230 test_one<Pt, MPo, Tup>(
231 "POINT(6 6)",
232 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))",
233 "MULTIPOINT(6 6)",
234 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))");
235
236 test_one<MPt, R, Tup>(
237 "MULTIPOINT(0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6)",
238 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
239 "MULTIPOINT(6 6)",
240 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)))");
241
242 test_one<MPt, Po, Tup>(
243 "MULTIPOINT(0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6)",
244 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
245 "MULTIPOINT(1 1, 2 2, 3 3, 6 6)",
246 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)))");
247
248 test_one<MPt, MPo, Tup>(
249 "MULTIPOINT(0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6)",
250 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))",
251 "MULTIPOINT(3 3, 6 6)",
252 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))");
253 }
254
255 template <typename Tup>
test_ll()256 inline void test_ll()
257 {
258 test_one<Ls, Ls, Tup>(
259 "LINESTRING(0 0, 1 0, 2 1, 3 0)",
260 "LINESTRING(0 0, 1 0, 3 0, 4 0)",
261 "MULTILINESTRING((1 0, 2 1, 3 0))",
262 "MULTILINESTRING((1 0, 3 0, 4 0))");
263
264 test_one<Ls, MLs, Tup>(
265 "LINESTRING(0 0, 1 0, 2 1, 3 0)",
266 "MULTILINESTRING((0 0, 1 0, 3 0),(2 1, 2 2))",
267 "MULTILINESTRING((1 0, 2 1, 3 0))",
268 "MULTILINESTRING((1 0, 3 0),(2 1, 2 2))");
269
270 test_one<MLs, MLs, Tup>(
271 "MULTILINESTRING((0 0, 1 0, 2 1),(2 1, 3 0))",
272 "MULTILINESTRING((0 0, 1 0, 3 0),(2 1, 2 2))",
273 "MULTILINESTRING((1 0, 2 1),(2 1, 3 0))",
274 "MULTILINESTRING((1 0, 3 0),(2 1, 2 2))");
275
276 test_one<Ls, Ls, Tup>(
277 "LINESTRING(0 0, 0 5, 5 5, 5 0, 0 0)",
278 "LINESTRING(0 0, 0 1, 6 1, 5 2, 5 5, 5 6, 4 5, 4 7, 7 7, 7 0, 0 0)",
279 "MULTILINESTRING((0 1, 0 5, 5 5),(5 2, 5 0))",
280 "MULTILINESTRING((0 1, 6 1, 5 2),(5 5, 5 6, 4 5, 4 7, 7 7, 7 0, 5 0))");
281
282 test_one<MLs, MLs, Tup>(
283 "MULTILINESTRING((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
284 "MULTILINESTRING((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0))",
285 "MULTILINESTRING((0 0, 0 5, 5 5, 5 4),(5 1, 5 0, 0 0),(4 4, 4 1))",
286 "MULTILINESTRING((4 4, 5 4),(5 1, 4 1),(0 0, 2 1, 2 2, 1 2, 0 0))");
287 }
288
289 template <typename Tup>
test_la()290 inline void test_la()
291 {
292 test_one<Ls, R, Tup>(
293 "LINESTRING(0 2, -4 1, 0 0, 5 0, 9 1, 5 2, 9 3, 5 5, 4 9, 4 5, 3 3, 2 5, 2 9, 0 5)",
294 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
295 "MULTILINESTRING((0 2, -4 1, 0 0),(5 0, 9 1, 5 2, 9 3, 5 5, 4 9, 4 5),(2 5, 2 9, 0 5))",
296 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)))");
297
298 test_one<Ls, Po, Tup>(
299 "LINESTRING(1 4, -4 1, 0 0, 5 0, 9 1, 5 2, 9 3, 5 5, 4 9, 4 5, 3 3, 2 5, 2 9, 0 5)",
300 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
301 "MULTILINESTRING((0 3.4, -4 1, 0 0),(5 0, 9 1, 5 2, 9 3, 5 5, 4 9, 4 5),(3.5 4, 3 3, 2.5 4),(2 5, 2 9, 0 5))",
302 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)))");
303
304 test_one<MLs, R, Tup>(
305 "MULTILINESTRING((0 2, -4 1, 0 0, 5 0, 9 1, 5 2, 9 3, 5 5, 4 9), (4 9, 4 5, 3 3, 2 5, 2 9, 0 5))",
306 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
307 "MULTILINESTRING((0 2, -4 1, 0 0),(5 0, 9 1, 5 2, 9 3, 5 5, 4 9),(4 9, 4 5),(2 5, 2 9, 0 5))",
308 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)))");
309
310 test_one<MLs, Po, Tup>(
311 "MULTILINESTRING((1 4, -4 1, 0 0, 5 0, 9 1, 5 2, 9 3, 5 5, 4 9), (4 9, 4 5, 3 3, 2 5, 2 9, 0 5))",
312 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
313 "MULTILINESTRING((0 3.4, -4 1, 0 0),(5 0, 9 1, 5 2, 9 3, 5 5, 4 9),(4 9, 4 5),(3.5 4, 3 3, 2.5 4),(2 5, 2 9, 0 5))",
314 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)))");
315
316 test_one<MLs, MPo, Tup>(
317 "MULTILINESTRING((1 4, -4 1, 0 0, 5 0, 9 1, 5 2, 9 3, 5 5, 4 9), (4 9, 4 5, 4 4, 2 2, 2 5, 1 9, 0 5))",
318 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))",
319 "MULTILINESTRING((0 3.4, -4 1, 0 0),(5 0, 9 1, 5 2, 9 3, 5 5, 4 9),(4 9, 4 5),(4 4, 2 2, 2 4),(2 5, 1 9, 0 5))",
320 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),((0 0, 1 2, 2 2, 2 1, 0 0)))");
321
322 test_one<Ls, R, Tup>(
323 "LINESTRING(0 0, 0 5, 5 5, 5 0, 0 0)",
324 "POLYGON((0 0, 0 1, 6 1, 5 2, 5 5, 5 6, 4 5, 4 7, 7 7, 7 0, 0 0))",
325 "MULTILINESTRING((0 1, 0 5, 5 5),(5 2, 5 1))",
326 "MULTIPOLYGON(((0 0, 0 1, 6 1, 5 2, 5 5, 5 6, 4 5, 4 7, 7 7, 7 0, 0 0)))");
327
328 test_one<MLs, Po, Tup>(
329 "MULTILINESTRING((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
330 "POLYGON((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0))",
331 "MULTILINESTRING((0 0, 0 5, 5 5, 5 4),(5 1, 5 0, 0 0))",
332 "MULTIPOLYGON(((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0)))");
333 }
334
335 template <typename Tup>
test_aa()336 inline void test_aa()
337 {
338 test_one<R, R, Tup>(
339 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
340 "POLYGON((0 0, 0 1, 6 1, 5 2, 5 5, 5 6, 4 5, 4 7, 7 7, 7 0, 0 0))",
341 "MULTIPOLYGON(((0 1,0 5,5 5,5 1,0 1)))",
342 "MULTIPOLYGON(((5 1,6 1,5 2,5 5,5 6,4 5,4 7,7 7,7 0,5 0,5 1)))");
343
344 test_one<R, MPo, Tup>(
345 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))",
346 "MULTIPOLYGON(((0 0, 0 1, 6 1, 6 0, 0 0)),"
347 "((6 1, 5 2, 5 5, 5 6, 4 5, 4 7, 7 7, 7 1, 6 1)))",
348 "MULTIPOLYGON(((0 1,0 5,5 5,5 1,0 1)))",
349 "MULTIPOLYGON(((5 1,6 1,6 0,5 0,5 1)),((5 2,5 5,5 6,4 5,4 7,7 7,7 1,6 1,5 2)))");
350
351 test_one<Po, Po, Tup>(
352 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
353 "POLYGON((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0))",
354 "MULTIPOLYGON(((5 1,5 0,0 0,4 1,5 1)),((5 4,1 4,0 0,0 5,5 5,5 4)))",
355 "MULTIPOLYGON(((1 4,4 4,4 1,0 0,1 4),(0 0,2 1,2 2,1 2,0 0)))");
356
357 test_one<Po, MPo, Tup>(
358 "POLYGON((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))",
359 "MULTIPOLYGON(((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0)),"
360 "((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0 5 0)))",
361 "MULTIPOLYGON(((4 5,5 4,1 4,0 0,0 5,4 5)),((5 1,5 0,0 0,4 1,5 1)))",
362 "MULTIPOLYGON(((5 0,5 1,6 1,6 4,5 4,5 5,4 5,3 6,2 5,2 7,7 7,7 0,5 0)),"
363 "((1 4,4 4,4 1,0 0,1 4),(0 0,2 1,2 2,1 2,0 0)))");
364
365 test_one<MPo, MPo, Tup>(
366 "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),"
367 "((2 6, 2 8, 8 8, 8 5, 7 5, 7 6, 2 6)))",
368 "MULTIPOLYGON(((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0)),"
369 "((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0 5 0)))",
370 "MULTIPOLYGON(((4 5,5 4,1 4,0 0,0 5,4 5)),"
371 "((5 1,5 0,0 0,4 1,5 1)),"
372 "((2 7,2 8,8 8,8 5,7 5,7 6,7 7,2 7)))",
373 "MULTIPOLYGON(((1 4,4 4,4 1,0 0,1 4),(0 0,2 1,2 2,1 2,0 0)),"
374 "((5 1,6 1,6 4,5 4,5 5,4 5,3 6,7 6,7 5,7 0,5 0,5 1)),"
375 "((3 6,2 5,2 6,3 6)))");
376 }
377
378 template <typename Tup>
test_pair()379 inline void test_pair()
380 {
381 test_pp<Tup>();
382 test_pl<Tup>();
383 test_ll<Tup>();
384 }
385
386 template <typename Tup>
test_tuple()387 inline void test_tuple()
388 {
389 test_pp<Tup>();
390 test_pl<Tup>();
391 test_pa<Tup>();
392 test_ll<Tup>();
393 test_la<Tup>();
394 test_aa<Tup>();
395 }
396
test_main(int,char * [])397 int test_main(int, char* [])
398 {
399 test_pair<std::pair<MPt, MLs> >();
400 test_tuple<boost::tuple<MPt, MLs, MPo> >();
401
402 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
403 test_tuple<std::tuple<MPt, MLs, MPo> >();
404 #endif
405
406 return 0;
407 }
408