blob: 763ebbd1fca1e708646458364b62a7b53900d3b5 [file] [log] [blame]
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Tool reporting Implementation Status in QBK format
// Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2011-2014 Bruno Lalande, Paris, France.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <boost/timer.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>
static const int point = 0;
static const int segment = 1;
static const int box = 2;
static const int linestring = 3;
static const int ring = 4;
static const int polygon = 5;
static const int multi_point = 6;
static const int multi_linestring = 7;
static const int multi_polygon = 8;
static const int variant = 9;
static const int geometry_count = 10;
struct compile_bjam
{
static inline bool apply(std::string const& id)
{
std::ostringstream command;
// For debugging:
command << "b2 -a tmp > tmp/t_" << id << ".out";
//command << "b2 -a tmp > tmp/t.out";
int failed = system(command.str().c_str());
{
// For debugging: save t.cpp
std::ostringstream c2;
c2 << "cp tmp/t.cpp tmp/t_" << id << ".cpp";
system(c2.str().c_str());
}
return failed == 0;
}
};
struct compile_clang
{
bool first;
compile_clang()
: first(true)
{}
inline bool apply(std::string const& id)
{
if (first)
{
// Generate the pre-compiled header
system("clang -x c++-header -I . -I ../../../../../../.. implementation_status.hpp");
first = false;
}
std::ostringstream command;
// We compile only, not even link
command << "clang -include implementation_status.hpp -I . -I ../../../../../../.. -c tmp/t.cpp > tmp/t_" << id << ".out 2>&1";
int failed = system(command.str().c_str());
{
// For debugging: save t.cpp
std::ostringstream c2;
c2 << "cp tmp/t.cpp tmp/t_" << id << ".cpp";
system(c2.str().c_str());
}
return failed == 0;
}
};
struct compile_msvc
{
bool first;
int count;
compile_msvc()
: first(true)
, count(0)
{}
inline bool apply(std::string const& id)
{
std::ostringstream command;
command << "cl /nologo -I. -I/_svn/boost/trunk /EHsc /Y";
if (first)
{
std::cout << " (creating PCH)";
command << "c";
first = false;
}
else
{
command << "u";
}
command << "implementation_status.hpp tmp/t.cpp > tmp/t" //.out";
// For debugging:
<< id << ".out";
int failed = system(command.str().c_str());
return failed == 0;
}
};
struct algorithm
{
std::string name;
int arity;
explicit algorithm(std::string const& n, int a = 1)
: name(n)
, arity(a)
{}
};
inline std::string bool_string(bool v)
{
return v ? "true" : "false";
}
inline std::string typedef_string(int type, bool clockwise, bool open)
{
std::ostringstream out;
switch(type)
{
case point : return "P";
case linestring : return "bg::model::linestring<P>";
case box : return "bg::model::box<P>";
case segment : return "bg::model::segment<P>";
case ring :
out << "bg::model::ring<P, "
<< bool_string(clockwise) << ", " << bool_string(open) << ">";
break;
case variant :
case polygon :
out << "bg::model::polygon<P, "
<< bool_string(clockwise) << ", " << bool_string(open) << ">";
break;
case multi_point : return "bg::model::multi_point<P>";
case multi_linestring :
out << "bg::model::multi_linestring<bg::model::linestring<P> >";
break;
case multi_polygon :
out << "bg::model::multi_polygon<bg::model::polygon<P, "
<< bool_string(clockwise) << ", " << bool_string(open) << "> >";
break;
}
return out.str();
}
inline std::string wkt_string(int type)
{
switch(type)
{
case point : return "POINT(1 1)";
case linestring : return "LINESTRING(1 1,2 2)";
case segment : return "LINESTRING(1 1,2 2)";
case box : return "POLYGON((1 1,2 2))";
case polygon :
case variant :
case ring :
return "POLYGON((0 0,0 1,1 1,0 0))";
case multi_point : return "MULTIPOINT((1 1),(2 2))";
case multi_linestring : return "MULTILINESTRING((1 1,2 2))";
case multi_polygon : return "MULTIPOLYGON(((0 0,0 1,1 1,0 0)))";
}
return "";
}
inline std::string geometry_string(int type)
{
switch(type)
{
case point : return "Point";
case linestring : return "Linestring";
case box : return "Box";
case polygon : return "Polygon";
case ring : return "Ring";
case segment : return "Segment";
case multi_point : return "MultiPoint";
case multi_linestring : return "MultiLinestring";
case multi_polygon : return "MultiPolygon";
case variant : return "Variant";
}
return "";
}
template <typename CompilePolicy>
int report_library(CompilePolicy& compile_policy,
int type, algorithm const& algo, bool clockwise,
bool open, int dimensions, std::string const& cs,
int type2 = -1)
{
std::string lit;
{
std::ostringstream out;
out << geometry_string(type);
if (type2 != -1)
{
out << "_" << geometry_string(type2);
}
out
<< "_" << algo.name
<< "_" << bool_string(clockwise)
<< "_" << bool_string(open)
<< "_" << boost::replace_all_copy
(
boost::replace_all_copy
(
boost::replace_all_copy(cs, "bg::", "")
, "<", "_"
)
, ">", "_"
);
lit = out.str();
}
std::cout << lit;
{
std::ofstream out("tmp/t.cpp");
std::string name = "geometry";
if (type == variant)
{
name = "source";
}
out << "#include <implementation_status.hpp>" << std::endl;
if (type == variant)
{
out << "#include <boost/variant/variant.hpp>" << std::endl;
}
out
<< "template <typename P>" << std::endl
<< "inline void test()" << std::endl
<< "{" << std::endl
<< " namespace bg = boost::geometry;" << std::endl
<< " " << typedef_string(type, clockwise, open) << " " << name << ";" << std::endl
<< " bg::read_wkt(\"" << wkt_string(type) << "\", " << name << ");" << std::endl;
if (type == variant)
{
out
<< " typedef " << typedef_string(polygon, clockwise, open) << " type1;" << std::endl
<< " typedef " << typedef_string(box, clockwise, open) << " type2;" << std::endl
<< " boost::variant<type1, type2> geometry;" << std::endl
<< " geometry = source;"
<< std::endl;
}
if (algo.arity > 1)
{
out
<< " " << typedef_string(type2, clockwise, open) << " geometry2;" << std::endl
<< " bg::read_wkt(\"" << wkt_string(type2) << "\", geometry2);" << std::endl;
}
if (algo.name == std::string("centroid"))
{
out << " P point;";
out << " bg::" << algo.name << "(geometry, point);" << std::endl;
}
else if (algo.name == std::string("envelope"))
{
out << " bg::model::box<P> box;";
out << " bg::" << algo.name << "(geometry, box);" << std::endl;
}
else
{
switch(algo.arity)
{
case 1 :
out << " bg::" << algo.name << "(geometry);" << std::endl;
break;
case 2 :
// For cases as point-in-polygon, take first geometry 2 (point), then geometry (polygon) such that
// it is listed as column:point in row:polygon
out << " bg::" << algo.name << "(geometry2, geometry);" << std::endl;
break;
}
}
out
<< "}" << std::endl
<< std::endl
;
out
<< "int main()" << std::endl
<< "{" << std::endl
<< " namespace bg = boost::geometry;" << std::endl
<< " test<bg::model::point< double, " << dimensions << ", bg::cs::" << cs << " > >();" << std::endl
<< " return 0;" << std::endl
<< "}" << std::endl
<< std::endl
;
}
bool result = compile_policy.apply(lit);
if (! result)
{
std::cout << " ERROR";
}
std::cout << std::endl;
return result;
}
template <typename CompilePolicy>
std::vector<int> report(CompilePolicy& compile_policy,
int type, algorithm const& algo, bool clockwise,
bool open, int dimensions, std::string const& cs)
{
std::vector<int> result;
switch(algo.arity)
{
case 1 :
result.push_back(report_library(compile_policy, type, algo, clockwise, open, dimensions, cs));
break;
case 2 :
for (int type2 = point; type2 < geometry_count; ++type2)
{
result.push_back(report_library(compile_policy, type, algo, clockwise, open, dimensions, cs, type2));
}
break;
}
return result;
}
struct cs
{
std::string name;
cs(std::string const& n)
: name(n)
{}
};
int main(int , char** )
{
#if defined(_MSC_VER)
compile_msvc compile_policy;
#else
//compile_bjam compile_policy;
compile_clang compile_policy;
#endif
typedef std::vector<algorithm> v_a_type;
v_a_type algorithms;
algorithms.push_back(algorithm("area"));
algorithms.push_back(algorithm("clear"));
algorithms.push_back(algorithm("correct"));
algorithms.push_back(algorithm("centroid")); // NOTE: current doc contains 2D / 3D
algorithms.push_back(algorithm("envelope"));
algorithms.push_back(algorithm("length"));
algorithms.push_back(algorithm("is_simple"));
algorithms.push_back(algorithm("is_valid"));
algorithms.push_back(algorithm("num_points"));
algorithms.push_back(algorithm("perimeter"));
algorithms.push_back(algorithm("covered_by", 2));
algorithms.push_back(algorithm("distance", 2));
algorithms.push_back(algorithm("crosses", 2));
algorithms.push_back(algorithm("disjoint", 2));
algorithms.push_back(algorithm("equals", 2));
algorithms.push_back(algorithm("intersects", 2));
algorithms.push_back(algorithm("overlaps", 2));
algorithms.push_back(algorithm("within", 2));
typedef std::vector<cs> cs_type;
cs_type css;
css.push_back(cs("cartesian"));
// css.push_back(cs("spherical<bg::degree>"));
// css.push_back(cs("spherical<bg::radian>"));
boost::timer timer;
for (v_a_type::const_iterator it = algorithms.begin(); it != algorithms.end(); ++it)
{
/*([heading Behavior]
[table
[[Case] [Behavior] ]
[[__2dim__][All combinations of: box, ring, polygon, multi_polygon]]
[[__other__][__nyiversion__]]
[[__sph__][__nyiversion__]]
[[Three dimensional][__nyiversion__]]
]*/
std::ostringstream name;
name << "../../../../reference/status/" << it->name << "_status.qbk";
std::ofstream out(name.str().c_str());
out << "[heading Supported geometries]" << std::endl;
cs_type::const_iterator cit = css.begin();
{
// Construct the table
std::vector<std::vector<int> > table;
for (int type = point; type < geometry_count; type++)
{
table.push_back(report(compile_policy, type, *it, true, true, 2, cit->name));
}
#if SURPRESS
// Detect red rows/columns
std::vector<int> lines_status(table.size(), false);
std::vector<int> columns_status(table[0].size(), false);
for (unsigned int i = 0; i != table.size(); ++i)
{
for (unsigned int j = 0; j != table[i].size(); ++j)
{
lines_status[i] |= table[i][j];
columns_status[j] |= table[i][j];
}
}
#endif
// Display the table
out << "[table" << std::endl << "[";
if (it->arity > 1)
{
out << "[ ]";
for (int type = point; type < geometry_count; type++)
{
#if SURPRESS
if (!columns_status[type]) continue;
#endif
out << "[" << geometry_string(type) << "]";
}
}
else
{
out << "[Geometry][Status]";
}
out << "]" << std::endl;
for (unsigned int i = 0; i != table.size(); ++i)
{
#if SURPRESS
if (!lines_status[i]) continue;
#endif
out << "[";
out << "[" << geometry_string(i) << "]";
for (unsigned int j = 0; j != table[i].size(); ++j)
{
#if SURPRESS
if (!columns_status[j]) continue;
#endif
out << "[ [$img/" << (table[i][j] ? "ok" : "nyi") << ".png] ]";
}
out << "]" << std::endl;
}
out << "]" << std::endl;
}
}
std::cout << "TIME: " << timer.elapsed() << std::endl;
return 0;
}