Add Vanessa Robins' periodic alpha shapes 2D code
authorDmitriy Morozov <dmitriy@mrzv.org>
Sun, 26 Nov 2017 12:07:49 -0800
changeset 291 5d387c35465b
parent 290 21b56c6c9512
child 292 b90319e7126f
Add Vanessa Robins' periodic alpha shapes 2D code
examples/alphashapes/CMakeLists.txt
examples/alphashapes/alphashapes2d-periodic.cpp
examples/alphashapes/alphashapes2d-periodic.h
examples/alphashapes/alphashapes2d-periodic.hpp
--- a/examples/alphashapes/CMakeLists.txt	Thu Sep 07 17:35:28 2017 -0700
+++ b/examples/alphashapes/CMakeLists.txt	Sun Nov 26 12:07:49 2017 -0800
@@ -14,6 +14,7 @@
                                                                 alphashapes2d
                                                                 alphashapes3d-cohomology
                                                                 alphashapes3d-periodic
+                                                                alphashapes2d-periodic
                                                                 #alpharadius
                                 )
     add_definitions             (${CGAL_CXX_FLAGS_INIT})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d-periodic.cpp	Sun Nov 26 12:07:49 2017 -0800
@@ -0,0 +1,120 @@
+#include <utilities/log.h>
+
+#include "alphashapes2d-periodic.h"
+#include <topology/filtration.h>
+#include <topology/static-persistence.h>
+#include <topology/persistence-diagram.h>
+#include <iostream>
+
+#include <fstream>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/serialization/map.hpp>
+
+#include <boost/program_options.hpp>
+
+
+typedef Filtration<AlphaSimplex2D>              AlphaFiltration;
+typedef StaticPersistence<>                     Persistence;
+typedef PersistenceDiagram<>                    PDgm;
+
+namespace po = boost::program_options;
+
+int main(int argc, char** argv) 
+{
+#ifdef LOGGING
+    rlog::RLogInit(argc, argv);
+
+    stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+    stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/filtration") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/cycle") );
+#endif
+
+    //SetFrequency(GetCounter("filtration/pair"), 10000);
+    //SetTrigger(GetCounter("filtration/pair"), GetCounter(""));
+
+    std::string     infilename, outfilename;
+    
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+    ("input-file",   po::value<std::string>(&infilename),     "Point set whose alpha shape filtration and persistence we want to compute")
+    ("output-file",  po::value<std::string>(&outfilename),    "Where to write the collection of persistence diagrams");
+    
+    po::positional_options_description pos;
+    pos.add("input-file", 1);
+    pos.add("output-file", 2);
+    
+    po::options_description all; all.add(hidden);
+    
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+              options(all).positional(pos).run(), vm);
+    po::notify(vm);
+    
+    if (!vm.count("input-file") || !vm.count("output-file"))
+    {
+        std::cout << "Usage: " << argv[0] << " input-file output-file" << std::endl;
+        std::cout << hidden << std::endl;
+        return 1;
+    }
+
+
+    // Read in the point set and compute its Delaunay triangulation
+    std::ifstream in(infilename.c_str());
+    double x,y;
+    
+    
+    // VR: The first two "points" from the input file must define the antipodal corners of the periodic domain.
+    // The periodic domain must be a square.
+    double a,b,c,d;
+    in >> a >> b >> c >> d;
+
+    Delaunay2D Dt(GT::Iso_rectangle_2(a,b,c,d));
+
+        
+    while(in)
+    {
+        in >> x >> y;
+        // if (!in) break;
+        Point p(x,y);
+        Dt.insert(p);
+    }
+    
+    // VR: Switch to 1-sheeted cover if possible
+    if (Dt.is_triangulation_in_1_sheet())
+        Dt.convert_to_1_sheeted_covering();
+    else
+        std::cout << "Periodic Triangulation not in one sheet. There may be problems ahead" << std::endl;
+    
+    rInfo("Delaunay triangulation computed");
+   
+    AlphaFiltration af;
+    fill_complex(Dt, af);
+    rInfo("Simplices: %i", af.size());
+
+    // Create the alpha-shape filtration
+    af.sort(AlphaSimplex2D::AlphaOrder());
+    rInfo("Filtration initialized");
+
+    Persistence p(af);
+    rInfo("Persistence initializaed");
+
+    p.pair_simplices();
+    rInfo("Simplices paired");
+
+    Persistence::SimplexMap<AlphaFiltration>    m       = p.make_simplex_map(af);
+    std::map<Dimension, PDgm>                   dgms;
+    init_diagrams(dgms, p.begin(), p.end(), 
+                  evaluate_through_map(m, AlphaSimplex2D::AlphaValueEvaluator()),
+                  evaluate_through_map(m, AlphaSimplex2D::DimensionExtractor()));
+
+#if 0
+    std::cout << 0 << std::endl << dgms[0] << std::endl;
+    std::cout << 1 << std::endl << dgms[1] << std::endl;
+#endif
+    
+    std::ofstream ofs(outfilename.c_str());
+    boost::archive::binary_oarchive oa(ofs);
+    oa << dgms;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d-periodic.h	Sun Nov 26 12:07:49 2017 -0800
@@ -0,0 +1,103 @@
+/**
+ * Author: Dmitriy Morozov
+ * Department of Computer Science, Duke University, 2007
+ *
+ * Modified by Vanessa Robins, ANU, November 2017 to use
+ * Delaunay triangulations built with periodic boundary conditions
+ *
+ */
+
+#ifndef __ALPHASHAPES2D_H__
+#define __ALPHASHAPES2D_H__
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+// #include <CGAL/Delaunay_triangulation_2.h>
+// VR: replaced with
+#include <CGAL/Periodic_2_triangulation_traits_2.h>
+#include <CGAL/Periodic_2_Delaunay_triangulation_2.h>
+
+
+#include <topology/simplex.h>
+#include <utilities/types.h>
+
+#include <vector>
+#include <set>
+#include <iostream>
+
+struct K: CGAL::Exact_predicates_exact_constructions_kernel {};
+
+//typedef CGAL::Delaunay_triangulation_2<K>           Delaunay2D;
+// VR: replaced with
+typedef CGAL::Periodic_2_triangulation_traits_2<K> GT;
+typedef CGAL::Periodic_2_Delaunay_triangulation_2<GT>  Delaunay2D;
+
+typedef Delaunay2D::Point                           Point;
+typedef Delaunay2D::Vertex_handle                   Vertex_handle;
+typedef Delaunay2D::Face_handle                     Face_handle;
+
+typedef K::FT                                       RealValue;
+
+// VR: had to change iterator typedefs from Finite_blah_iterator to Blah_iterator. 
+//typedef Delaunay2D::Finite_vertices_iterator        Vertex_iterator;
+//typedef Delaunay2D::Finite_edges_iterator           Edge_iterator;
+//typedef Delaunay2D::Finite_faces_iterator           Face_iterator;
+
+typedef Delaunay2D::Vertex_iterator     Vertex_iterator;
+typedef Delaunay2D::Edge_iterator       Edge_iterator;
+typedef Delaunay2D::Face_iterator       Face_iterator;
+
+
+class AlphaSimplex2D: public Simplex<Vertex_handle>
+{
+    public:
+        typedef     Simplex<Vertex_handle>                              Parent;
+        typedef     std::set<AlphaSimplex2D, Parent::VertexComparison>  SimplexSet;
+        typedef     Parent::VertexContainer                             VertexSet;
+
+    public:
+                                    AlphaSimplex2D()                    {}
+                                    AlphaSimplex2D(const Parent& p): 
+                                            Parent(p)                   {}
+                                    AlphaSimplex2D(const AlphaSimplex2D& s): 
+                                            Parent(s)                   { attached_ = s.attached_; alpha_ = s.alpha_; }
+                                    AlphaSimplex2D(const Delaunay2D::Vertex& v);
+        
+                                    AlphaSimplex2D(const Delaunay2D::Edge& e);
+                                    AlphaSimplex2D(const Delaunay2D::Edge& e, const SimplexSet& simplices, const Delaunay2D& Dt,  const RealValue r);
+        
+                                    AlphaSimplex2D(const Delaunay2D::Face& f);
+                                    AlphaSimplex2D(const Delaunay2D::Face& f,  const RealValue r); 
+        
+        RealType                    value() const                       { return CGAL::to_double(alpha_); }
+        RealValue                   alpha() const                       { return alpha_; }
+        bool                        attached() const                    { return attached_; }
+
+        // Ordering
+        struct AlphaOrder
+        { bool operator()(const AlphaSimplex2D& first, const AlphaSimplex2D& second) const; };
+        
+        struct AlphaValueEvaluator
+        { 
+            typedef                 AlphaSimplex2D                                  first_argument_type;
+            typedef                 RealType                                        result_type;
+
+            RealType                operator()(const AlphaSimplex2D& s) const       { return s.value(); }
+        };
+
+        std::ostream&               operator<<(std::ostream& out) const;
+        
+    private:
+        RealValue                   alpha_;
+        bool                        attached_;
+};
+
+typedef             std::vector<AlphaSimplex2D>                             AlphaSimplex2DVector;
+void                fill_simplex_set(const Delaunay2D& Dt, AlphaSimplex2D::SimplexSet& simplices);
+template<class Filtration>
+void                fill_complex(const Delaunay2D& Dt,     Filtration& filtration);
+
+std::ostream&       operator<<(std::ostream& out, const AlphaSimplex2D& s)  { return s.operator<<(out); }
+
+#include "alphashapes2d-periodic.hpp"
+
+#endif // __ALPHASHAPES2D_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d-periodic.hpp	Sun Nov 26 12:07:49 2017 -0800
@@ -0,0 +1,211 @@
+#include <utilities/log.h>
+#include <boost/foreach.hpp>
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Vertex& v): alpha_(0), attached_(false)
+{
+    for (int i = 0; i < 3; ++i)
+        if (v.face()->vertex(i) != Vertex_handle() && v.face()->vertex(i)->point() == v.point())
+            Parent::add(v.face()->vertex(i));
+}
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Edge& e): attached_(false)
+{
+    Face_handle f = e.first;
+    for (int i = 0; i < 3; ++i)
+        if (i != e.second)
+            Parent::add(f->vertex(i));
+}
+
+// AlphaSimplex2D::
+// AlphaSimplex2D(const Delaunay2D::Edge& e, const SimplexSet& simplices, const Delaunay2D& Dt): attached_(false)
+// {
+//     Face_handle f = e.first;
+//     for (int i = 0; i < 3; ++i)
+//         if (i != e.second)
+//             Parent::add(f->vertex(i));
+// 
+//     VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+//     const Point& p1 = (*v++)->point();
+//     const Point& p2 = (*v)->point();
+// 
+//     Face_handle o = f->neighbor(e.second);
+//     if (o == Face_handle())
+//     {
+//         alpha_ = CGAL::squared_radius(p1, p2);
+//         return;
+//     }
+//     int oi = o->index(f);
+// 
+//     attached_ = false;
+//     if (!Dt.is_infinite(f->vertex(e.second)) &&
+//         CGAL::side_of_bounded_circle(p1, p2,
+//                                      f->vertex(e.second)->point()) == CGAL::ON_BOUNDED_SIDE)
+//         attached_ = true;
+//     else if (!Dt.is_infinite(o->vertex(oi)) &&
+//              CGAL::side_of_bounded_circle(p1, p2,
+//                                           o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE)
+//         attached_ = true;
+//     else
+//         alpha_ = CGAL::squared_radius(p1, p2);
+// 
+//     if (attached_)
+//     {
+//         if (Dt.is_infinite(f))
+//             alpha_ = simplices.find(AlphaSimplex2D(*o))->alpha();
+//         else if (Dt.is_infinite(o))
+//             alpha_ = simplices.find(AlphaSimplex2D(*f))->alpha();
+//         else
+//             alpha_ = std::min(simplices.find(AlphaSimplex2D(*f))->alpha(),
+//                               simplices.find(AlphaSimplex2D(*o))->alpha());
+//     }
+// }
+
+// VR modified for periodic DT 
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Edge& e, const SimplexSet& simplices, const Delaunay2D& Dt, const RealValue r): attached_(false)
+{
+    Face_handle f = e.first;
+    for (int i = 0; i < 3; ++i)
+        if (i != e.second)
+            Parent::add(f->vertex(i));
+
+    Face_handle o = f->neighbor(e.second);
+    int oi = o->index(f);
+    alpha_ = r; 
+
+    attached_ = false;
+// First check if the circle centred on the edge contains its f-opposite vertex
+	Point fpt = Dt.point(Dt.periodic_point(e.first,e.second));
+	Delaunay2D::Segment fseg = Dt.segment(e.first,e.second);
+	if (CGAL::side_of_bounded_circle(fseg[0],fseg[1],fpt) == CGAL::ON_BOUNDED_SIDE)
+		attached_ = true;
+
+// Then check if the circle centred on the edge contains its o-opposite vertex. 	
+	Point opt = Dt.point(Dt.periodic_point(o,oi)); 
+	Delaunay2D::Segment oseg = Dt.segment(o,oi);
+	if (CGAL::side_of_bounded_circle(oseg[0],oseg[1],opt) == CGAL::ON_BOUNDED_SIDE)
+		attached_ = true;
+
+
+    if (attached_)
+    {
+    	//std::cout << "found an attached edge" << std::endl;
+    	alpha_ = std::min(simplices.find(AlphaSimplex2D(*f))->alpha(),
+                              simplices.find(AlphaSimplex2D(*o))->alpha());
+    }
+}
+
+// AlphaSimplex2D::
+// AlphaSimplex2D(const Delaunay2D::Face& f): attached_(false)
+// {
+//     for (int i = 0; i < 3; ++i)
+//         Parent::add(f.vertex(i));
+//     VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+//     Point p1 = (*v++)->point();
+//     Point p2 = (*v++)->point();
+//     Point p3 = (*v)->point();
+//     alpha_ = CGAL::squared_radius(p1, p2, p3);
+// }
+
+// VR: new initialisation for periodic DT faces. 
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Face& f)
+{
+    for (int i = 0; i < 3; ++i)
+        Parent::add(f.vertex(i));
+}
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Face& f, const RealValue r): attached_(false)
+{
+    for (int i = 0; i < 3; ++i)
+        Parent::add(f.vertex(i));
+
+    alpha_ = r;
+}
+
+
+bool
+AlphaSimplex2D::AlphaOrder::
+operator()(const AlphaSimplex2D& first, const AlphaSimplex2D& second) const
+{
+    if (first.alpha() == second.alpha())
+        return (first.dimension() < second.dimension());
+    else
+        return (first.alpha() < second.alpha());
+}
+
+std::ostream&
+AlphaSimplex2D::
+operator<<(std::ostream& out) const
+{
+    for (VertexSet::const_iterator cur = Parent::vertices().begin();
+                                   cur != Parent::vertices().end(); ++cur)
+        out << **cur << ", ";
+    out << "value = " << value();
+
+    return out;
+}
+
+// void fill_simplex_set(const Delaunay2D& Dt, AlphaSimplex2D::SimplexSet& simplices)
+// {
+//     for(Face_iterator cur = Dt.finite_faces_begin(); cur != Dt.finite_faces_end(); ++cur)
+//         simplices.insert(AlphaSimplex2D(*cur));
+//     rInfo("Faces inserted");
+//     for(Edge_iterator cur = Dt.finite_edges_begin(); cur != Dt.finite_edges_end(); ++cur)
+//         simplices.insert(AlphaSimplex2D(*cur, simplices, Dt));
+//     rInfo("Edges inserted");
+//     for(Vertex_iterator cur = Dt.finite_vertices_begin(); cur != Dt.finite_vertices_end(); ++cur)
+//         simplices.insert(AlphaSimplex2D(*cur));
+//     rInfo("Vertices inserted");
+// }
+
+//VR: modified function for periodic DT
+
+void fill_simplex_set(const Delaunay2D& Dt, AlphaSimplex2D::SimplexSet& simplices)
+{
+    // Compute all simplices with their alpha values and attachment information
+	int counter = 0;
+    for(Face_iterator cur = Dt.faces_begin(); cur != Dt.faces_end(); ++cur){
+        //Delaunay2D::Periodic_triangle ptri = Dt.periodic_triangle(cur);
+        //Delaunay2D::Triangle tri = Dt.triangle(ptri);
+        Delaunay2D::Triangle tri = Dt.triangle(cur);
+        RealValue sqrad = CGAL::squared_radius(tri[0], tri[1], tri[2]);
+        simplices.insert(AlphaSimplex2D(*cur, sqrad));
+        counter++;
+    }
+    //std::cout << "Number of triangles inserted in filtration " << counter << std::endl;  
+    rInfo("Facets inserted");
+    counter = 0;
+    for(Edge_iterator cur = Dt.edges_begin(); cur != Dt.edges_end(); ++cur){
+        //Delaunay2D::Periodic_segment pseg = Dt.periodic_segment(*cur);
+        //Delaunay2D::Segment seg = Dt.segment(pseg);
+        Delaunay2D::Segment seg = Dt.segment(cur);
+        RealValue sqrad = CGAL::squared_radius(seg[0],seg[1]);
+        simplices.insert(AlphaSimplex2D(*cur, simplices, Dt, sqrad));
+        counter++;
+    }
+    //std::cout << "Number of edges inserted in filtration " << counter << std::endl;  
+    rInfo("Edges inserted");      
+    for(Vertex_iterator cur = Dt.vertices_begin(); cur != Dt.vertices_end(); ++cur)
+        simplices.insert(AlphaSimplex2D(*cur));
+    rInfo("Vertices inserted");
+    
+}
+
+
+
+template<class Filtration>
+void fill_complex(const Delaunay2D& Dt, Filtration& filtration)
+{
+    // Compute all simplices with their alpha values and attachment information
+    // TODO: this can be optimized; the new Filtration can act as a SimplexSet
+    AlphaSimplex2D::SimplexSet simplices;
+    fill_simplex_set(Dt, simplices);
+    BOOST_FOREACH(const AlphaSimplex2D& s, simplices)
+        filtration.push_back(s);
+}
+