• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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