I'm using CGAL (v. 4.14-2) to compute the visibility region (polygon) within a simple polygon from one of its vertices, using the Simple_polygon_visibility_2 class.
On a particular combination of polygon/vertex, I'm getting the following assertion error:
terminate called after throwing an instance of 'CGAL::Assertion_exception'
what(): CGAL ERROR: assertion violation!
Expr: k+1<vertices.size()
File: /usr/include/CGAL/Simple_polygon_visibility_2.h
Line: 678
This occurs in the method scan_edges of the class Simple_polygon_visibility_2, it seems like there should be some intersection with the given segment/ray, but none was found.
When I run the same code with the class Triangular_expansion_visibility_2, it seems to work, giving the output:
Regularized visibility region of q has 8 edges:
[7968 492 -> 7938 428]
[7884 408 -> 7968 492]
[8040 428 -> 7884 408]
[8090.99 428 -> 8040 428]
[8105.55 458.865 -> 8090.99 428]
[8090 456 -> 8105.55 458.865]
[7968 446 -> 8090 456]
[7938 428 -> 7968 446]
Here's a minimal working example:
#include <CGAL/Arr_naive_point_location.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Simple_polygon_visibility_2.h>
#include <CGAL/Triangular_expansion_visibility_2.h>
#include <fstream>
#include <iostream>
#include <string>
#include <list>
#include <vector>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Segment_2 Segment_2;
typedef CGAL::Polygon_2<Kernel, std::list<Point_2>> Polygon_2;
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
typedef Arrangement_2::Face_handle Face_handle;
typedef Arrangement_2::Vertex_handle ArrVertex_handle;
typedef Arrangement_2::Edge_const_iterator Edge_const_iterator;
typedef Arrangement_2::Ccb_halfedge_circulator Ccb_halfedge_circulator;
using namespace std;
vector<Point_2> readInput() {
vector<Point_2> Points;
ifstream File;
File.open("polygon");
string Line;
long int Idx, XCoord, YCoord;
while (getline(File, Line)) {
istringstream Iss(Line);
Iss >> Idx >> XCoord >> YCoord;
Points.push_back({XCoord, YCoord});
}
return Points;
}
int main() {
// create environment
std::vector<Segment_2> segments;
Arrangement_2 env;
Segment_2 CurrSegment;
Polygon_2 AuxPoly;
auto Points = readInput();
auto QueryPt = Points[0];
ArrVertex_handle CurrPtHandle =
env.insert_in_face_interior(QueryPt, env.unbounded_face());
AuxPoly.push_back(Points[0]);
ArrVertex_handle NextPtHandle = CurrPtHandle;
ArrVertex_handle QueryPtHandle = CurrPtHandle;
for (auto i = 1; i < Points.size(); ++i) {
NextPtHandle = env.insert_in_face_interior(Points[i], env.unbounded_face());
CurrSegment = Segment_2(CurrPtHandle->point(), NextPtHandle->point());
env.insert_at_vertices(CurrSegment, CurrPtHandle, NextPtHandle);
CurrPtHandle = NextPtHandle;
AuxPoly.push_back(Points[i]);
}
assert(AuxPoly.is_simple());
CurrSegment = Segment_2(CurrPtHandle->point(), QueryPtHandle->point());
auto HalfEHandle =
env.insert_at_vertices(CurrSegment, CurrPtHandle, QueryPtHandle);
if (HalfEHandle->face()->is_unbounded()) {
// there are exactly two incident halfedges in the query point
auto FirstHalfE = HalfEHandle->target()->incident_halfedges();
HalfEHandle = (FirstHalfE != HalfEHandle) ? FirstHalfE : next(FirstHalfE, 1);
}
// compute non regularized visibility area
// Define visibiliy object type that computes regularized visibility area
typedef CGAL::Simple_polygon_visibility_2<Arrangement_2, CGAL::Tag_true> RSPV;
// typedef CGAL::Triangular_expansion_visibility_2<Arrangement_2, CGAL::Tag_true> RSPV;
Arrangement_2 regular_output;
RSPV regular_visibility(env);
regular_visibility.compute_visibility(QueryPtHandle->point(), HalfEHandle, regular_output);
std::cout << "Regularized visibility region of q has "
<< regular_output.number_of_edges() << " edges:" << std::endl;
for (Edge_const_iterator eit = regular_output.edges_begin();
eit != regular_output.edges_end(); ++eit)
std::cout << "[" << eit->source()->point() << " -> "
<< eit->target()->point() << "]" << std::endl;
return 0;
}
an auxiliary file arr_print.h to print the arrangement:
#ifndef _PRINT_ARR_H_
#define _PRINT_ARR_H_
#include <iostream>
//-----------------------------------------------------------------------------
// Print all neighboring vertices to a given arrangement vertex.
//
template<class Arrangement>
void print_neighboring_vertices (typename Arrangement::Vertex_const_handle v)
{
if (v->is_isolated())
{
std::cout << "The vertex (" << v->point() << ") is isolated" << std::endl;
return;
}
typename Arrangement::Halfedge_around_vertex_const_circulator first, curr;
typename Arrangement::Vertex_const_handle u;
std::cout << "The neighbors of the vertex (" << v->point() << ") are:";
first = curr = v->incident_halfedges();
do
{
// Note that the current halfedge is (u -> v):
u = curr->source();
std::cout << " (" << u->point() << ")";
++curr;
} while (curr != first);
std::cout << std::endl;
return;
}
//-----------------------------------------------------------------------------
// Print all vertices (points) and edges (curves) along a connected component
// boundary.
//
template<class Arrangement>
void print_ccb (typename Arrangement::Ccb_halfedge_const_circulator circ)
{
typename Arrangement::Ccb_halfedge_const_circulator curr = circ;
typename Arrangement::Halfedge_const_handle he;
std::cout << "(" << curr->source()->point() << ")";
do
{
he = curr;
std::cout << " [" << he->curve() << "] "
<< "(" << he->target()->point() << ")";
++curr;
} while (curr != circ);
std::cout << std::endl;
return;
}
//-----------------------------------------------------------------------------
// Print the boundary description of an arrangement face.
//
template<class Arrangement>
void print_face (typename Arrangement::Face_const_handle f)
{
// Print the outer boundary.
if (f->is_unbounded())
{
std::cout << "Unbounded face. " << std::endl;
}
else
{
std::cout << "Outer boundary: ";
print_ccb<Arrangement> (f->outer_ccb());
}
// Print the boundary of each of the holes.
typename Arrangement::Hole_const_iterator hole;
int index = 1;
for (hole = f->holes_begin(); hole != f->holes_end(); ++hole, ++index)
{
std::cout << " Hole #" << index << ": ";
print_ccb<Arrangement> (*hole);
}
// Print the isolated vertices.
typename Arrangement::Isolated_vertex_const_iterator iv;
for (iv = f->isolated_vertices_begin(), index = 1;
iv != f->isolated_vertices_end(); ++iv, ++index)
{
std::cout << " Isolated vertex #" << index << ": "
<< "(" << iv->point() << ")" << std::endl;
}
return;
}
//-----------------------------------------------------------------------------
// Print the given arrangement.
//
template<class Arrangement>
void print_arrangement (const Arrangement& arr)
{
// CGAL_precondition (arr.is_valid());
// Print the arrangement vertices.
typename Arrangement::Vertex_const_iterator vit;
std::cout << arr.number_of_vertices() << " vertices:" << std::endl;
for (vit = arr.vertices_begin(); vit != arr.vertices_end(); ++vit)
{
std::cout << "(" << vit->point() << ")";
if (vit->is_isolated())
std::cout << " - Isolated." << std::endl;
else
std::cout << " - degree " << vit->degree() << std::endl;
}
// Print the arrangement edges.
typename Arrangement::Edge_const_iterator eit;
std::cout << arr.number_of_edges() << " edges:" << std::endl;
for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit)
std::cout << "[" << eit->curve() << "]" << std::endl;
// Print the arrangement faces.
typename Arrangement::Face_const_iterator fit;
std::cout << arr.number_of_faces() << " faces:" << std::endl;
for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit)
print_face<Arrangement> (fit);
return;
}
#endif
The input polygon:
input polygon
The input file has in each line the polygon vertex id, followed by its x- and-coordinates. The query point is the one with id 1716.
Could anyone help me with this issue?
Thank you all in advance.
Related
I have written this Class as a start to build My Algorithm, but I can see Before word on console, but not After ! what is my mistake in using Dijkstra Algorithm of Boost ??
#include <myalgorithm.h>
#include<mygraphbuilder.h>
//===============================================
using namespace std;
using namespace boost;
//===============================================
MyAlgorithm::MyAlgorithm()// Default constructor
{
}
//===========================================================================
MyAlgorithm::MyAlgorithm(graph_t AnyGraph, Vertex VSource){//}, Vertex VTarget){ // Parameters Constructor
MyGraph = AnyGraph;
vector<Vertex> p(num_vertices(AnyGraph));
vector<double> d(num_edges(AnyGraph));
//===========================================================================
//Dijkstra_Algorithm
//===========================================================================
cout<<"Before\t"<<endl;
dijkstra_shortest_paths(AnyGraph, VSource,
predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, AnyGraph))).
distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, AnyGraph))));
cout<<"After\t"<<endl;
//===========================================================================
}// End of Parameters Constructor
//===========================================================================
MyAlgorithm::~MyAlgorithm(){ //Destructur
}
//===========================================================================
// Accessors
// function to call ShortPath
vector <Vertex> MyAlgorithm::getShortPath(){
return MyAlgorithm::ShortPath;
}
// function to call the Graph
graph_t MyAlgorithm::getGraph(){
return MyGraph;
}
//===========================================================================
// Mutators
//function to set short path Vector as whole
void MyAlgorithm::setShortPath(vector<Vertex> PathVector){
MyAlgorithm::ResetShortPath();
MyAlgorithm::ShortPath = PathVector;
}
//function to inject node to Short Path
void MyAlgorithm::setShortPath(Vertex MyNode){
ShortPath.emplace_back(MyNode);
}
// function to set a graph
void MyAlgorithm::setGraph(graph_t YourGraph){
MyGraph = YourGraph;
}
//============================================================================
//function to reset short path
void MyAlgorithm::ResetShortPath(){
MyAlgorithm::ShortPath.clear();
}
//function to Print Out Results
void MyAlgorithm::PrintOut(){
cout << "distances and parents:" << endl;
graph_traits < graph_t >::vertex_iterator vi, vend;
for (boost::tie(vi, vend) = vertices(MyAlgorithm::MyGraph); vi != vend; ++vi) {
vector<Vertex> p(num_vertices(MyAlgorithm::MyGraph));
vector<double> d(num_vertices(MyAlgorithm::MyGraph));
cout << "distance(" << *vi << ") = " << d[*vi] << ", ";
cout << "parent(" << *vi << ") = " << p[*vi] << endl;
} // End of Print Loop
}// end of Print Function
My Graph is defined as following :
typedef adjacency_list < vecS, vecS, directedS, property < vertex_name_t, idType >, property < edge_weight_t, double > > graph_t;
Where idType is unsigned long long int; but it didn't work, how I can Make it work ??
I don't see what the question is. Your code would simply compile, see Live On Coliru.
That said
you can probably do without copying the graph quite so many times
you should make the distance-map to number of vertices instead of edges:
std::vector<double> d(num_edges(MyGraph));
is supposed to be
std::vector<double> d(num_vertices(MyGraph));
UPDATE
To the added code in the question:
Like I said, you probably should not be copying quite so much. In particular, why does MyAlgorithm own a copy of AnyGraph as a member MyGraph? It is never used by your own constructor...
Similarly, the added code has the same problem, specifically with
for (auto v : make_iterator_range(vertices(MyGraph))) {
std::vector<Vertex> p(num_vertices(MyGraph));
std::vector<double> d(num_vertices(MyGraph));
std::cout << "distance(" << v << ") = " << d[v] << ", ";
std::cout << "parent(" << v << ") = " << p[v] << std::endl;
}
The d and p vectors are simply created with default-initialized values every iteration through the loop. What did you expect to find?
I can guess that you intended the result of dijkstra_shortest_paths to be used there, but you never did anything to make that happen. At the very least it looks like you should have made d and p member varlables
The setShortPath member functions are never used. By extension, the ShortPath member is never properly set. It seems you are aware of this because you also don't attempt to use it in PrintOut
There is a conceptual problem with printing "The Shortest Path" as it obviously depends on the target vertex... I'd write a getShortPath accessor that calculates a specific path:
Path getShortPath(Vertex destination) {
Path path;
while (destination != MyGraph.null_vertex()) {
path.push_front(destination);
if (destination == src)
return path;
if (predecessors.at(destination) == destination)
break;
destination = predecessors.at(destination);
}
throw std::runtime_error("Unreachable");
}
Now you can add a print function for any path:
void PrintPath(MyAlgorithm::Path const& path, graph_t const& g) {
std::cout << "Path: ";
auto idmap = get(boost::vertex_name, g);
auto wmap = get(boost::edge_weight, g);
auto previous = g.null_vertex();
for (auto v : path) {
if (previous != g.null_vertex()) {
for (auto e : make_iterator_range(out_edges(previous, g))) {
if (target(e, g) == v) {
std::cout << " -> (w:" << " << " << wmap[e] << ") ";
}
}
}
std::cout << "#" << v << " (id:" << idmap[v] << ") ";
previous = v;
}
std::cout << "\n";
}
It also prints weights on every edge (you will see it matches the total distance)
Fixed Demo
Here's a version that fixes all of the above. I stopped generating random graphs as now the "test cases" make assumptions about which paths are reachable:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dag_shortest_paths.hpp>
#include <boost/graph/graph_utility.hpp>
#include <iostream>
using boost::make_iterator_range;
using idType = unsigned long long;
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::directedS,
boost::property<boost::vertex_name_t, idType>,
boost::property<boost::edge_weight_t, double>> graph_t;
struct MyGraphBuilder {
void generate();
void printGraph() const;
graph_t const& getGraph() const { return MyGraph; }
graph_t& getGraph() { return MyGraph; }
private:
graph_t MyGraph;
};
void MyGraphBuilder::printGraph() const {
std::cout << "Number of Vertices is:" << num_vertices(MyGraph) << "\n";
std::cout << "Number of Edges is:" << num_edges(MyGraph) << "\n";
boost::print_graph(MyGraph, boost::get(boost::vertex_name, MyGraph), std::cout);
// to print with edge weights:
for (auto v : make_iterator_range(vertices(MyGraph))) {
for (auto oe : make_iterator_range(out_edges(v, MyGraph))) {
std::cout << "Edge " << oe << " weight " << get(boost::edge_weight, MyGraph, oe) << "\n";
}
}
}
void MyGraphBuilder::generate() {
MyGraph = graph_t(5); // clear graph, 5 vertices
auto idmap = get(boost::vertex_name, MyGraph);
idmap[0] = 0ull;
idmap[1] = 100ull;
idmap[2] = 200ull;
idmap[3] = 300ull;
idmap[4] = 400ull;
add_edge(1, 3, { 1.52275 }, MyGraph);
add_edge(2, 0, { 8.79559 }, MyGraph);
add_edge(2, 0, { 6.41004 }, MyGraph);
add_edge(3, 2, { 7.37265 }, MyGraph);
add_edge(4, 0, { 1.18526 }, MyGraph);
}
struct MyAlgorithm {
using Vertex = graph_t::vertex_descriptor;
graph_t MyGraph;
Vertex src;
std::vector<Vertex> predecessors;
std::vector<double> distances;
MyAlgorithm(graph_t const& AnyGraph, Vertex VSource)
: MyGraph(AnyGraph),
src(VSource),
predecessors(num_vertices(MyGraph)),
distances(num_vertices(MyGraph))
{
dijkstra_shortest_paths(MyGraph, src,
predecessor_map(make_iterator_property_map(predecessors.begin(), get(boost::vertex_index, MyGraph)))
.distance_map(boost::make_iterator_property_map(distances.begin(), get(boost::vertex_index, MyGraph))));
}
using Path = std::deque<Vertex>;
Path getShortPath(Vertex destination) {
Path path;
while (destination != MyGraph.null_vertex()) {
path.push_front(destination);
if (destination == src)
return path;
if (predecessors.at(destination) == destination)
break;
destination = predecessors.at(destination);
}
throw std::runtime_error("Unreachable");
}
void PrintRawData() const {
std::cout << "distances and parents:" << std::endl;
for (auto v : make_iterator_range(vertices(MyGraph))) {
std::cout << "distance(" << v << ") = " << distances.at(v) << ", ";
std::cout << "parent(" << v << ") = " << predecessors.at(v) << std::endl;
}
}
graph_t const& getGraph() const { return MyGraph; }
graph_t& getGraph() { return MyGraph; }
};
void PrintPath(MyAlgorithm::Path const& path, graph_t const& g) {
std::cout << "Path: ";
auto idmap = get(boost::vertex_name, g);
auto wmap = get(boost::edge_weight, g);
auto previous = g.null_vertex();
for (auto v : path) {
if (previous != g.null_vertex()) {
for (auto e : make_iterator_range(out_edges(previous, g))) {
if (target(e, g) == v) {
std::cout << " -> (w:" << " << " << wmap[e] << ") ";
}
}
}
std::cout << "#" << v << " (id:" << idmap[v] << ") ";
previous = v;
}
std::cout << "\n";
}
int main() {
MyGraphBuilder builder;
builder.generate();
//builder.printGraph();
MyAlgorithm algo(builder.getGraph(), 1); // 1 is first vertex, not idmap
algo.PrintRawData();
auto p0 = algo.getShortPath(0);
auto p1 = algo.getShortPath(1);
auto p2 = algo.getShortPath(2);
auto p3 = algo.getShortPath(3);
for (auto path : {p0, p1, p2, p3}) {
PrintPath(path, algo.getGraph());
}
// vertex 4 is unreachable:
try {
auto p4 = algo.getShortPath(4);
} catch(std::exception const& e) {
std::cout << "Error getting path for vertex 4: " << e.what() << "\n";
}
}
Prints
distances and parents:
distance(0) = 15.3054, parent(0) = 2
distance(1) = 0, parent(1) = 1
distance(2) = 8.8954, parent(2) = 3
distance(3) = 1.52275, parent(3) = 1
distance(4) = 1.79769e+308, parent(4) = 4
Path: #1 (id:100) -> (w: << 1.52275) #3 (id:300) -> (w: << 7.37265) #2 (id:200) -> (w: << 8.79559) -> (w: << 6.41004) #0 (id:0)
Path: #1 (id:100)
Path: #1 (id:100) -> (w: << 1.52275) #3 (id:300) -> (w: << 7.37265) #2 (id:200)
Path: #1 (id:100) -> (w: << 1.52275) #3 (id:300)
Error getting path for vertex 4: Unreachable
Following this: How to print the faces of a Voronoi diagram?, I now have:
#include <iostream>
#include <fstream>
#include <cassert>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Segment_Delaunay_graph_2.h>
#include <CGAL/Segment_Delaunay_graph_adaptation_policies_2.h>
#include <CGAL/Segment_Delaunay_graph_traits_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Segment_Delaunay_graph_traits_2<K> Gt;
typedef CGAL::Segment_Delaunay_graph_2<Gt> DT;
int main() {
std::ifstream ifs("data.cin");
assert( ifs );
DT vd;
DT::Site_2 site;
// read the sites from the stream and insert them in the diagram
while ( ifs >> site ) { vd.insert( site ); }
ifs.close();
// validate the diagram
assert( vd.is_valid(true, 1) );
std::cout << std::endl << std::endl;
// Iterate over edges
DT::Finite_edges_iterator eit = vd.finite_edges_begin();
for (int k = 1; eit != vd.finite_edges_end(); ++eit, ++k) {
DT::Edge e = *eit;
//std::cout << e << std::endl;
}
}
However, an edge cannot be printed that simply (with cout). How to do it?
Here is the error from another attempt:
/home/gsamaras/CGAL-4.7/code/DelaunayTOvoronoi/delTovor.cpp:30:27: error: ‘CGAL::Triangulation_ds_edge_iterator_2<CGAL::Triangulation_data_structure_2<CGAL::Segment_Delaunay_graph_vertex_base_2<CGAL::Segment_Delaunay_graph_storage_traits_2<CGAL::Segment_Delaunay_graph_traits_2<CGAL::Epick> >, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Segment_Delaunay_graph_face_base_2<CGAL::Segment_Delaunay_graph_traits_2<CGAL::Epick>, CGAL::Triangulation_ds_face_base_2<void> > >, true>::Edge’ has no member named ‘site’
std::cout << eit->site() << std::endl;
^
You can print the sites forming the edge like this:
for (int k = 1; eit != vd.finite_edges_end(); ++eit, ++k) {
DT::Edge e = *eit;
std::cout << "k = " << k << std::endl;
if ( vd.is_infinite(e.first->vertex( vd.ccw(e.second) )) )
std::cout << "infinite\n";
else
std::cout << e.first->vertex( vd.ccw(e.second) )->site() << std::endl;
if ( vd.is_infinite(e.first->vertex( vd.cw(e.second) )) )
std::cout << "infinite\n";
else
std::cout << e.first->vertex( vd.cw(e.second) )->site() << std::endl;
if ( vd.is_infinite(e.first->vertex( e.second )) )
std::cout << "infinite\n";
else
std::cout << e.first->vertex( e.second )->site() << std::endl;
if ( vd.is_infinite(vd.tds().mirror_vertex(e.first, e.second) ) )
std::cout << "infinite\n";
else
std::cout << vd.tds().mirror_vertex(e.first, e.second)->site() << std::endl;
}
I am trying to get a parametrized surface on a surface mesh (which is read from a STL format file.). I read some examples about parametrization provided by CGAL examples directory. I get to know that seam line should be provided in order to get a parametric surface on a arbitrary surface. But still I don't get how to make seam line. The below is my code so far. In summary, What I want to know is,
1) When CGAL::Parameterization_mesh_feature_extractor is used, how can I get vertices on the feature curves and make a seam line with the vertices?
2) Does CGAL provide a way to get intersection curve of a given surface and a cutting plane so that I can get a parametrized surface on a part of the given surface?
#include <cstdio>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <CGAL/IO/io.h>
#include <CGAL/IO/STL_reader.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <CGAL/Parameterization_polyhedron_adaptor_3.h>
#include <CGAL/Parameterization_mesh_patch_3.h>
#include <CGAL/parameterize.h>
int main(int argc, char* argv[]) {
clock_t time1, time2;
double read_time, write_time, build_time;
if(argc == 1) {
std::cout << "Please, give me a filename" << std::endl;
return 0;
}
std::ifstream infile(argv[1]);
if(infile.bad()) {
std::cout << "Infile not found or file corrupt" << std::endl;
return 1;
}
std::vector<CGAL::cpp11::array<double, 3> > points;
std::vector<CGAL::cpp11::array<int, 3> > triangles;
time1 = clock();
if (!CGAL::read_STL(infile, points, triangles)) {
std::cerr << "Error: invalid STL file" << std::endl;
return 0;
}
time2 = clock();
read_time = float(time2 - time1) / CLOCKS_PER_SEC;
fprintf(stdout, "Read time : %5.2f sec\n", read_time);
// Write polyhedron in Tecplot format
std::ofstream ofs("mesh.dat");
CGAL::set_ascii_mode(ofs);
time1 = clock();
ofs << "TITLE=\"\"" << std::endl;
ofs << "VARIABLES=\"X\" \"Y\" \"Z\"" << std::endl;
ofs << "ZONE T=\"None\" N=" << points.size() << " E=" << triangles.size() << " F=FEPOINT ET=TRIANGLE" << std::endl;
ofs.setf(std::ios::fixed);
ofs.precision(6);
for(std::vector<CGAL::cpp11::array<double, 3> >::iterator i = points.begin(); i != points.end(); ++i) {
ofs << (*i)[0] << " " << (*i)[1] << " " << (*i)[2] << std::endl;
}
for(std::vector<CGAL::cpp11::array<int, 3> >::iterator i = triangles.begin(); i != triangles.end(); ++i) {
ofs << (*i)[0]+1 << " " << (*i)[1]+1 << " " << (*i)[2]+1 << std::endl;
}
time2 = clock();
write_time = float(time2 - time1) / CLOCKS_PER_SEC;
fprintf(stdout, "Write time : %5.2f sec\n", write_time);
// build mesh
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
Polyhedron mesh;
time1 = clock();
try{
// Try building a polyhedron
CGAL::polygon_soup_to_polyhedron_3(mesh, points, triangles);
if(! mesh.is_valid() || mesh.empty()){
std::cerr << "Error: Invalid polyhedron" << std::endl;
}
}
catch(...){}
time2 = clock();
build_time= float(time2 - time1) / CLOCKS_PER_SEC;
fprintf(stdout, "Build time : %5.2f sec\n", build_time);
// parameterization
typedef CGAL::Parameterization_polyhedron_adaptor_3<Polyhedron> Parameterization_polyhedron_adaptor;
// Type describing a border or seam as a vertex list
typedef std::list<Parameterization_polyhedron_adaptor::Vertex_handle> Seam;
//Create a second adaptor that virtually "cuts" the mesh following the 'seam' path
typedef CGAL::Parameterization_mesh_patch_3<Parameterization_polyhedron_adaptor> Mesh_patch_polyhedron;
Parameterization_polyhedron_adaptor mesh_adaptor(mesh);
////////////////////// cut graph ////////////////////////////////
typedef CGAL::Parameterization_mesh_feature_extractor<Parameterization_polyhedron_adaptor>
Mesh_feature_extractor;
Seam seam;
// Get reference to Polyhedron_3 mesh
Polyhedron& mesh_ref = mesh_adaptor.get_adapted_mesh();
// Extract mesh borders and compute genus
Mesh_feature_extractor feature_extractor(mesh_adaptor);
int nb_borders = feature_extractor.get_nb_borders();
int genus = feature_extractor.get_genus(); // genus means a hole inside a surface
std::cout << "# borders: " << nb_borders << " # holes: " << genus << std::endl;
std::cout << feature_extractor.get_borders()[0] << std::endl;
///////////////////// end of cut graph //////////////////////////
/*
Mesh_patch_polyhedron mesh_patch(mesh_adaptor, seam.begin(), seam.end());
if (!mesh_patch.is_valid())
{
std::cerr << "Input mesh not supported: non manifold shape or invalid cutting" << std::endl;
return EXIT_FAILURE;
}
typedef CGAL::Parameterizer_traits_3<Mesh_patch_polyhedron> Parameterizer; // Type that defines the error codes
Parameterizer::Error_code err = CGAL::parameterize(mesh_patch);
switch(err) {
case Parameterizer::OK: // Success
break;
case Parameterizer::ERROR_EMPTY_MESH: // Input mesh not supported
case Parameterizer::ERROR_NON_TRIANGULAR_MESH:
case Parameterizer::ERROR_NO_TOPOLOGICAL_DISC:
case Parameterizer::ERROR_BORDER_TOO_SHORT:
std::cerr << "Input mesh not supported: " << Parameterizer::get_error_message(err) << std::endl;
return EXIT_FAILURE;
break;
default: // Error
std::cerr << "Error: " << Parameterizer::get_error_message(err) << std::endl;
return EXIT_FAILURE;
break;
};
// Raw output: dump (u,v) pairs
Polyhedron::Vertex_const_iterator pVertex;
for (pVertex = mesh.vertices_begin(); pVertex != mesh.vertices_end(); pVertex++)
{
// (u,v) pair is stored in any halfedge
double u = mesh_adaptor.info(pVertex->halfedge())->uv().x();
double v = mesh_adaptor.info(pVertex->halfedge())->uv().y();
std::cout << "(u,v) = (" << u << "," << v << ")" << std::endl;
}
*/
return 0;
}
I have never used CGAL and have got almost no C/C++ experience. But following
Google I have however managed to compile the example "Alpha_shapes_3"
(\CGAL-4.1-beta1\examples\Alpha_shapes_3) on a Windows 7 64bit machine using
visual studio 2010.
Now if we check the source code for the program "ex_alpha_shapes_3" we
notice that a data file called "bunny_1000" is red where the 3d point
cluster resides.
Now my question is how can I change the source code so that after the alpha
shape is computed for the given points, surface mesh of the alpha shape is
saved/wrote in an external file. It can be simply the list of polygons and
their respective 3D vertices. I guess these polygons will be defining the
surface mesh of the alpha shape. If I can do that I can see the output of
the alpha shape generation program in an external tool I am familiar with.
I know this is very straightforward but I could not figure this out with my
limited knowledge of CGAL.
I know you gueys have the code but I am pasting it again for completion.
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Alpha_shape_3.h>
#include <fstream>
#include <list>
#include <cassert>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Gt;
typedef CGAL::Alpha_shape_vertex_base_3<Gt> Vb;
typedef CGAL::Alpha_shape_cell_base_3<Gt> Fb;
typedef CGAL::Triangulation_data_structure_3<Vb,Fb> Tds;
typedef CGAL::Delaunay_triangulation_3<Gt,Tds> Triangulation_3;
typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3;
typedef Gt::Point_3 Point;
typedef Alpha_shape_3::Alpha_iterator Alpha_iterator;
int main()
{
std::list<Point> lp;
//read input
std::ifstream is("./data/bunny_1000");
int n;
is >> n;
std::cout << "Reading " << n << " points " << std::endl;
Point p;
for( ; n>0 ; n--) {
is >> p;
lp.push_back(p);
}
// compute alpha shape
Alpha_shape_3 as(lp.begin(),lp.end());
std::cout << "Alpha shape computed in REGULARIZED mode by default"
<< std::endl;
// find optimal alpha value
Alpha_iterator opt = as.find_optimal_alpha(1);
std::cout << "Optimal alpha value to get one connected component is "
<< *opt << std::endl;
as.set_alpha(*opt);
assert(as.number_of_solid_components() == 1);
return 0;
}
After searching a lot in the internet I found that probably we need to use something like
std::list<Facet> facets;
alpha_shape.get_alpha_shape_facets
(
std::back_inserter(facets),Alpha_shape::REGULAR
);
But I am still completely clueless how to use this in the above code!
As documented here, a facet is a pair (Cell_handle c,int i) defined as the facet in c opposite to the vertex of index i.
On this page, you have the description of how the vertex indices of a cell are.
In the following code sample, I added a small output that prints an OFF file on cout by duplicating the vertices. To do something clean, you can either use a std::map<Alpha_shape_3::Vertex_handle,int> to associate a unique index per vertex or add an info to the vertices like in those examples.
/// collect all regular facets
std::vector<Alpha_shape_3::Facet> facets;
as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::REGULAR);
std::stringstream pts;
std::stringstream ind;
std::size_t nbf=facets.size();
for (std::size_t i=0;i<nbf;++i)
{
//To have a consistent orientation of the facet, always consider an exterior cell
if ( as.classify( facets[i].first )!=Alpha_shape_3::EXTERIOR )
facets[i]=as.mirror_facet( facets[i] );
CGAL_assertion( as.classify( facets[i].first )==Alpha_shape_3::EXTERIOR );
int indices[3]={
(facets[i].second+1)%4,
(facets[i].second+2)%4,
(facets[i].second+3)%4,
};
/// according to the encoding of vertex indices, this is needed to get
/// a consistent orienation
if ( facets[i].second%2==0 ) std::swap(indices[0], indices[1]);
pts <<
facets[i].first->vertex(indices[0])->point() << "\n" <<
facets[i].first->vertex(indices[1])->point() << "\n" <<
facets[i].first->vertex(indices[2])->point() << "\n";
ind << "3 " << 3*i << " " << 3*i+1 << " " << 3*i+2 << "\n";
}
std::cout << "OFF "<< 3*nbf << " " << nbf << " 0\n";
std::cout << pts.str();
std::cout << ind.str();
Here is my code, which outputs vtk file for visualization in Paraview. Comparing with slorior's solutions, no duplicated points are saved in the file. But my code is just for the visualization, if you need to figure out the exterior or interior simplexes, you should modify the code to get these results.
void writevtk(Alpha_shape_3 &as, const std::string &asfile) {
// http://cgal-discuss.949826.n4.nabble.com/Help-with-filtration-and-filtration-with-alpha-values-td4659524.html#a4659549
std::cout << "Information of the Alpha_Complex:\n";
std::vector<Alpha_shape_3::Cell_handle> cells;
std::vector<Alpha_shape_3::Facet> facets;
std::vector<Alpha_shape_3::Edge> edges;
// tetrahedron = cell, they should be the interior, it is inside the 3D space
as.get_alpha_shape_cells(std::back_inserter(cells), Alpha_shape_3::INTERIOR);
// triangles
// for the visualiization, don't need regular because tetrahedron will show it
//as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::REGULAR);
as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::SINGULAR);
// edges
as.get_alpha_shape_edges(std::back_inserter(edges), Alpha_shape_3::SINGULAR);
std::cout << "The alpha-complex has : " << std::endl;
std::cout << cells.size() << " cells as tetrahedrons" << std::endl;
std::cout << facets.size() << " triangles" << std::endl;
std::cout << edges.size() << " edges" << std::endl;
size_t tetra_num, tri_num, edge_num;
tetra_num = cells.size();
tri_num = facets.size();
edge_num = edges.size();
// vertices: points <-> id
std::map<Point, size_t> points;
size_t index = 0;
// finite_.. is from DT class
for (auto v_it = as.finite_vertices_begin(); v_it != as.finite_vertices_end(); v_it++) {
points[v_it->point()] = index;
index++;
}
// write
std::ofstream of(asfile);
of << "# vtk DataFile Version 2.0\n\nASCII\nDATASET UNSTRUCTURED_GRID\n\n";
of << "POINTS " << index << " float\n";
for (auto v_it = as.finite_vertices_begin(); v_it != as.finite_vertices_end(); v_it++) {
of << v_it->point() << std::endl;
}
of << std::endl;
of << "CELLS " << tetra_num + tri_num + edge_num << " " << 5 * tetra_num + 4 * tri_num + 3 * edge_num << std::endl;
for (auto cell:cells) {
size_t v0 = points.find(cell->vertex(0)->point())->second;
size_t v1 = points.find(cell->vertex(1)->point())->second;
size_t v2 = points.find(cell->vertex(2)->point())->second;
size_t v3 = points.find(cell->vertex(3)->point())->second;
of << "4 " << v0 << " " << v1 << " " << v2 << " " << v3 << std::endl;
}
// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#ad6a20b45e66dfb690bfcdb8438e9fcae
for (auto tri_it = facets.begin(); tri_it != facets.end(); ++tri_it) {
of << "3 ";
auto tmp_tetra = tri_it->first;
for (int i = 0; i < 4; i++) {
if (i != tri_it->second) {
of << points.find(tmp_tetra->vertex(i)->point())->second << " ";
}
}
of << std::endl;
}
// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#af31db7673a6d7d28c0bb90a3115ac695
for (auto e : edges) {
of << "2 ";
auto tmp_tetra = e.get<0>();
int p1, p2;
p1 = e.get<1>();
p2 = e.get<2>();
of << points.find(tmp_tetra->vertex(p1)->point())->second << " "
<< points.find(tmp_tetra->vertex(p2)->point())->second << std::endl;
}
of << std::endl;
of << "CELL_TYPES " << tetra_num + tri_num + edge_num << std::endl;
for (int i = 0; i < tetra_num; i++) {
of << "10 ";
}
for (int i = 0; i < tri_num; i++) {
of << "5 ";
}
for (int i = 0; i < edge_num; i++) {
of << "3 ";
}
of << std::endl;
of.close();
}
First part of the question is that I am trying to use boost::bimap, but from the documentation it is unclear to me how to define a bidirectional multimap.
The second part of the question is that I need it to be a map in one direction and a multimap in the other direction, can this be done using boost::bimap ?
Has anyone experience of this or can point me to the correct page ?
All is in documentation... http://www.boost.org/doc/libs/1_51_0/libs/bimap/doc/html/boost_bimap/the_tutorial/discovering_the_bimap_framework.html
typedef boost::bimap<bimaps::multiset_of<int>, bimaps::set_of<int>> bimap_t;
Example.
#include <iostream>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
namespace bimaps = boost::bimaps;
int main()
{
typedef boost::bimap<bimaps::multiset_of<int>, bimaps::set_of<int>> bimap_t;
typedef bimap_t::value_type value_type;
bimap_t bimap;
bimap.insert(value_type(1, 1));
bimap.insert(value_type(1, 2));
auto& left = bimap.left;
auto it = left.find(1);
std::cout << "LEFT" << std::endl;
for (; it != left.end(); ++it)
{
std::cout << it->first << " " << it->second << std::endl;
}
auto& right = bimap.right;
auto r_it = right.find(2);
std::cout << "RIGHT" << std::endl;
for (; r_it != right.end(); ++r_it)
{
std::cout << r_it->first << " " << r_it->second << std::endl;
}
}
The answer from ForEverR is partially correct for the first part of your question (how to define a bidirectional multimap?).
For the second part (accessing a bimap which is a map in one direction and a multimap in the other direction) It is not correct.
A correct way to access would be [ http://rextester.com/BXBDHN12336 ]:
//bimap operations
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
int main()
{
typedef boost::bimap<boost::bimaps::multiset_of<int>, boost::bimaps::set_of<int>> bimap_t;
typedef bimap_t::value_type value_type;
bimap_t bimap;
bimap.insert(value_type(1, 1));
bimap.insert(value_type(10, 50));
bimap.insert(value_type(1, 2));
bimap.insert(value_type(9, 15));
typedef bimap_t::left_const_iterator l_itr_t;
typedef std::pair<l_itr_t,l_itr_t> l_itr_range_t;
l_itr_range_t ii = bimap.left.equal_range(1);
std::cout << "LEFT" << std::endl;
for(l_itr_t it = ii.first; it != ii.second; ++it)
{
std::cout << "Key = " << it->first << " Value = " << it->second << std::endl;
}
std::cout << "RIGHT" << std::endl;
std::cout << "Key = " << 1 << " Value = " << bimap.right.at(1) << std::endl;
}
stdout:
LEFT
Key = 1 Value = 1
Key = 1 Value = 2
RIGHT
Key = 1 Value = 1
The example from ForEverR 'seems' to work because of the order of the data inserted but check out the results when you insert another couple at the end bimap.insert(value_type(9, 15));:
#include <iostream>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
namespace bimaps = boost::bimaps;
int main()
{
typedef boost::bimap<bimaps::multiset_of<int>, bimaps::set_of<int>> bimap_t;
typedef bimap_t::value_type value_type;
bimap_t bimap;
bimap.insert(value_type(1, 1));
bimap.insert(value_type(1, 2));
bimap.insert(value_type(9, 15));
auto& left = bimap.left;
auto it = left.find(1);
std::cout << "LEFT" << std::endl;
for (; it != left.end(); ++it)
{
std::cout << it->first << " " << it->second << std::endl;
}
auto& right = bimap.right;
auto r_it = right.find(2);
std::cout << "RIGHT" << std::endl;
for (; r_it != right.end(); ++r_it)
{
std::cout << r_it->first << " " << r_it->second << std::endl;
}
}
stdout:
LEFT
1 1
1 2
9 15
RIGHT
2 1
15 9