Skip to content

File GeometryGraph.h

File List > detail > graph > GeometryGraph.h

Go to the documentation of this file

// Copyright (c) 2012-2013, IGN France.
// Copyright (c) 2012-2022, Oslandia.
// SPDX-License-Identifier: LGPL-2.0-or-later

#ifndef _SFCGAL_GRAPH_GEOMETRYGRAPH_H_
#define _SFCGAL_GRAPH_GEOMETRYGRAPH_H_

#include <boost/graph/adjacency_list.hpp>

#include "SFCGAL/detail/graph/Edge.h"
#include "SFCGAL/detail/graph/Vertex.h"

namespace SFCGAL {
namespace graph {

typedef enum { DIRECT = 0, REVERSE = 1 } EdgeDirection;

inline EdgeDirection
reverse(const EdgeDirection &direction)
{
  return (EdgeDirection)(1 - direction);
}

template <typename VertexProperties, typename EdgeProperties>
class GeometryGraphT {
public:
  typedef VertexProperties vertex_properties;
  typedef EdgeProperties   edge_properties;

  typedef boost::adjacency_list<
      boost::listS, /* stable identifiers */
      boost::listS, /* parallel edges allowed + stable identifiers */
      boost::bidirectionalS, vertex_properties, edge_properties>
      graph_t;

  typedef typename boost::graph_traits<graph_t>::vertex_descriptor
      vertex_descriptor;
  typedef
      typename boost::graph_traits<graph_t>::edge_descriptor edge_descriptor;

  typedef
      typename boost::graph_traits<graph_t>::vertex_iterator   vertex_iterator;
  typedef typename boost::graph_traits<graph_t>::edge_iterator edge_iterator;
  typedef std::pair<edge_descriptor, EdgeDirection> directed_edge_descriptor;

  typedef
      typename boost::graph_traits<graph_t>::in_edge_iterator in_edge_iterator;
  typedef typename boost::graph_traits<graph_t>::out_edge_iterator
      out_edge_iterator;

  inline size_t
  numVertices() const
  {
    return boost::num_vertices(_graph);
  }

  inline std::pair<vertex_iterator, vertex_iterator>
  vertices() const
  {
    return boost::vertices(_graph);
  }

  vertex_descriptor
  addVertex(const vertex_properties &properties = vertex_properties())
  {
    return boost::add_vertex(properties, _graph);
  }
  void
  removeVertex(const vertex_descriptor &vertex)
  {
    boost::clear_vertex(vertex);
    boost::remove_vertex(vertex);
  }

  inline size_t
  numEdges() const
  {
    return boost::num_edges(_graph);
  }

  inline std::pair<edge_iterator, edge_iterator>
  edges() const
  {
    return boost::edges(_graph);
  }

  edge_descriptor
  addEdge(const vertex_descriptor &source, const vertex_descriptor &target,
          const EdgeProperties &properties = EdgeProperties())
  {
    return boost::add_edge(source, target, properties, _graph).first;
  }

  vertex_descriptor
  source(const edge_descriptor &edge) const
  {
    return boost::source(edge, _graph);
  }
  vertex_descriptor
  source(const edge_descriptor &edge, const EdgeDirection &direction) const
  {
    return direction == DIRECT ? boost::source(edge, _graph)
                               : boost::target(edge, _graph);
  }
  vertex_descriptor
  source(const directed_edge_descriptor &edge) const
  {
    return source(edge.first, edge.second);
  }

  vertex_descriptor
  target(const edge_descriptor &edge) const
  {
    return boost::target(edge, _graph);
  }
  vertex_descriptor
  target(const edge_descriptor &edge, const EdgeDirection &direction) const
  {
    return direction == DIRECT ? boost::target(edge, _graph)
                               : boost::source(edge, _graph);
  }
  vertex_descriptor
  target(const directed_edge_descriptor &edge) const
  {
    return target(edge.first, edge.second);
  }
  void
  removeEdge(const edge_descriptor &edge)
  {
    boost::remove_edge(edge, _graph);
  }

