I have read many articles on drawing planar graphs on the plane, I tried a lot of libraries.
In the end, I need to specify the input graph, the output to obtain new coordinates of its vertices, so that the edges do not intersect.
The choice fell on the function chrobak_payne_straight_line_drawing from Boost Graph Library.
I tested it on the following graph: http://cboard.cprogramming.com/attachments/cplusplus-programming/11153d1322430048-graph-planarization-boost-library-1grb.jpg
But it did not work and calls System.AccessViolationException at the 125 line of file chrobak_payne_drawing.hpp:
delta_x[v3] = 1;
But on this graph it works: http://cboard.cprogramming.com/attachments/cplusplus-programming/11154d1322430090-graph-planarization-boost-library-2gr.jpg
Please help, I need to function to work with all planar graphs and does not cause critical errors. Below I present the code, which I tested the first graph and got a critical error, by the way, I'm using visual studio 2010.
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <vector>
#include <stack>
#include <boost/graph/planar_canonical_ordering.hpp>
#include <boost/graph/is_straight_line_drawing.hpp>
#include <boost/graph/chrobak_payne_drawing.hpp>
#include <boost/graph/boyer_myrvold_planar_test.hpp>
using namespace boost;
//a class to hold the coordinates of the straight line embedding
struct coord_t
{
std::size_t x;
std::size_t y;
};
int main(int argc, char** argv)
{
typedef adjacency_list
< vecS,
vecS,
undirectedS,
property<vertex_index_t, int>
> graph;
//Define the storage type for the planar embedding
typedef std::vector< std::vector< graph_traits<graph>::edge_descriptor > >
embedding_storage_t;
typedef boost::iterator_property_map
< embedding_storage_t::iterator,
property_map<graph, vertex_index_t>::type
>
embedding_t;
// Create the graph - a maximal planar graph on 7 vertices. The functions
// planar_canonical_ordering and chrobak_payne_straight_line_drawing both
// require a maximal planar graph. If you start with a graph that isn't
// maximal planar (or you're not sure), you can use the functions
// make_connected, make_biconnected_planar, and make_maximal planar in
// sequence to add a set of edges to any undirected planar graph to make
// it maximal planar.
graph g(5);
add_edge(0,3, g);
add_edge(0,4, g);
add_edge(1,3, g);
add_edge(1,4, g);
add_edge(2,3, g);
add_edge(2,4, g);
// Create the planar embedding
embedding_storage_t embedding_storage(num_vertices(g));
embedding_t embedding(embedding_storage.begin(), get(vertex_index,g));
boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g,
boyer_myrvold_params::embedding = embedding
);
// Find a canonical ordering
std::vector<graph_traits<graph>::vertex_descriptor> ordering;
planar_canonical_ordering(g, embedding, std::back_inserter(ordering));
//Set up a property map to hold the mapping from vertices to coord_t's
typedef std::vector< coord_t > straight_line_drawing_storage_t;
typedef boost::iterator_property_map
< straight_line_drawing_storage_t::iterator,
property_map<graph, vertex_index_t>::type
>
straight_line_drawing_t;
straight_line_drawing_storage_t straight_line_drawing_storage
(num_vertices(g));
straight_line_drawing_t straight_line_drawing
(straight_line_drawing_storage.begin(),
get(vertex_index,g)
);
// Compute the straight line drawing
chrobak_payne_straight_line_drawing(g,
embedding,
ordering.begin(),
ordering.end(),
straight_line_drawing
);
std::cout << "The straight line drawing is: " << std::endl;
graph_traits<graph>::vertex_iterator vi, vi_end;
for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
{
coord_t coord(get(straight_line_drawing,*vi));
std::cout << *vi << " -> (" << coord.x << ", " << coord.y << ")"
<< std::endl;
}
// Verify that the drawing is actually a plane drawing
if (is_straight_line_drawing(g, straight_line_drawing))
std::cout << "Is a plane drawing." << std::endl;
else
std::cout << "Is not a plane drawing." << std::endl;
return 0;
}
Mayber i must first make graph maximal planar? But I did not succeed .. Please help me add to my code the necessary functions for this, I'm not quite sure what step to convert the graph.
Thanks in advance, you - my last hope!
This looks like a bug in boost::graph. I have a different access violation there, perhaps because of a different boost version, but there's definitely a bug.
left[v] = right[leftmost];
vertex_t next_to_rightmost;
for(vertex_t temp = leftmost; temp != rightmost;
temp = right[temp]
)
{
next_to_rightmost = temp;
}
right[next_to_rightmost] = graph_traits<Graph>::null_vertex();
Here when leftmost==rightmost, the for loop is not executed and next_to_rightmost remains uninitialized. Crash! That's what I'm seeing.
The graph you were using was not maximal planar. You need to use the functions make_connected, make_biconnected_planar and make_maximal_planar before you get to a canonical ordering or an embedding. Though the comment in the source explains this, their use is not exactly intuitive and I could not find a source using them and the function chrobak_payne_straight_line_drawing in combination. Here is an example I adapted from the original source and other examples.
Related
I've been trying to puzzle out how to form edge descriptors for a CGAL Triangulation_3 such that I can use Boost's implementation of Kruskal's Minimum Spanning Tree on that Triangulation.
I have been reading through the reference documentation for a Triangulation_2 (provided here), but have observed that no implementation exists for boost::graph_traits<Triangulation_3>. While puzzling it out, I found that I could possibly provide my own implementation for edge descriptors through an adjacency list as shown in Boost's example for a Kruskal MST, but got lost and confused at this step, and didn't know if that would be a sufficient approach.
Ultimately, it seems that what I need to do is create a boost Graph implementation, but am lost at what resources I need to accomplish this step. From there, the desired use is to be able to traverse this MST to perform graph-based min-cuts at specific edges matching a predicate.
// EDIT :>
My current attempt revolves around creating the EMST via pushing simplex edges defined as a pair of vertex iterate indices, with weights defined as euclidean distance between vertices (a Point_3 with data attached), using the Graph construction shown in the Boost example.
My hope is to have BGL vertices (as a Point_3 with color information attached) be connected by BGL edges (as a simplex[!] edge after the triangulation). My ultimate use just requires that I traverse some sort of contiguous spatial ordering of my Point_3's (with RGB info), and split estimated planes into "patches" which meet a max-distance (complete linkage?) threshold, or a within-patch distance variance. It's not exactly segmentation, but similar.
// some defns...
using RGBA = std::array<uint16_t, 3>;
using PointData = boost::tuple<
Point_3, // Point location; Easting-Altitude-Northing
Vector_3, // Estimated Normal Vector at Point
RGBA, // Photo Color
RGBA, // RANSAC Shape Colorization
size_t, // Estimated Patch ID
RGBA>; // Estimated Patch Colorization
//
// Some operations on the points and RANSAC estimation occurs here
//
// iterate through shapes
while (it != shapes.end()) {
boost::shared_ptr<EfficientRANSAC::Shape> shape = *it;
std::cout << (*it)->info() << std::endl;
// generate a random color code for this shape
RGBA rgb;
for (int i=0; i<3; i++) {
rgb[i] = rand()%256;
}
// Form triangulation to later convert into Graph representation
using VertexInfoBase = CGAL::Triangulation_vertex_base_with_info_3<
PointData,
Kernel
>;
using TriTraits = CGAL::Triangulation_data_structure_3<
VertexInfoBase,
CGAL::Delaunay_triangulation_cell_base_3<Kernel>,
CGAL::Parallel_tag
>;
using Triangulation_3 = CGAL::Delaunay_triangulation_3<Kernel, TriTraits>;
Triangulation_3 tr;
// Iterate through point indices assigned to each detected shape.
std::vector<std::size_t>::const_iterator
index_it = (*it)->indices_of_assigned_points().begin();
while (index_it != (*it)->indices_of_assigned_points().end()) {
PointData& p = *(points.begin() + (*index_it));
// assign shape diagnostic color info
boost::get<3>(p) = rgb;
// insert Point_3 data for triangulation and attach PointData info
auto vertex = tr.insert(boost::get<0>(p));
vertex->info() = p;
index_it++; // next assigned point
}
std::cout << "Found triangulation with: \n\t" <<
tr.number_of_vertices() << "\tvertices\n\t" <<
tr.number_of_edges() << "\tedges\n\t" <<
tr.number_of_facets() << "\tfacets" << std::endl;
// build a Graph out of the triangulation that we can do a Minimum-Spanning-Tree on
using Graph = boost::adjacency_list<
boost::vecS, // OutEdgeList
boost::vecS, // VertexList
boost::undirectedS, // Directed
boost::no_property, // VertexProperties
boost::property< boost::edge_weight_t, int >, // EdgeProperties
boost::no_property, // GraphProperties
boost::listS // EdgeList
>;
using Edge = boost::graph_traits<Graph>::edge_descriptor;
using E = std::pair< size_t, size_t >; // <: TODO - should be iterator index of vertex in Triangulation_3 instead of size_t?
std::vector<E> edge_array; // edges should be between Point_3's with attached RGBA photocolor info.
// It is necessary to later access both the Point_3 and RGBA info for vertices after operations are performed on the EMST
std::vector<float> weights; // weights are `std::sqrt(CGAL::squared_distance(...))` between these Point_3's
// Question(?) :> Should be iterating over "finite" edges here?
for (auto edge : tr.all_edges()) {
// insert simplex (!!) edge (between-vertices) here
edge_array.push_back(...);
// generate weight using std::sqrt(CGAL::squared_distance(...))
weights.push_back(...);
}
// build Graph from `edge_array` and `weights`
Graph g(...);
// build Euclidean-Minimum-Spanning-Tree (EMST) as list of simplex edges between vertices
std::list<E> emst;
boost::kruskal_minimum_spanning_tree(...);
// - traverse EMST from start of list, performing "cuts" into "patches" when we have hit
// max patch distance (euclidean) from current "first" vertex of "patch".
// - have to be able to access Triangulation_3 vertex info (via `locate`?) here
// - foreach collection of PointData in patch, assign `patch_id` and diagnostic color info,
// then commit individual serialized "patches" collections of Point_3 and RGBA photocolor to database
todo!();
it++; // next shape
}
The end goal of traversing each of the shapes using a Minimum Spanning Tree via Triangulation is to break each of the RANSAC estimated shapes into chunks, for other purposes. Picture example:
Do you want the graph of vertices and edges, or the graph of the dual, that is the tetrahedra would be BGL vertices and the faces between tetrahedra would be BGL edges?
For both it is not that hard to write the specialization of the graph traits class and the some free functions to navigate. Get inspired by the code for the 2D version for the graph_traits
Ultimately, it seems that what I need to do is create a boost Graph implementation, but am lost at what resources I need to accomplish this step.
The algorithm documents the concept requirements:
You can zoom in on the implications here: VertexListGraph and EdgeListGraph.
I found that I could possibly provide my own implementation for edge descriptors through an adjacency list as shown in Boost's example for a Kruskal MST, but got lost and confused at this step, and didn't know if that would be a sufficient approach.
It would be fine to show your attempt as a question, because it would help us know where you are stuck. Right now there is really no code to "go at", so I'll happily await a newer, more concrete question.
I was able to find an attempt at an answer. I added another property to my Point collection implementation (that included the index of that point in an array), and used this to iterate over edges in the triangulation to build the Graph, before running the EMST algorithm on it.
However, the real answer is don't do this -- it still is not working correctly (incorrect number of edges, including infinite vertices in the edge list, and other problems).
// Form triangulation to later convert into Graph representation
using VertexInfoBase = CGAL::Triangulation_vertex_base_with_info_3<
PointData,
Kernel
>;
using TriTraits = CGAL::Triangulation_data_structure_3<
VertexInfoBase,
CGAL::Delaunay_triangulation_cell_base_3<Kernel>,
CGAL::Parallel_tag
>;
using Triangulation_3 = CGAL::Delaunay_triangulation_3<Kernel, TriTraits>;
Triangulation_3 tr;
// Iterate through point indices assigned to each detected shape.
std::vector<std::size_t>::const_iterator
index_it = (*it)->indices_of_assigned_points().begin();
while (index_it != (*it)->indices_of_assigned_points().end()) {
PointData& p = *(points.begin() + (*index_it));
// assign shape diagnostic color info
boost::get<3>(p) = rgb;
// insert Point_3 data for triangulation and attach PointData info
TriTraits::Vertex_handle vertex = tr.insert(boost::get<0>(p));
vertex->info() = p;
index_it++; // next assigned point
}
std::cout << "Found triangulation with: \n\t" <<
tr.number_of_vertices() << "\tvertices\n\t" <<
tr.number_of_edges() << "\tedges\n\t" <<
tr.number_of_facets() << "\tfacets" << std::endl;
// build a Graph out of the triangulation that we can do a Minimum-Spanning-Tree on
// examples taken from https://www.boost.org/doc/libs/1_80_0/libs/graph/example/kruskal-example.cpp
using Graph = boost::adjacency_list<
boost::vecS, // OutEdgeList
boost::vecS, // VertexList
boost::undirectedS, // Directed
boost::no_property, // VertexProperties
boost::property< boost::edge_weight_t, double > // EdgeProperties
>;
using Edge = boost::graph_traits<Graph>::edge_descriptor;
using E = std::pair< size_t, size_t >; // <: TODO - should be iterator index of vertex in Triangulation_3 instead of size_t?
Graph g(tr.number_of_vertices());
boost::property_map< Graph, boost::edge_weight_t >::type weightmap = boost::get(boost::edge_weight, g);
// iterate over finite edges in the triangle, and add these
for (
Triangulation_3::Finite_edges_iterator eit = tr.finite_edges_begin();
eit != tr.finite_edges_end();
eit++
)
{
Triangulation_3::Segment s = tr.segment(*eit);
Point_3 vtx = s.point(0);
Point_3 n_vtx = s.point(1);
// locate the (*eit), get vertex handles?
// from https://www.appsloveworld.com/cplus/100/204/how-to-get-the-source-and-target-points-from-edge-iterator-in-cgal
Triangulation_3::Vertex_handle vh1 = eit->first->vertex((eit->second + 1) % 3);
Triangulation_3::Vertex_handle vh2 = eit->first->vertex((eit->second + 2) % 3);
double weight = std::sqrt(CGAL::squared_distance(vtx, n_vtx));
Edge e;
bool inserted;
boost::tie(e, inserted)
= boost::add_edge(
boost::get<6>(vh1->info()),
boost::get<6>(vh2->info()),
g
);
weightmap[e] = weight;
}
// build Euclidean-Minimum-Spanning-Tree (EMST) as list of simplex edges between vertices
//boost::property_map<Graph, boost::edge_weight_t>::type weight = boost::get(boost::edge_weight, g);
std::vector<Edge> spanning_tree;
boost::kruskal_minimum_spanning_tree(g, std::back_inserter(spanning_tree));
// we can use something like a hash table to go from source -> target
// for each of the edges, making traversal easier.
// from there, we can keep track or eventually find a source "key" which
// does not correspond to any target "key" within the table
std::unordered_map< size_t, std::vector<size_t> > map = {};
// iterate minimum spanning tree to build unordered_map (hashtable)
std::cout << "Found minimum spanning tree of " << spanning_tree.size() << " edges for #vertices " << tr.number_of_vertices() << std::endl;
for (std::vector< Edge >::iterator ei = spanning_tree.begin();
ei != spanning_tree.end(); ++ei)
{
size_t source = boost::source(*ei, g);
size_t target = boost::target(*ei, g);
// << " with weight of " << weightmap[*ei] << std::endl;
if ( map.find(source) == map.end() ) {
map.insert(
{
source,
std::vector({target})
}
);
} else {
std::vector<size_t> target_vec = map[source];
target_vec.push_back(target);
map[source] = target_vec;
}
}
// iterate over map to find an "origin" node
size_t origin = 0;
for (const auto& it : map) {
bool exit_flag = false;
std::vector<size_t> check_targets = it.second;
for (size_t target : check_targets) {
if (map.find(target) == map.end()) {
origin = target;
exit_flag = true;
break;
}
}
if (exit_flag) {
break;
}
}
std::cout << "Found origin of tree with value: " << origin << std::endl;
Currently I am trying to implement a Girvan Newman Algorithm for a class project using boost graph library in c++.
At the moment, edges and vertices are being added fine, but I am having an issue removing edges. I am using an iterator to add my edges, and am now trying to remove them. Everything functions as expected until I try to remove an edge, and then I hit a segfault. I have tried removing the edge using the conditional remove_edge_if() and tried some of the other boost options - still having the same issue.
enum {A, B, C, D, E};
num_vertices = 5;
//writing out edges in graph
typedef std::pair<int, int> Edge;
Edge edge_array[] = {
Edge(A,B),
Edge(A,D),
Edge(C,A),
Edge(D,C),
Edge(C,E),
Edge(D,E)
};
const int num_edges = sizeof(edge_array)/sizeof(edge_array[0]);
//declare a graph object
Graph g(num_vertices);
//add the edges to the graph object
for(int i=0;i<num_edges;i++){
add_edge(edge_array[i].first, edge_array[i].second, g);
}
//actual algorithm starts here
//get property map for vertex indices
index = get(boost::vertex_index, g);
//calculate all centrality values and store in vector betweenness
calcCentrality();
//set up iterators to run through all edges
boost::graph_traits<Graph>::edge_iterator ei, ei_end;
boost::graph_traits<Graph>::edge_iterator loc;
std::tie(ei, ei_end)=edges(g);
for(int i=0;i<num_edges;i++){
std::cout << "(" << index[source(*ei, g)] << "," << index[target(*ei, g)] << ") ";
ei++;
}
std::cout << std::endl;
std::tie(ei, ei_end)=edges(g);
int max_B = 0;
boost::graph_traits<Graph>::vertex_descriptor max_B_edge1, max_B_edge2;
//iterate through all edges-1
for(int i=0;i<num_edges-1;i++){
//check betweenness centrality of edge i
int BC = betweeness[i];
if(BC > max_B){
max_B = BC;
max_B_edge1 = source(*ei, g);
max_B_edge2 = target(*ei, g);
}
ei++;
}
boost::remove_edge(max_B_edge1, max_B_edge2, g);
std::cout << std::endl;
std::tie(ei, ei_end)=edges(g);
for(int i=0;i<num_edges;i++){
std::cout << "(" << index[source(*ei, g)] << "," << index[target(*ei, g)] << ") ";
ei++;
}
std::cout << std::endl;
}
Any guidance on how to resolve this, or a new approach would be extremely helpful. I think the issue is with my iterator
The bigger problem is that you are indexing betweenness by an integer [0, num_edges). This doesn't make a lot of sense unless betweenness is actually an edge centrality map (not the vertex centrality map, or just "centrality map").
But that is making things weirder, because that would suggest an associative container like map<edge_descriptor, double> instead of a vector<>, because edge_descriptor is not an integral type.
Of course, one can paper over this by creating an explicit edge_index property/map and projecting through that to a integral-indexed container, e.g.
std::vector<double> betweenness(num_edges(g));
auto edge_id_map = get(boost::edge_index, g); // or assumed externally supplied?
auto edge_centrality_map = boost::make_safe_iterator_property_map(
betweenness.begin(),
betweenness.size(),
edge_id_map);
Now, if that were the case, one has to wonder why the same map is not used to access the betweenness by descriptor... instead of implicitly recalculating an edge index again in a loop-variable (int i). That is unsafe especially since you're modifying the edges, so re-running the loop will calculate different i for each edge! Oops.
Instead, I'd make betweenness associative, indexed by edge-descriptor. Of course, I can't show the relevant changes, because calcCentrality is missing. Even betweenness is missing (which by the way suggests that it must be a global variable? Not a very robust idea if so).
Let's assume for a moment that you have edge_centrality_map defined as above, or, in my preferred approach, like this:
// more stable idea:
std::map<Graph::edge_descriptor, double> betweenness;
auto edge_centrality_map = boost::make_assoc_property_map(betweenness);
Now the whole... mess with the loop could be replace with:
std::map<Graph::edge_descriptor, double> betweenness;
auto edge_centrality_map = boost::make_assoc_property_map(betweenness);
while (num_edges(g)) {
auto ee = edges(g);
auto [min, max] = std::minmax_element(
ee.first, ee.second, [ecm = edge_centrality_map](auto a, auto b) {
return ecm[a] < ecm[b];
});
remove_edge(*max, g);
print_edges();
}
For good measure I used minmax_element to show off the convenience of using standard algorithms here. We use the lambda to "simply" project through the centrality map. No manual juggling with loop variables and translating to vector indexes. This is less work, but more importantly less room for error.
Here's the code presented modernized and showing the suggested approach:
Live On Compiler Explorer
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/betweenness_centrality.hpp>
#include <iostream>
using Graph = boost::adjacency_list<>;
int main() {
enum { A, B, C, D, E, N /*==5*/ };
Graph g(N);
auto print_edges = [&g] { // helper to avoid repeating code
for (auto e : boost::make_iterator_range(edges(g)))
std::cout << e << " ";
std::cout << std::endl;
};
// add the edges to the graph object
for (auto [s, t] :
std::array{std::pair{A, B}, std::pair{A, D}, std::pair{C, A},
std::pair{D, C}, std::pair{C, E}, std::pair{D, E}}) //
{
add_edge(s, t, g);
}
print_edges();
// actual algorithm starts here
// get property map for vertex indices
auto index = get(boost::vertex_index, g);
// calculate all centrality values and store in vector betweenness
// calcCentrality();
//std::vector<int> betweenness(num_edges(g)); // JUST GUESSING
// more stable idea:
std::map<Graph::edge_descriptor, double> betweenness;
auto edge_centrality_map = boost::make_assoc_property_map(betweenness);
while (num_edges(g)) {
auto ee = edges(g);
auto [min, max] = std::minmax_element(
ee.first, ee.second, [ecm = edge_centrality_map](auto a, auto b) {
return ecm[a] < ecm[b];
});
boost::remove_edge(*max, g);
print_edges();
}
}
Prints dummy output (because the betweenness is defaulted to 0.0 for each edge):
(0,1) (0,3) (2,0) (2,4) (3,2) (3,4)
(0,1) (0,3) (2,0) (2,4) (3,2)
(0,1) (0,3) (2,0) (2,4)
(0,1) (0,3) (2,0)
(0,1) (0,3)
(0,1)
BONUS
In fact, the loop is not very optimal, because instead of repeatedly finding the maximum element of a container, just to remove them can be thought of as sorting, and then removing edges in order.
Live On Compiler Explorer
auto [e_begin, e_end] = edges(g);
std::vector ascending(e_begin, e_end);
std::stable_sort(begin(ascending), end(ascending), edge_compare);
while (not ascending.empty()) {
remove_edge(ascending.back(), g);
ascending.pop_back();
print_edges();
}
Which gives the same output, just much quicker.
Also note that if your chosen edge_centrality_map suffers from
index/iterator/descriptor or reference invalidation in some way on the
remove_edge operation, this is safer, because it only depends on
the stability of edge descriptors in your chosen Graph model.
In fact, you might not even need/want to remove the edges "physically" to save time and work. After all, you know which edges to leave out when printing.
I am trying to find out the intersection points of two unit-radius circles in CGAL. Inspired by the CGAL sample codes and tutorials, I have succeeded in creating the following code. But unfortunately, I am unable to print out the points. I have noticed that the size of the vector is the number of intersection points. Any help will be appreciated since I am new to CGAL.
#include <CGAL/Circular_kernel_intersections.h>
#include <CGAL/Exact_circular_kernel_2.h>
typedef CGAL::Exact_circular_kernel_2 Circular_k;
typedef CGAL::Point_2<Circular_k> Point_2;
typedef CGAL::Circle_2<Circular_k> Circle_2;
typedef CGAL::Circular_arc_2<Circular_k> Circular_arc_2;
typedef CGAL::CK2_Intersection_traits<Circular_k, Circle_2, Circle_2>::type Intersection_result;
using namespace std;
int main() {
Point_2 p(2,2), r(5.5,2);
Circle_2 c1(p,1), c2(r,1);
vector<Intersection_result> res;
intersection(c1,c2,back_inserter(res));
cout << res.size() << endl;
}
I tested your code and it seems to work. Note that the intersection points are stored as Circular_arc_point_2. Using your code I added only the following lines:
using boostRetVal = std::pair<CGAL::Circular_arc_point_2<CGAL::Filtered_bbox_circular_kernel_2<CGAL::Circular_kernel_2<CGAL::Cartesian<CGAL::Gmpq>, CGAL::Algebraic_kernel_for_circles_2_2<CGAL::Gmpq> > > > , unsigned>;
for(const auto& element : res) {
auto algPoint = std::get<0>( boost::get< boostRetVal >(element) );
auto point = Point_2(to_double(algPoint.x()), to_double(algPoint.y()));
std::cout << point << std::endl;
}
As points I used p(0,0), r(2,0), as circles c1(p,4), c2(r,1), then the received output was:
2
7/4 -4360591588697965/4503599627370496
7/4 4360591588697965/4503599627370496
Let's say I have a graph, with edges each containing a char. From a vertex, I want to get a specific out-edge with a specific char. Since the edge container can be set to a set or a hash-set, I assume there is a way to do this without iterating through the vertex's out-edges. I'm also assuming/hoping the edge container is keyed on the type the edge contains.
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
typedef boost::adjacency_list<setS, vecS, directedS, std::string, char> MyGraph;
typedef boost::graph_traits<MyGraph>::vertex_descriptor Vertex;
typedef boost::graph_traits<MyGraph>::edge_descriptor Edge;
MyGraph g;
//setup
add_vertex(std::string("xxx"), g);
Vertex currentVertex = g.vertex_set()[0];
Vertex endVertex = add_vertex(std::string("yyy"), g);
add_edge(currentVertex, endVertex, 'i', g);
//later...
//Now I want that edge containing the letter 'i'.
//out_edges returns a pair of edge iterators.
std::pair<iterator, iterator> iterators = out_edges(currentVertex, g); // do not want!
Edge iEdge = how_do_I_get_This?(currentVertex, g); // want!
Is there a way to do this, or is iterating through the out-edges the only option?
update:
I think this will get me the container.
std::set<?> edges = g.out_edge_list(currentVertex);
Now I cannot figure out what the ? template type is.
update2:
This seems to compile, but I need an edge_descriptor, not an edge_property to pass to target.
std::set<boost::detail::stored_edge_property<long unsigned int, char> > edges = fGraph.out_edge_list(currentVertex);
update3:
Guess I don't need an edge descriptor. Got what I needed like this:
std::set<boost::detail::stored_edge_property<long unsigned int, char> > edges = fGraph.out_edge_list(currentVertex);
std::_Rb_tree_const_iterator<boost::detail::stored_edge_property<long unsigned int, char> > edge = edges.find(*i);
Vertex target = edge.get_target();
This all compiles and seems to work, but it is massively ugly.
Are you looking for how to use edge descriptors?
Edge i_edge = add_edge(currentVertex, endVertex, 'i', g).first;
i_edge is the vertex-descriptor for the 'i' edge.
// later...
// Now I want that edge containing the letter 'i'.
char yougotit = g[i_edge];
Check it:
assert('i' == yougotit);
See it Live On Coliru
If you really want to search, and can use c++1y you might find this elegant: Also Live
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <iostream>
using namespace boost::adaptors;
using namespace boost;
typedef boost::adjacency_list<setS, vecS, directedS, std::string, char> MyGraph;
typedef boost::graph_traits<MyGraph>::vertex_descriptor Vertex;
typedef boost::graph_traits<MyGraph>::edge_descriptor Edge;
int main() {
MyGraph g;
// setup
add_vertex(std::string("xxx"), g);
Vertex currentVertex = g.vertex_set()[0];
Vertex endVertex = add_vertex(std::string("yyy"), g);
add_edge(currentVertex, endVertex, 'i', g);
for (auto matching : boost::edges(g) | filtered([&g](auto const& e) { return g[e] == 'i'; }))
std::cout << matching << " --> " << g[matching] << "\n";
}
Output:
(0,1) --> i
I'm using CGAL and got into some weird bug, which I can't reproduce in a small test program. Here is the test code that works as given, but when I have the exact same code in my larger program (a ROS node) it spits an error:
#include <vector>
#include <boost/shared_ptr.hpp>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include "print.h"
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT Ft;
typedef Kernel::Point_2 Point;
typedef Kernel::Segment_2 Segment;
typedef Kernel::Direction_2 Direction;
typedef Kernel::Line_2 Line;
typedef Kernel::Vector_2 Vector;
typedef CGAL::Polygon_2<Kernel> Polygon;
typedef CGAL::Polygon_with_holes_2<Kernel> PolygonWithHoles;
main() {
Polygon poly;
float scale = 4.0/100;
float max_y = 500*scale;
poly.push_back(Point(76*scale, max_y-496*scale));
poly.push_back(Point(660*scale, max_y-496*scale));
poly.push_back(Point(660*scale, max_y-48*scale));
poly.push_back(Point(71*scale, max_y-54*scale));
// Holes must be clock wise!!
Polygon holes[10];
holes[0].push_back(Point(131*scale, max_y-86*scale));
holes[0].push_back(Point(179*scale, max_y-85*scale));
holes[0].push_back(Point(180*scale, max_y-238*scale));
holes[0].push_back(Point(133*scale, max_y-239*scale));
holes[1].push_back(Point(237*scale, max_y-84*scale));
holes[1].push_back(Point(286*scale, max_y-84*scale));
holes[1].push_back(Point(288*scale, max_y-237*scale));
holes[1].push_back(Point(240*scale, max_y-238*scale));
// Why does this hole make intersection() error?
holes[2].push_back(Point(345*scale, max_y-84*scale));
holes[2].push_back(Point(393*scale, max_y-83*scale));
holes[2].push_back(Point(396*scale, max_y-236*scale));
holes[2].push_back(Point(348*scale, max_y-236*scale));
PolygonWithHoles polyHoles(poly);
polyHoles.outer_boundary() = poly;
for (int i=0; i<3; ++i)
polyHoles.add_hole(holes[i]);
std::cout << "\nPolygon:" << std::endl;
print_polygon_with_holes(polyHoles);
Polygon selection;
float minx = -5.7669;
float miny = -2.13124;
float maxx = 0.396996;
float maxy = 4.88933;
selection.push_back(Point(minx, miny));
selection.push_back(Point(maxx, miny));
selection.push_back(Point(maxx, maxy));
selection.push_back(Point(minx, maxy));
std::cout << "\nSelection:" << std::endl;
print_polygon(selection);
std::vector<PolygonWithHoles> result;
CGAL::intersection(polyHoles, selection, std::back_inserter(result));
std::cout << "Intersection:" << std::endl;
if (!result.empty())
print_polygon_with_holes(result.front());
}
The error:
terminate called after throwing an instance of 'CGAL::Precondition_exception'
what(): CGAL ERROR: precondition violation!
Expr: comp_f(object, parentP->object) != SMALLER
File: /usr/include/CGAL/Multiset.h
Line: 2128
I found 2 ways to fix this:
Shift one point a little bit: replace 83 with 84.
Use Exact_predicates_exact_constructions_kernel
My question is: what could cause the problem to exist only in the larger program?
I'd like to keep using the unexact_constructions, I don't see why I'd have to use the exact_constructions in this case (points aren't close to each other or anything), but since I don't know what the intersection() algorithm does I might be wrong about that.
The intersect function constructs new points - new points of intersections. If you are not using exact constructions, then these new points are not promised to be correct. If you then use these inexact points for further computations you'll run into problems. Unless you have significant constraints on the running time, I believe you're better of with exact constructions.
Example: Consider the unit circle x^2+y^2=1 and the line y=x and let p be a constructed point of intersection. Then circle.has_on_boundary (p) will return TRUE only if you use the exact constructions.