dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/gnuplot_output_2.h

242 lines
7.6 KiB
C++

// Copyright (c) 2013-2015 The University of Western Sydney, Australia.
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Cone_spanners_2/include/CGAL/gnuplot_output_2.h $
// $Id: gnuplot_output_2.h 254d60f 2019-10-19T15:23:19+02:00 Sébastien Loriot
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s): Quincy Tse, Weisheng Si
/*! \file gnuplot_output_2.h
*
* This header implements the function that can generate data and script files for plotting
* graphs by Gnuplot. This function requires that graphs be represented by boost::adjacency_list
* with its template parameter VertexProperties set to CGAL::Point_2.
*/
#ifndef GNUPLOT_OUTPUT_2_H
#define GNUPLOT_OUTPUT_2_H
#include <CGAL/license/Cone_spanners_2.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
namespace CGAL {
/* ------ Declarations go first, then implementations follow. ------ */
/*!
* \ingroup PkgConeSpanners2Ref
* \brief Output a set of files used by Gnuplot to plot `g`.
*
* The files that are generated for Gnuplot are:
* (1) prefix.v (vertex list)
* (2) prefix.plt (Gnuplot script), This script will read
* prefix.v as input to plot the vertex list. The edge list is also
* included in this script.
*
* Notes:
* (1) If these files already exists, this function will overwrite these
* files.
* (2) Parallel and self-edges cannot be plotted.
*
* \tparam Graph The type of the graph to be plotted. For this function to work,
* the graph type must be `boost::adjacency_list` with `CGAL::Point_2`
* as the `VertexProperties`.
*
* \param g A `boost::adjacency_list` graph with `CGAL::Point_2` as the VertexProperties to be plotted
* \param prefix The prefix of the output files names
*/
template <typename Graph>
void gnuplot_output_2 (const Graph& g, const std::string& prefix);
/*
* \brief Compiles a multi-lined %string to draw the edges in \p g by Gnuplot.
* Compiles an edge list in the following format:
*
* set arrow from (start x, start y) to (end x, end y)
* ...
*
* NOTE: For undirected graphs, use "set style arrow nohead"; for directed graphs,
* use "set style arrow head"
*
* \param g A boost::adjacency_list graph with CGAL::Point_2 as the VertexProperties to be plotted
* \return The edge list string.
*/
template <typename Graph>
std::string gnuplot_edge_list (const Graph& g);
/*
* \brief Compiles a multi-lined %string representing the vertices in \p g.
*
* Compiles a vertex list in the following format:
* x y
* x y
* ...
*
* \param g A boost::adjacency_list graph with CGAL::Point_2 as the VertexProperties to be plotted
* \return The vertex list string.
*/
template <typename Graph>
std::string gnuplot_vertex_list (const Graph& g);
/* This struct is defined to use partial specialization to generate arrow styles differently for
* directed and undirected graphs.
* Note: Need to use structs because C++ before 11 doesn't allow partial specialisation
* for functions
*/
template <typename Graph, typename Directedness=typename Graph::directed_selector>
struct Gnuplot_edges_2;
/* ------- IMPLEMENTATIONS ------- */
template <typename Graph>
std::string gnuplot_edge_list (const Graph& g)
{
std::stringstream ss;
ss.precision(3);
ss << std::fixed; // Use fixed floating-point notation
typename Graph::edge_iterator eit, ee;
for (boost::tie(eit, ee) = boost::edges(g); eit != ee; ++eit) {
typename Graph::vertex_descriptor src = boost::source(*eit, g);
typename Graph::vertex_descriptor end = boost::target(*eit, g);
ss << "set arrow from ";
ss << to_double(g[src].x()) << "," << to_double(g[src].y());
ss << " to ";
ss << to_double(g[end].x()) << "," << to_double(g[end].y());
ss << " as 1" << std::endl;
}
return ss.str();
}
// Common regardless of whether g is directed.
template <typename Graph>
std::string gnuplot_vertex_list(const Graph& g) {
std::stringstream ss;
ss.precision(3);
ss << std::fixed;
typename Graph::vertex_iterator vit, ve;
for (boost::tie(vit, ve) = boost::vertices(g); vit != ve; ++vit) {
ss << to_double(g[*vit].x()) << " " << to_double(g[*vit].y()) << std::endl;
}
return ss.str();
}
template <typename Graph>
void gnuplot_output_2 (const Graph& g, const std::string& prefix)
{
// Generate the vertex list to the .v file
std::ofstream fs((prefix + ".v").c_str(),
std::ofstream::out | std::ofstream::trunc);
fs << gnuplot_vertex_list(g);
fs.close();
std::cout << prefix << ".v" << " is generated. " << std::endl;
// Generate the Gnuplot Script to the .plt file
fs.open((prefix + ".plt").c_str(),
std::ofstream::out | std::ofstream::trunc);
fs << "set term ";
// Choose one:
fs << "wxt ";
// fs << "postscript eps ";
fs << "font \", 9\" enhanced" << std::endl;
// Uncomment if eps:
// fs << "set output \"" << prefix << ".eps\"" << std::endl;
fs << "set title" << std::endl;
fs << "set xlabel # when no options, clear the xlabel" << std::endl;
fs << "set ylabel" << std::endl;
fs << "unset key" << std::endl;
fs << "set size square" << std::endl;
fs << "unset xtics" << std::endl;
fs << "unset ytics" << std::endl;
fs << "unset border" << std::endl;
/* Uncomment if you need the following:
ss << "set xtics" << std::endl;
ss << "set ytics" << std::endl;
ss << "set border" << std::endl;
ss << "set grid xtics ytics" << std::endl;
*/
fs << std::endl;
// Specific part that depends on whether g is directed
fs << Gnuplot_edges_2<Graph>::gnuplot_edge_script(g);
fs << std::endl;
// plot the vertices
fs << "plot \"" << prefix << ".v\" with points pt 7 ps 0.8 lt rgb \"blue\"" << std::endl;
// Uncomment if wxt and also want eps output:
// fs << "set term postscript eps " << std::endl;
// fs << "set output \"" << prefix << ".eps\"" << std::endl;
// fs << "replot" << std::endl;
fs.close();
std::cout << prefix << ".plt" << " is generated. " << std::endl;
}
// directed graphs
/* Writing edge list to the gnuplot script for directed graphs */
template <typename Graph>
struct Gnuplot_edges_2<Graph, boost::directedS> {
// Uses "set style arrow 1 head" to draw directed edges
// Edges are written directly into the script file.
static std::string gnuplot_edge_script(const Graph& g)
{
std::stringstream ss;
ss << "set style arrow 1 head filled lc rgb \"black\"" << std::endl;
ss << std::endl;
ss << "# edges" << std::endl;
ss << gnuplot_edge_list(g);
ss << "# end of edges" << std::endl;
return ss.str();
}
};
// Bidirectional graph, the same as the directed graph.
/* Writing edge list to the gnuplot script for bidirectional graphs */
template <typename Graph>
struct Gnuplot_edges_2<Graph, boost::bidirectionalS> : public Gnuplot_edges_2<Graph, boost::directedS> {};
// Undirected graphs
/* Writing edge list to the gnuplot script for undirected graphs */
template <typename Graph>
struct Gnuplot_edges_2<Graph, boost::undirectedS> {
static std::string gnuplot_edge_script(const Graph& g)
{
std::stringstream ss;
ss << "set style arrow 1 nohead lc rgb \"black\"" << std::endl;
ss << std::endl;
ss << "# edges" << std::endl;
ss << gnuplot_edge_list(g);
ss << "# end of edges" << std::endl;
return ss.str();
}
};
} // namespace CGAL
#endif