  std::vector<directed_edge_descriptor>
  edges(const vertex_descriptor &a, const vertex_descriptor &b) const
  {
    std::vector<directed_edge_descriptor> result;

    // out_edges from a targeting b
    {
      out_edge_iterator it, end;

      for (boost::tie(it, end) = boost::out_edges(a, _graph); it != end; ++it) {
        if (target(*it) != b) {
          continue;
        }

        result.push_back(std::make_pair(*it, DIRECT));
      }
    }
    // out_edges from b targeting a
    {
      out_edge_iterator it, end;

      for (boost::tie(it, end) = boost::out_edges(b, _graph); it != end; ++it) {
        if (target(*it) != a) {
          continue;
        }

        result.push_back(std::make_pair(*it, REVERSE));
      }
    }
    return result;
  }

  inline size_t
  degree(const vertex_descriptor &vertex) const
  {
    return boost::degree(vertex, _graph);
  }

  std::vector<edge_descriptor>
  inEdges(const vertex_descriptor &vertex)
  {
    std::vector<edge_descriptor> edges;

    in_edge_iterator it, end;

    for (boost::tie(it, end) = boost::in_edges(vertex, _graph); it != end;
         ++it) {
      edges.push_back(*it);
    }

    return edges;
  }
  std::vector<edge_descriptor>
  outEdges(const vertex_descriptor &vertex) const
  {
    std::vector<edge_descriptor> edges;

    out_edge_iterator it, end;

    for (boost::tie(it, end) = boost::out_edges(vertex, _graph); it != end;
         ++it) {
      edges.push_back(*it);
    }

    return edges;
  }
  std::vector<directed_edge_descriptor>
  inOutEdges(const vertex_descriptor &vertex) const
  {
    std::vector<directed_edge_descriptor> edges;
    {
      in_edge_iterator it, end;

      for (boost::tie(it, end) = boost::in_edges(vertex, _graph); it != end;
           ++it) {
        edges.push_back(std::make_pair(*it, REVERSE));
      }
    }

    // out edges
    {
      out_edge_iterator it, end;

      for (boost::tie(it, end) = boost::out_edges(vertex, _graph); it != end;
           ++it) {
        edges.push_back(std::make_pair(*it, DIRECT));
      }
    }
    return edges;
  }

  std::set<vertex_descriptor>
  adjacentVertices(const vertex_descriptor &vertex,
                   bool                     withReverseDirection = true)
  {
    std::set<vertex_descriptor> vertices;
    // out edges
    {
      out_edge_iterator it, end;

      for (boost::tie(it, end) = boost::out_edges(vertex, _graph); it != end;
           ++it) {
        vertex_descriptor reached = target(*it);

        if (reached != vertex) {
          vertices.insert(reached);
        }
      }
    }

    // in edges
    if (withReverseDirection) {
      in_edge_iterator it, end;

      for (boost::tie(it, end) = boost::in_edges(vertex, _graph); it != end;
           ++it) {
        vertex_descriptor reached = source(*it);

        if (reached != vertex) {
          vertices.insert(reached);
        }
      }
    }

    return vertices;
  }

  inline bool
  areOpposite(const edge_descriptor &a, const edge_descriptor &b) const
  {
    return source(a) == target(b) && target(a) == source(b);
  }
  inline bool
  areParallel(const edge_descriptor &a, const edge_descriptor &b) const
  {
    return source(a) == source(b) && target(a) == target(b);
  }

  void
  reverse(std::vector<edge_descriptor> &edges)
  {
    std::vector<edge_descriptor> result;

    for (typename std::vector<edge_descriptor>::reverse_iterator it =
             edges.rbegin();
         it != edges.rend(); ++it) {
      edge_descriptor newEdge = addEdge(target(*it), source(*it), (*this)[*it]);
      result.push_back(newEdge);
      removeEdge(*it);
    }

    edges = result;
  }

  inline const vertex_properties &
  operator[](const vertex_descriptor &vertex) const
  {
    return _graph[vertex];
  }
  inline vertex_properties &
  operator[](const vertex_descriptor &vertex)
  {
    return _graph[vertex];
  }

  inline const edge_properties &
  operator[](const edge_descriptor &edge) const
  {
    return _graph[edge];
  }
  inline edge_properties &
  operator[](const edge_descriptor &edge)
  {
    return _graph[edge];
  }

  inline graph_t &
  graph()
  {
    return _graph;
  }
  inline const graph_t &
  graph() const
  {
    return _graph;
  }

  operator graph_t &(void) { return _graph; }
  operator const graph_t &(void) const { return _graph; }

private:
  graph_t _graph;
};

typedef GeometryGraphT<Vertex, Edge> GeometryGraph;

} // namespace graph
} // namespace SFCGAL

#endif