1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Tool reporting Implementation Status in QBK format
3 
4 // Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands.
5 // Copyright (c) 2011-2014 Bruno Lalande, Paris, France.
6 
7 // Use, modification and distribution is subject to the Boost Software License,
8 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #include <iostream>
12 #include <fstream>
13 #include <sstream>
14 #include <string>
15 #include <vector>
16 
17 #include <stdlib.h>
18 
19 #include <boost/timer.hpp>
20 #include <boost/algorithm/string/predicate.hpp>
21 #include <boost/algorithm/string/replace.hpp>
22 #include <boost/algorithm/string/trim.hpp>
23 
24 static const int point = 0;
25 static const int segment = 1;
26 static const int box = 2;
27 static const int linestring = 3;
28 static const int ring = 4;
29 static const int polygon = 5;
30 static const int multi_point = 6;
31 static const int multi_linestring = 7;
32 static const int multi_polygon = 8;
33 static const int variant = 9;
34 static const int geometry_count = 10;
35 
36 struct compile_bjam
37 {
applycompile_bjam38     static inline bool apply(std::string const& id)
39     {
40         std::ostringstream command;
41         // For debugging:
42         command << "b2 -a tmp > tmp/t_" << id << ".out";
43         //command << "b2 -a tmp > tmp/t.out";
44         int failed = system(command.str().c_str());
45 
46         {
47             // For debugging: save t.cpp
48             std::ostringstream c2;
49             c2 << "cp tmp/t.cpp tmp/t_" << id << ".cpp";
50             system(c2.str().c_str());
51         }
52         return failed == 0;
53     }
54 };
55 
56 
57 struct compile_clang
58 {
59     bool first;
60 
compile_clangcompile_clang61     compile_clang()
62         : first(true)
63     {}
64 
applycompile_clang65     inline bool apply(std::string const& id)
66     {
67         if (first)
68         {
69            // Generate the pre-compiled header
70            system("clang -x c++-header -I . -I ../../../../../../.. implementation_status.hpp");
71            first = false;
72         }
73 
74         std::ostringstream command;
75         // We compile only, not even link
76         command << "clang -include implementation_status.hpp -I . -I ../../../../../../.. -c tmp/t.cpp > tmp/t_" << id << ".out 2>&1";
77         int failed = system(command.str().c_str());
78 
79         {
80             // For debugging: save t.cpp
81             std::ostringstream c2;
82             c2 << "cp tmp/t.cpp tmp/t_" << id << ".cpp";
83             system(c2.str().c_str());
84         }
85         return failed == 0;
86     }
87 };
88 
89 struct compile_msvc
90 {
91     bool first;
92     int count;
93 
compile_msvccompile_msvc94     compile_msvc()
95         : first(true)
96         , count(0)
97     {}
98 
applycompile_msvc99     inline bool apply(std::string const& id)
100     {
101         std::ostringstream command;
102         command << "cl /nologo -I. -I/_svn/boost/trunk /EHsc /Y";
103         if (first)
104         {
105             std::cout << " (creating PCH)";
106             command << "c";
107             first = false;
108         }
109         else
110         {
111             command <<  "u";
112         }
113 
114         command << "implementation_status.hpp tmp/t.cpp > tmp/t" //.out";
115             // For debugging:
116             << id << ".out";
117 
118         int failed = system(command.str().c_str());
119         return failed == 0;
120     }
121 };
122 
123 struct algorithm
124 {
125     std::string name;
126     int arity;
127 
algorithmalgorithm128     explicit algorithm(std::string const& n, int a = 1)
129         : name(n)
130         , arity(a)
131     {}
132 };
133 
134 
bool_string(bool v)135 inline std::string bool_string(bool v)
136 {
137     return v ? "true" : "false";
138 }
139 
typedef_string(int type,bool clockwise,bool open)140 inline std::string typedef_string(int type, bool clockwise, bool open)
141 {
142     std::ostringstream out;
143     switch(type)
144     {
145         case point : return "P";
146         case linestring : return "bg::model::linestring<P>";
147         case box : return "bg::model::box<P>";
148         case segment : return "bg::model::segment<P>";
149         case ring :
150             out << "bg::model::ring<P, "
151                 << bool_string(clockwise) << ", " << bool_string(open) << ">";
152             break;
153         case variant :
154         case polygon :
155             out << "bg::model::polygon<P, "
156                 << bool_string(clockwise) << ", " << bool_string(open) << ">";
157             break;
158         case multi_point : return "bg::model::multi_point<P>";
159         case multi_linestring :
160             out << "bg::model::multi_linestring<bg::model::linestring<P> >";
161             break;
162         case multi_polygon :
163             out << "bg::model::multi_polygon<bg::model::polygon<P, "
164                 << bool_string(clockwise) << ", " << bool_string(open) << "> >";
165             break;
166     }
167     return out.str();
168 }
169 
wkt_string(int type)170 inline std::string wkt_string(int type)
171 {
172     switch(type)
173     {
174         case point : return "POINT(1 1)";
175         case linestring : return "LINESTRING(1 1,2 2)";
176         case segment : return "LINESTRING(1 1,2 2)";
177         case box : return "POLYGON((1 1,2 2))";
178         case polygon :
179         case variant :
180         case ring :
181             return "POLYGON((0 0,0 1,1 1,0 0))";
182         case multi_point : return "MULTIPOINT((1 1),(2 2))";
183         case multi_linestring : return "MULTILINESTRING((1 1,2 2))";
184         case multi_polygon : return "MULTIPOLYGON(((0 0,0 1,1 1,0 0)))";
185     }
186     return "";
187 }
188 
geometry_string(int type)189 inline std::string geometry_string(int type)
190 {
191     switch(type)
192     {
193         case point : return "Point";
194         case linestring : return "Linestring";
195         case box : return "Box";
196         case polygon : return "Polygon";
197         case ring : return "Ring";
198         case segment : return "Segment";
199         case multi_point : return "MultiPoint";
200         case multi_linestring : return "MultiLinestring";
201         case multi_polygon : return "MultiPolygon";
202         case variant : return "Variant";
203     }
204     return "";
205 }
206 
207 template <typename CompilePolicy>
report_library(CompilePolicy & compile_policy,int type,algorithm const & algo,bool clockwise,bool open,int dimensions,std::string const & cs,int type2=-1)208 int report_library(CompilePolicy& compile_policy,
209                    int type, algorithm const& algo, bool clockwise,
210                    bool open, int dimensions, std::string const& cs,
211                    int type2 = -1)
212 {
213     std::string lit;
214     {
215         std::ostringstream out;
216         out << geometry_string(type);
217         if (type2 != -1)
218         {
219             out << "_" << geometry_string(type2);
220         }
221         out
222             << "_" << algo.name
223             << "_" << bool_string(clockwise)
224             << "_" << bool_string(open)
225             << "_" << boost::replace_all_copy
226                         (
227                             boost::replace_all_copy
228                                 (
229                                     boost::replace_all_copy(cs, "bg::", "")
230                                 , "<", "_"
231                                 )
232                             , ">", "_"
233                         );
234         lit = out.str();
235     }
236 
237     std::cout << lit;
238 
239     {
240         std::ofstream out("tmp/t.cpp");
241 
242         std::string name = "geometry";
243 
244         if (type == variant)
245         {
246             name = "source";
247         }
248 
249         out << "#include <implementation_status.hpp>" << std::endl;
250 
251         if (type == variant)
252         {
253             out << "#include <boost/variant/variant.hpp>" << std::endl;
254         }
255 
256         out
257             << "template <typename P>" << std::endl
258             << "inline void test()" << std::endl
259             << "{" << std::endl
260             << "  namespace bg = boost::geometry;" << std::endl
261             << "  " << typedef_string(type, clockwise, open) << " " << name << ";" << std::endl
262             << "  bg::read_wkt(\"" << wkt_string(type) << "\", " << name << ");" << std::endl;
263 
264         if (type == variant)
265         {
266             out
267                 << "  typedef " << typedef_string(polygon, clockwise, open) << " type1;" << std::endl
268                 << "  typedef " << typedef_string(box, clockwise, open) << " type2;" << std::endl
269                 << "  boost::variant<type1, type2> geometry;" << std::endl
270                 << "  geometry = source;"
271                 << std::endl;
272         }
273 
274         if (algo.arity > 1)
275         {
276             out
277                 << "  " << typedef_string(type2, clockwise, open) << " geometry2;" << std::endl
278                 << "  bg::read_wkt(\"" << wkt_string(type2) << "\", geometry2);" << std::endl;
279         }
280 
281         if (algo.name == std::string("centroid"))
282         {
283             out << "  P point;";
284             out << "  bg::" << algo.name << "(geometry, point);" << std::endl;
285         }
286         else if (algo.name == std::string("envelope"))
287         {
288             out << "  bg::model::box<P> box;";
289             out << "  bg::" << algo.name << "(geometry, box);" << std::endl;
290         }
291         else
292         {
293             switch(algo.arity)
294             {
295                 case 1 :
296                     out << "  bg::" << algo.name << "(geometry);" << std::endl;
297                     break;
298                 case 2 :
299                     // For cases as point-in-polygon, take first geometry 2 (point), then geometry (polygon) such that
300                     // it is listed as column:point in row:polygon
301                     out << "  bg::" << algo.name << "(geometry2, geometry);" << std::endl;
302                     break;
303             }
304         }
305 
306         out
307             << "}" << std::endl
308             << std::endl
309             ;
310 
311         out
312             << "int main()" << std::endl
313             << "{" << std::endl
314             << "  namespace bg = boost::geometry;" << std::endl
315             << "  test<bg::model::point< double, " << dimensions << ", bg::cs::" << cs << " > >();" << std::endl
316             << "  return 0;" << std::endl
317             << "}" << std::endl
318             << std::endl
319             ;
320     }
321 
322     bool result = compile_policy.apply(lit);
323     if (! result)
324     {
325         std::cout << " ERROR";
326     }
327     std::cout << std::endl;
328     return result;
329 }
330 
331 
332 template <typename CompilePolicy>
report(CompilePolicy & compile_policy,int type,algorithm const & algo,bool clockwise,bool open,int dimensions,std::string const & cs)333 std::vector<int> report(CompilePolicy& compile_policy,
334                         int type, algorithm const& algo, bool clockwise,
335                         bool open, int dimensions, std::string const& cs)
336 {
337     std::vector<int> result;
338 
339     switch(algo.arity)
340     {
341         case 1 :
342             result.push_back(report_library(compile_policy, type, algo, clockwise, open, dimensions, cs));
343             break;
344         case 2 :
345             for (int type2 = point; type2 < geometry_count; ++type2)
346             {
347                 result.push_back(report_library(compile_policy, type, algo, clockwise, open, dimensions, cs, type2));
348             }
349             break;
350     }
351 
352     return result;
353 }
354 
355 
356 struct cs
357 {
358     std::string name;
359 
cscs360     cs(std::string const& n)
361         : name(n)
362     {}
363 };
364 
365 
main(int,char **)366 int main(int , char** )
367 {
368 #if defined(_MSC_VER)
369     compile_msvc compile_policy;
370 #else
371     //compile_bjam compile_policy;
372     compile_clang compile_policy;
373 #endif
374 
375     typedef std::vector<algorithm> v_a_type;
376     v_a_type algorithms;
377     algorithms.push_back(algorithm("area"));
378     algorithms.push_back(algorithm("clear"));
379     algorithms.push_back(algorithm("correct"));
380     algorithms.push_back(algorithm("centroid")); // NOTE: current doc contains 2D / 3D
381     algorithms.push_back(algorithm("envelope"));
382     algorithms.push_back(algorithm("length"));
383     algorithms.push_back(algorithm("is_simple"));
384     algorithms.push_back(algorithm("is_valid"));
385     algorithms.push_back(algorithm("num_points"));
386     algorithms.push_back(algorithm("perimeter"));
387 
388     algorithms.push_back(algorithm("covered_by", 2));
389     algorithms.push_back(algorithm("distance", 2));
390     algorithms.push_back(algorithm("crosses", 2));
391     algorithms.push_back(algorithm("disjoint", 2));
392     algorithms.push_back(algorithm("equals", 2));
393     algorithms.push_back(algorithm("intersects", 2));
394     algorithms.push_back(algorithm("overlaps", 2));
395     algorithms.push_back(algorithm("within", 2));
396 
397     typedef std::vector<cs> cs_type;
398     cs_type css;
399     css.push_back(cs("cartesian"));
400     // css.push_back(cs("spherical<bg::degree>"));
401     // css.push_back(cs("spherical<bg::radian>"));
402 
403 
404     boost::timer timer;
405 
406     for (v_a_type::const_iterator it = algorithms.begin(); it != algorithms.end(); ++it)
407     {
408 /*([heading Behavior]
409 [table
410 [[Case] [Behavior] ]
411 [[__2dim__][All combinations of: box, ring, polygon, multi_polygon]]
412 [[__other__][__nyiversion__]]
413 [[__sph__][__nyiversion__]]
414 [[Three dimensional][__nyiversion__]]
415 ]*/
416 
417         std::ostringstream name;
418         name << "../../../../reference/status/" << it->name << "_status.qbk";
419 
420         std::ofstream out(name.str().c_str());
421         out << "[heading Supported geometries]" << std::endl;
422 
423         cs_type::const_iterator cit = css.begin();
424 
425         {
426             // Construct the table
427 
428             std::vector<std::vector<int> > table;
429 
430             for (int type = point; type < geometry_count; type++)
431             {
432                 table.push_back(report(compile_policy, type, *it, true, true, 2, cit->name));
433             }
434 
435 
436 #if SURPRESS
437             // Detect red rows/columns
438 
439             std::vector<int> lines_status(table.size(), false);
440             std::vector<int> columns_status(table[0].size(), false);
441 
442             for (unsigned int i = 0; i != table.size(); ++i)
443             {
444                 for (unsigned int j = 0; j != table[i].size(); ++j)
445                 {
446                     lines_status[i] |= table[i][j];
447                     columns_status[j] |= table[i][j];
448                 }
449             }
450 #endif
451 
452 
453             // Display the table
454 
455             out << "[table" << std::endl << "[";
456 
457             if (it->arity > 1)
458             {
459                 out << "[ ]";
460                 for (int type = point; type < geometry_count; type++)
461                 {
462 #if SURPRESS
463                     if (!columns_status[type]) continue;
464 #endif
465                     out << "[" << geometry_string(type) << "]";
466                 }
467             }
468             else
469             {
470                 out << "[Geometry][Status]";
471             }
472 
473             out << "]" << std::endl;
474 
475             for (unsigned int i = 0; i != table.size(); ++i)
476             {
477 #if SURPRESS
478                 if (!lines_status[i]) continue;
479 #endif
480                 out << "[";
481                 out << "[" << geometry_string(i) << "]";
482                 for (unsigned int j = 0; j != table[i].size(); ++j)
483                 {
484 #if SURPRESS
485                     if (!columns_status[j]) continue;
486 #endif
487                     out << "[ [$img/" << (table[i][j] ? "ok" : "nyi") << ".png] ]";
488                 }
489                 out << "]" << std::endl;
490             }
491 
492             out << "]" << std::endl;
493         }
494     }
495 
496     std::cout << "TIME: " << timer.elapsed() << std::endl;
497 
498     return 0;
499 }
500