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