{"action":"created","comment":{"url":"https://api.github.com/repos/CGAL/cgal/pulls/comments/43357411","id":43357411,"diff_hunk":"@@ -0,0 +1,851 @@\n+#include <QTime>\n+#include <QApplication>\n+#include <QAction>\n+#include <QList>\n+#include <QMainWindow>\n+#include <QObject>\n+\n+#include <fstream>\n+\n+#include \"Scene_polygon_soup_item.h\"\n+#include \"Scene_polyhedron_item.h\"\n+#include \"Scene_points_with_normal_item.h\"\n+#include \"Polyhedron_type.h\"\n+#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>\n+#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>\n+\n+#include <CGAL/array.h>\n+#include <CGAL/centroid.h>\n+#include <CGAL/PCA_util.h>\n+#include <CGAL/Search_traits_3.h>\n+#include <CGAL/squared_distance_3.h>\n+#include <CGAL/Orthogonal_k_neighbor_search.h>\n+#include <CGAL/Default_diagonalize_traits.h>\n+#include <CGAL/compute_average_spacing.h>\n+#include <CGAL/grid_simplify_point_set.h>\n+#include <CGAL/jet_smooth_point_set.h>\n+#include <CGAL/jet_estimate_normals.h>\n+#include <CGAL/mst_orient_normals.h>\n+#include <CGAL/Scale_space_surface_reconstruction_3.h>\n+#include <CGAL/Advancing_front_surface_reconstruction.h>\n+\n+#include \"ui_Polyhedron_demo_surface_reconstruction_plugin.h\"\n+\n+// Concurrency\n+#ifdef CGAL_LINKED_WITH_TBB\n+typedef CGAL::Parallel_tag Concurrency_tag;\n+#else\n+typedef CGAL::Sequential_tag Concurrency_tag;\n+#endif\n+\n+\n+// Poisson reconstruction method:\n+// Reconstructs a surface mesh from a point set and returns it as a polyhedron.\n+Polyhedron* poisson_reconstruct(const Point_set& points,\n+                                Kernel::FT sm_angle, // Min triangle angle (degrees). \n+                                Kernel::FT sm_radius, // Max triangle size w.r.t. point set average spacing. \n+                                Kernel::FT sm_distance, // Approximation error w.r.t. point set average spacing.\n+                                const QString& solver, // solver name\n+                                bool use_two_passes,\n+\t\t\t\tbool do_not_fill_holes);\n+\n+\n+struct Radius {\n+\n+  double bound;\n+\n+  Radius(double bound)\n+    : bound(bound)\n+  {}\n+\n+  bool operator()(const Kernel::Point_3& p, const Kernel::Point_3& q, const Kernel::Point_3& r) const\n+  {\n+    if(bound == 0){\n+      return false;\n+    }\n+    double d  = sqrt(squared_distance(p,q));\n+    if(d>bound) return true;\n+    d = sqrt(squared_distance(p,r)) ;\n+    if(d>bound) return true;\n+    d = sqrt(squared_distance(q,r));\n+    return d>bound;\n+  }\n+};\n+\n+\n+namespace SurfaceReconstruction\n+{\n+  typedef Kernel::Point_3 Point;\n+  typedef Kernel::Vector_3 Vector;\n+  // types for K nearest neighbors search\n+  typedef CGAL::Search_traits_3<Kernel> Tree_traits;\n+  typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;\n+  typedef Neighbor_search::Tree Tree;\n+  typedef Neighbor_search::iterator Search_iterator;\n+\n+  typedef CGAL::Scale_space_surface_reconstruction_3<Kernel> ScaleSpace;\n+  \n+  template <typename OutputIterator>\n+  void generate_scales (OutputIterator out,\n+\t\t\tconst unsigned int scale_min = 6,\n+\t\t\tconst double factor = 1.15,\n+\t\t\tunsigned int nb_scales = 30)\n+  {\n+    unsigned int prev = -1;\n+    \n+    for (unsigned int i = 0; i < nb_scales; ++ i)\n+      {\n+\tunsigned int current = static_cast<unsigned int>(scale_min * std::pow (factor, i));\n+\tif (current != prev)\n+\t  {\n+\t    *(out ++) = current;\n+\t    prev = current;\n+\t  }\n+\telse\n+\t  ++ nb_scales;\n+      }\n+  }\n+  \n+  unsigned int scale_of_anisotropy (const Point_set& points, double& size)\n+  {\n+    Tree tree(points.begin(), points.end());\n+    \n+    double ratio_kept = (points.size() < 1000)\n+      ? 1. : 1000. / (points.size());\n+    \n+    std::vector<Point> subset;\n+    for (std::size_t i = 0; i < points.size (); ++ i)\n+      if (rand() / (double)RAND_MAX < ratio_kept)\n+    \tsubset.push_back (points[i]);\n+    \n+    std::vector<unsigned int> scales;\n+    generate_scales (std::back_inserter (scales));\n+\n+    std::vector<unsigned int> chosen;\n+\n+    for (std::size_t i = 0; i < subset.size (); ++ i)\n+      {\n+    \tNeighbor_search search(tree, subset[i],scales.back());\n+\tdouble current = 0.;\n+    \tunsigned int nb = 0;\n+    \tstd::size_t index = 0;\n+\tdouble maximum = 0.;\n+\tunsigned int c = 0;\n+\t\n+    \tfor (Search_iterator search_iterator = search.begin();\n+    \t     search_iterator != search.end (); ++ search_iterator, ++ nb)\n+    \t  {\n+\t    current += search_iterator->second;\n+\n+    \t    if (nb + 1 == scales[index])\n+    \t      {\n+\t\tdouble score = std::sqrt (current / scales[index])\n+\t\t  / std::pow (scales[index], 0.75); // NB ^ (3/4)\n+\n+\t\tif (score > maximum)\n+\t\t  {\n+\t\t    maximum = score;\n+\t\t    c = scales[index];\n+\t\t  }\n+\n+    \t\t++ index;\n+    \t\tif (index == scales.size ())\n+    \t\t  break;\n+    \t      }\n+    \t  }\n+\tchosen.push_back (c);\n+      }\n+\n+    double mean = 0.;\n+    for (std::size_t i = 0; i < chosen.size(); ++ i)\n+      mean += chosen[i];\n+    mean /= chosen.size();\n+    unsigned int aniso_scale = static_cast<unsigned int>(mean);\n+\n+    size = 0.;\n+    for (std::size_t i = 0; i < subset.size (); ++ i)\n+      {\n+    \tNeighbor_search search(tree, subset[i], aniso_scale);\n+\tsize += std::sqrt ((-- search.end())->second);\n+      }\n+    size /= subset.size();\n+    \n+    return aniso_scale;\n+  }\n+\n+  \n+  unsigned int scale_of_noise (const Point_set& points, double& size)\n+  {\n+    Tree tree(points.begin(), points.end());\n+    \n+    double ratio_kept = (points.size() < 1000)\n+      ? 1. : 1000. / (points.size());\n+    \n+    std::vector<Point> subset;\n+    for (std::size_t i = 0; i < points.size (); ++ i)\n+      if (rand() / (double)RAND_MAX < ratio_kept)\n+    \tsubset.push_back (points[i]);\n+    \n+    std::vector<unsigned int> scales;\n+    generate_scales (std::back_inserter (scales));\n+\n+    std::vector<unsigned int> chosen;\n+    \n+    for (std::size_t i = 0; i < subset.size (); ++ i)\n+      {\n+    \tNeighbor_search search(tree, subset[i],scales.back());\n+\tdouble current = 0.;\n+    \tunsigned int nb = 0;\n+    \tstd::size_t index = 0;\n+\tdouble minimum = (std::numeric_limits<double>::max)();\n+\tunsigned int c = 0;\n+\t\n+    \tfor (Search_iterator search_iterator = search.begin();\n+    \t     search_iterator != search.end (); ++ search_iterator, ++ nb)\n+    \t  {\n+\t    current += search_iterator->second;\n+\n+    \t    if (nb + 1 == scales[index])\n+    \t      {\n+\t\tdouble score = std::sqrt (current / scales[index])\n+\t\t  / std::pow (scales[index], 0.375); // NB ^ (5/12)\n+\n+\t\tif (score < minimum)\n+\t\t  {\n+\t\t    minimum = score;\n+\t\t    c = scales[index];\n+\t\t  }\n+\n+    \t\t++ index;\n+    \t\tif (index == scales.size ())\n+    \t\t  break;\n+    \t      }\n+    \t  }\n+\tchosen.push_back (c);\n+      }\n+\n+    std::sort (chosen.begin (), chosen.end());\n+\n+    unsigned int noise_scale = chosen[chosen.size() / 2];\n+    size = 0.;\n+    for (std::size_t i = 0; i < subset.size (); ++ i)\n+      {\n+    \tNeighbor_search search(tree, subset[i], noise_scale);\n+\tsize += std::sqrt ((-- search.end())->second);\n+      }\n+    size /= subset.size();\n+\n+    \n+    return noise_scale;\n+  }\n+\n+  void simplify_point_set (Point_set& points, double size)\n+  {\n+    points.erase (CGAL::grid_simplify_point_set (points.begin (), points.end (), size),\n+\t\t  points.end ());\n+  }\n+\n+  void smooth_point_set (Point_set& points, unsigned int scale)\n+  {\n+    CGAL::jet_smooth_point_set<Concurrency_tag>(points.begin(), points.end(),\n+                                                scale);\n+  }\n+\n+  template <typename ItemsInserter>\n+  void scale_space (const Point_set& points, ItemsInserter items,\n+\t\t    unsigned int scale, bool generate_smooth = false,\n+                    bool separate_shells = false, bool force_manifold = true,\n+                    unsigned int samples = 300, unsigned int iterations = 4)\n+  {\n+    ScaleSpace reconstruct (scale, samples);\n+    reconstruct.reconstruct_surface(points.begin (), points.end (), iterations,\n+                                    separate_shells, force_manifold);\n+\n+    for( unsigned int sh = 0; sh < reconstruct.number_of_shells(); ++sh )\n+      {\n+        Scene_polygon_soup_item* new_item\n+          = new Scene_polygon_soup_item ();\n+        new_item->setColor(Qt::magenta);\n+        new_item->setRenderingMode(FlatPlusEdges);\n+        new_item->init_polygon_soup(points.size(), reconstruct.number_of_triangles ());\n+\n+        Scene_polygon_soup_item* smooth_item = NULL;\n+        if (generate_smooth)\n+          {\n+            smooth_item = new Scene_polygon_soup_item ();\n+            smooth_item->setColor(Qt::magenta);\n+            smooth_item->setRenderingMode(FlatPlusEdges);\n+            smooth_item->init_polygon_soup(points.size(), reconstruct.number_of_triangles ());\n+          }\n+\n+        std::map<unsigned int, unsigned int> map_i2i;\n+        unsigned int current_index = 0;\n+    \n+        for (ScaleSpace::Triple_iterator it = reconstruct.shell_begin (sh);\n+             it != reconstruct.shell_end (sh); ++ it)\n+          {\n+            for (unsigned int ind = 0; ind < 3; ++ ind)\n+              {\n+                if (map_i2i.find ((*it)[ind]) == map_i2i.end ())\n+                  {\n+                    map_i2i.insert (std::make_pair ((*it)[ind], current_index ++));\n+                    Point p = points[(*it)[ind]].position();\n+                    new_item->new_vertex (p.x (), p.y (), p.z ());\n+                    \n+                    if (generate_smooth)\n+                      {\n+                        p = *(reconstruct.points_begin() + (*it)[ind]);\n+                        smooth_item->new_vertex (p.x (), p.y (), p.z ());\n+                      }\n+                  }\n+              }\n+            new_item->new_triangle( map_i2i[(*it)[0]],\n+                                    map_i2i[(*it)[1]],\n+                                    map_i2i[(*it)[2]] );\n+            if (generate_smooth)\n+              smooth_item->new_triangle( map_i2i[(*it)[0]],\n+                                         map_i2i[(*it)[1]],\n+                                         map_i2i[(*it)[2]] );\n+              \n+          }\n+\n+        *(items ++) = new_item;\n+        if (generate_smooth)\n+          *(items ++) = smooth_item;\n+      }\n+\n+    if (force_manifold)\n+      {\n+        std::ptrdiff_t num = std::distance( reconstruct.garbage_begin(  ),\n+                                            reconstruct.garbage_end(  ) );\n+\n+        Scene_polygon_soup_item* new_item\n+          = new Scene_polygon_soup_item ();\n+        new_item->setColor(Qt::blue);\n+        new_item->setRenderingMode(FlatPlusEdges);\n+        new_item->init_polygon_soup(points.size(), num);\n+\n+        Scene_polygon_soup_item* smooth_item = NULL;\n+        if (generate_smooth)\n+          {\n+            smooth_item = new Scene_polygon_soup_item ();\n+            smooth_item->setColor(Qt::blue);\n+            smooth_item->setRenderingMode(FlatPlusEdges);\n+            smooth_item->init_polygon_soup(points.size(), num);\n+          }\n+\n+        std::map<unsigned int, unsigned int> map_i2i;\n+\n+        unsigned int current_index = 0;\n+        for (ScaleSpace::Triple_iterator it=reconstruct.garbage_begin(),\n+               end=reconstruct.garbage_end();it!=end;++it)\n+          {\n+            for (unsigned int ind = 0; ind < 3; ++ ind)\n+              {\n+                if (map_i2i.find ((*it)[ind]) == map_i2i.end ())\n+                  {\n+                    map_i2i.insert (std::make_pair ((*it)[ind], current_index ++));\n+                    Point p = points[(*it)[ind]].position();\n+                    new_item->new_vertex (p.x (), p.y (), p.z ());\n+                    \n+                    if (generate_smooth)\n+                      {\n+                        p = *(reconstruct.points_begin() + (*it)[ind]);\n+                        smooth_item->new_vertex (p.x (), p.y (), p.z ());\n+                      }\n+                  }\n+\n+              }\n+            new_item->new_triangle( map_i2i[(*it)[0]],\n+                                    map_i2i[(*it)[1]],\n+                                    map_i2i[(*it)[2]] );\n+            if (generate_smooth)\n+              smooth_item->new_triangle( map_i2i[(*it)[0]],\n+                                         map_i2i[(*it)[1]],\n+                                         map_i2i[(*it)[2]] );\n+          }\n+\n+        *(items ++) = new_item;\n+        if (generate_smooth)\n+          *(items ++) = smooth_item;\n+\n+      }\n+  }\n+  \n+  void advancing_front (const Point_set& points, Scene_polyhedron_item* new_item, double size)\n+  {\n+    Polyhedron& P = * const_cast<Polyhedron*>(new_item->polyhedron());\n+    Radius filter(10 * size);\n+\n+    CGAL::advancing_front_surface_reconstruction (points.begin (), points.end (), P, filter);\n+\t\t\t\t\t\t  \n+  }\n+\n+  void compute_normals (Point_set& points, unsigned int neighbors)\n+  {\n+    CGAL::jet_estimate_normals<Concurrency_tag>(points.begin(), points.end(),\n+                                                CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),\n+                                                2 * neighbors);\n+    \n+    points.erase (CGAL::mst_orient_normals (points.begin(), points.end(),\n+\t\t\t\t\t    CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),\n+\t\t\t\t\t    2 * neighbors),\n+\t\t  points.end ());\n+  }\n+  \n+}\n+\n+\n+\n+class Polyhedron_demo_surface_reconstruction_plugin_dialog : public QDialog, private Ui::SurfaceReconstructionDialog\n+{\n+  Q_OBJECT\n+public:\n+  Polyhedron_demo_surface_reconstruction_plugin_dialog(QWidget* /*parent*/ = 0)\n+  {\n+    setupUi(this);\n+    \n+#ifdef CGAL_EIGEN3_ENABLED\n+    m_inputSolver->addItem(\"Eigen - built-in CG\");\n+    m_inputSolver->addItem(\"Eigen - built-in simplicial LDLt\");\n+#endif\n+  }\n+\n+  unsigned int method () const\n+  {\n+    if (buttonAuto->isChecked ())       return 0;\n+    if (buttonAdvancing->isChecked ())  return 1;\n+    if (buttonScaleSpace->isChecked ()) return 2;\n+    if (buttonPoisson->isChecked ())    return 3;\n+    return -1;\n+  }\n+  bool boundaries () const { return m_boundaries->isChecked (); }\n+  bool interpolate () const { return m_interpolate->isChecked (); }\n+  double longest_edge () const { return m_longestEdge->value (); }\n+  unsigned int neighbors () const { return m_neighbors->value (); }\n+  unsigned int samples () const { return m_samples->value (); }\n+  unsigned int iterations () const { return m_iterations->value (); }\n+  bool separate_shells () const { return m_genShells->isChecked (); }\n+  bool force_manifold () const { return m_forceManifold->isChecked (); }\n+  bool generate_smoothed () const { return m_genSmooth->isChecked (); }\n+  double angle () const { return m_inputAngle->value (); }\n+  double radius () const { return m_inputRadius->value (); }\n+  double distance () const { return m_inputDistance->value (); }\n+  bool two_passes () const { return m_inputTwoPasses->isChecked (); }\n+  bool do_not_fill_holes () const { return m_doNotFillHoles->isChecked (); }\n+  QString solver () const { return m_inputSolver->currentText (); }\n+};\n+\n+#include <CGAL/Scale_space_surface_reconstruction_3.h>\n+\n+class Polyhedron_demo_surface_reconstruction_plugin :\n+  public QObject,\n+  public CGAL::Three::Polyhedron_demo_plugin_helper\n+{\n+  Q_OBJECT\n+  Q_PLUGIN_METADATA(IID \"com.geometryfactory.PolyhedronDemo.PluginInterface/1.0\")\n+\n+  Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)\n+  QAction* actionScaleSpaceReconstruction;\n+\n+public:\n+  void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface) {\n+\n+    actionScaleSpaceReconstruction = new QAction(tr(\"Surface surface reconstruction\"), mainWindow);\n+    actionScaleSpaceReconstruction->setObjectName(\"actionSurfaceReconstruction\");","path":"Polyhedron/demo/Polyhedron/Polyhedron_demo_surface_reconstruction_plugin.cpp","position":455,"original_position":455,"commit_id":"cef08091f627f3f6d9bf17cd60afb9fb23291ccd","original_commit_id":"cef08091f627f3f6d9bf17cd60afb9fb23291ccd","user":{"login":"sloriot","id":1224632,"avatar_url":"https://avatars.githubusercontent.com/u/1224632?v=3","gravatar_id":"","url":"https://api.github.com/users/sloriot","html_url":"https://github.com/sloriot","followers_url":"https://api.github.com/users/sloriot/followers","following_url":"https://api.github.com/users/sloriot/following{/other_user}","gists_url":"https://api.github.com/users/sloriot/gists{/gist_id}","starred_url":"https://api.github.com/users/sloriot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sloriot/subscriptions","organizations_url":"https://api.github.com/users/sloriot/orgs","repos_url":"https://api.github.com/users/sloriot/repos","events_url":"https://api.github.com/users/sloriot/events{/privacy}","received_events_url":"https://api.github.com/users/sloriot/received_events","type":"User","site_admin":false},"body":"Surface surface reconstruction? Did you mean 3D surface reconstruction?","created_at":"2015-10-29T07:54:10Z","updated_at":"2015-10-29T07:54:10Z","html_url":"https://github.com/CGAL/cgal/pull/434#discussion_r43357411","pull_request_url":"https://api.github.com/repos/CGAL/cgal/pulls/434","_links":{"self":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/comments/43357411"},"html":{"href":"https://github.com/CGAL/cgal/pull/434#discussion_r43357411"},"pull_request":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/434"}}},"pull_request":{"url":"https://api.github.com/repos/CGAL/cgal/pulls/434","id":48582422,"html_url":"https://github.com/CGAL/cgal/pull/434","diff_url":"https://github.com/CGAL/cgal/pull/434.diff","patch_url":"https://github.com/CGAL/cgal/pull/434.patch","issue_url":"https://api.github.com/repos/CGAL/cgal/issues/434","number":434,"state":"open","locked":false,"title":"Polyhedron demo - Meta reconstruction plugin","user":{"login":"sgiraudot","id":12890639,"avatar_url":"https://avatars.githubusercontent.com/u/12890639?v=3","gravatar_id":"","url":"https://api.github.com/users/sgiraudot","html_url":"https://github.com/sgiraudot","followers_url":"https://api.github.com/users/sgiraudot/followers","following_url":"https://api.github.com/users/sgiraudot/following{/other_user}","gists_url":"https://api.github.com/users/sgiraudot/gists{/gist_id}","starred_url":"https://api.github.com/users/sgiraudot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sgiraudot/subscriptions","organizations_url":"https://api.github.com/users/sgiraudot/orgs","repos_url":"https://api.github.com/users/sgiraudot/repos","events_url":"https://api.github.com/users/sgiraudot/events{/privacy}","received_events_url":"https://api.github.com/users/sgiraudot/received_events","type":"User","site_admin":false},"body":"Replace the 3 reconstruction plugins (poisson, scale space and advancing front) by one single plugin with a unique dialog.\r\n\r\nIn addition, I added an \"automatic\" mode that analyses the point cloud and selects the most adapted method with automatically computed parameters. It is very empiric and not guaranteed to work in general so it cannot go into a CGAL package but it gives acceptable results in general and provides an easy access to the reconstruction algorithms of CGAL.\r\n\r\nThis has not been merged into integration yet.","created_at":"2015-10-23T13:52:51Z","updated_at":"2015-10-29T07:54:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c383de1d813078a13958d533fabffe62bfe6fdb1","assignee":null,"milestone":{"url":"https://api.github.com/repos/CGAL/cgal/milestones/7","html_url":"https://github.com/CGAL/cgal/milestones/4.8-beta","labels_url":"https://api.github.com/repos/CGAL/cgal/milestones/7/labels","id":1202221,"number":7,"title":"4.8-beta","description":"","creator":{"login":"lrineau","id":5746675,"avatar_url":"https://avatars.githubusercontent.com/u/5746675?v=3","gravatar_id":"","url":"https://api.github.com/users/lrineau","html_url":"https://github.com/lrineau","followers_url":"https://api.github.com/users/lrineau/followers","following_url":"https://api.github.com/users/lrineau/following{/other_user}","gists_url":"https://api.github.com/users/lrineau/gists{/gist_id}","starred_url":"https://api.github.com/users/lrineau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lrineau/subscriptions","organizations_url":"https://api.github.com/users/lrineau/orgs","repos_url":"https://api.github.com/users/lrineau/repos","events_url":"https://api.github.com/users/lrineau/events{/privacy}","received_events_url":"https://api.github.com/users/lrineau/received_events","type":"User","site_admin":false},"open_issues":22,"closed_issues":77,"state":"open","created_at":"2015-07-10T10:06:47Z","updated_at":"2015-10-29T07:51:31Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/CGAL/cgal/pulls/434/commits","review_comments_url":"https://api.github.com/repos/CGAL/cgal/pulls/434/comments","review_comment_url":"https://api.github.com/repos/CGAL/cgal/pulls/comments{/number}","comments_url":"https://api.github.com/repos/CGAL/cgal/issues/434/comments","statuses_url":"https://api.github.com/repos/CGAL/cgal/statuses/cef08091f627f3f6d9bf17cd60afb9fb23291ccd","head":{"label":"sgiraudot:Polyhedron_demo-Meta_reconstruction_plugin-GF","ref":"Polyhedron_demo-Meta_reconstruction_plugin-GF","sha":"cef08091f627f3f6d9bf17cd60afb9fb23291ccd","user":{"login":"sgiraudot","id":12890639,"avatar_url":"https://avatars.githubusercontent.com/u/12890639?v=3","gravatar_id":"","url":"https://api.github.com/users/sgiraudot","html_url":"https://github.com/sgiraudot","followers_url":"https://api.github.com/users/sgiraudot/followers","following_url":"https://api.github.com/users/sgiraudot/following{/other_user}","gists_url":"https://api.github.com/users/sgiraudot/gists{/gist_id}","starred_url":"https://api.github.com/users/sgiraudot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sgiraudot/subscriptions","organizations_url":"https://api.github.com/users/sgiraudot/orgs","repos_url":"https://api.github.com/users/sgiraudot/repos","events_url":"https://api.github.com/users/sgiraudot/events{/privacy}","received_events_url":"https://api.github.com/users/sgiraudot/received_events","type":"User","site_admin":false},"repo":{"id":37466040,"name":"cgal","full_name":"sgiraudot/cgal","owner":{"login":"sgiraudot","id":12890639,"avatar_url":"https://avatars.githubusercontent.com/u/12890639?v=3","gravatar_id":"","url":"https://api.github.com/users/sgiraudot","html_url":"https://github.com/sgiraudot","followers_url":"https://api.github.com/users/sgiraudot/followers","following_url":"https://api.github.com/users/sgiraudot/following{/other_user}","gists_url":"https://api.github.com/users/sgiraudot/gists{/gist_id}","starred_url":"https://api.github.com/users/sgiraudot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sgiraudot/subscriptions","organizations_url":"https://api.github.com/users/sgiraudot/orgs","repos_url":"https://api.github.com/users/sgiraudot/repos","events_url":"https://api.github.com/users/sgiraudot/events{/privacy}","received_events_url":"https://api.github.com/users/sgiraudot/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sgiraudot/cgal","description":"The public CGAL repository","fork":true,"url":"https://api.github.com/repos/sgiraudot/cgal","forks_url":"https://api.github.com/repos/sgiraudot/cgal/forks","keys_url":"https://api.github.com/repos/sgiraudot/cgal/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sgiraudot/cgal/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sgiraudot/cgal/teams","hooks_url":"https://api.github.com/repos/sgiraudot/cgal/hooks","issue_events_url":"https://api.github.com/repos/sgiraudot/cgal/issues/events{/number}","events_url":"https://api.github.com/repos/sgiraudot/cgal/events","assignees_url":"https://api.github.com/repos/sgiraudot/cgal/assignees{/user}","branches_url":"https://api.github.com/repos/sgiraudot/cgal/branches{/branch}","tags_url":"https://api.github.com/repos/sgiraudot/cgal/tags","blobs_url":"https://api.github.com/repos/sgiraudot/cgal/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sgiraudot/cgal/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sgiraudot/cgal/git/refs{/sha}","trees_url":"https://api.github.com/repos/sgiraudot/cgal/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sgiraudot/cgal/statuses/{sha}","languages_url":"https://api.github.com/repos/sgiraudot/cgal/languages","stargazers_url":"https://api.github.com/repos/sgiraudot/cgal/stargazers","contributors_url":"https://api.github.com/repos/sgiraudot/cgal/contributors","subscribers_url":"https://api.github.com/repos/sgiraudot/cgal/subscribers","subscription_url":"https://api.github.com/repos/sgiraudot/cgal/subscription","commits_url":"https://api.github.com/repos/sgiraudot/cgal/commits{/sha}","git_commits_url":"https://api.github.com/repos/sgiraudot/cgal/git/commits{/sha}","comments_url":"https://api.github.com/repos/sgiraudot/cgal/comments{/number}","issue_comment_url":"https://api.github.com/repos/sgiraudot/cgal/issues/comments{/number}","contents_url":"https://api.github.com/repos/sgiraudot/cgal/contents/{+path}","compare_url":"https://api.github.com/repos/sgiraudot/cgal/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sgiraudot/cgal/merges","archive_url":"https://api.github.com/repos/sgiraudot/cgal/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sgiraudot/cgal/downloads","issues_url":"https://api.github.com/repos/sgiraudot/cgal/issues{/number}","pulls_url":"https://api.github.com/repos/sgiraudot/cgal/pulls{/number}","milestones_url":"https://api.github.com/repos/sgiraudot/cgal/milestones{/number}","notifications_url":"https://api.github.com/repos/sgiraudot/cgal/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sgiraudot/cgal/labels{/name}","releases_url":"https://api.github.com/repos/sgiraudot/cgal/releases{/id}","created_at":"2015-06-15T13:14:30Z","updated_at":"2015-06-15T13:15:28Z","pushed_at":"2015-10-26T06:25:57Z","git_url":"git://github.com/sgiraudot/cgal.git","ssh_url":"git@github.com:sgiraudot/cgal.git","clone_url":"https://github.com/sgiraudot/cgal.git","svn_url":"https://github.com/sgiraudot/cgal","homepage":"http://www.cgal.org","size":521143,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"CGAL:master","ref":"master","sha":"a6b985c0c35c574562d726931a83efbcdb7373ec","user":{"login":"CGAL","id":5746664,"avatar_url":"https://avatars.githubusercontent.com/u/5746664?v=3","gravatar_id":"","url":"https://api.github.com/users/CGAL","html_url":"https://github.com/CGAL","followers_url":"https://api.github.com/users/CGAL/followers","following_url":"https://api.github.com/users/CGAL/following{/other_user}","gists_url":"https://api.github.com/users/CGAL/gists{/gist_id}","starred_url":"https://api.github.com/users/CGAL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CGAL/subscriptions","organizations_url":"https://api.github.com/users/CGAL/orgs","repos_url":"https://api.github.com/users/CGAL/repos","events_url":"https://api.github.com/users/CGAL/events{/privacy}","received_events_url":"https://api.github.com/users/CGAL/received_events","type":"Organization","site_admin":false},"repo":{"id":24677392,"name":"cgal","full_name":"CGAL/cgal","owner":{"login":"CGAL","id":5746664,"avatar_url":"https://avatars.githubusercontent.com/u/5746664?v=3","gravatar_id":"","url":"https://api.github.com/users/CGAL","html_url":"https://github.com/CGAL","followers_url":"https://api.github.com/users/CGAL/followers","following_url":"https://api.github.com/users/CGAL/following{/other_user}","gists_url":"https://api.github.com/users/CGAL/gists{/gist_id}","starred_url":"https://api.github.com/users/CGAL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CGAL/subscriptions","organizations_url":"https://api.github.com/users/CGAL/orgs","repos_url":"https://api.github.com/users/CGAL/repos","events_url":"https://api.github.com/users/CGAL/events{/privacy}","received_events_url":"https://api.github.com/users/CGAL/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CGAL/cgal","description":"The public CGAL repository","fork":false,"url":"https://api.github.com/repos/CGAL/cgal","forks_url":"https://api.github.com/repos/CGAL/cgal/forks","keys_url":"https://api.github.com/repos/CGAL/cgal/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CGAL/cgal/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CGAL/cgal/teams","hooks_url":"https://api.github.com/repos/CGAL/cgal/hooks","issue_events_url":"https://api.github.com/repos/CGAL/cgal/issues/events{/number}","events_url":"https://api.github.com/repos/CGAL/cgal/events","assignees_url":"https://api.github.com/repos/CGAL/cgal/assignees{/user}","branches_url":"https://api.github.com/repos/CGAL/cgal/branches{/branch}","tags_url":"https://api.github.com/repos/CGAL/cgal/tags","blobs_url":"https://api.github.com/repos/CGAL/cgal/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CGAL/cgal/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CGAL/cgal/git/refs{/sha}","trees_url":"https://api.github.com/repos/CGAL/cgal/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CGAL/cgal/statuses/{sha}","languages_url":"https://api.github.com/repos/CGAL/cgal/languages","stargazers_url":"https://api.github.com/repos/CGAL/cgal/stargazers","contributors_url":"https://api.github.com/repos/CGAL/cgal/contributors","subscribers_url":"https://api.github.com/repos/CGAL/cgal/subscribers","subscription_url":"https://api.github.com/repos/CGAL/cgal/subscription","commits_url":"https://api.github.com/repos/CGAL/cgal/commits{/sha}","git_commits_url":"https://api.github.com/repos/CGAL/cgal/git/commits{/sha}","comments_url":"https://api.github.com/repos/CGAL/cgal/comments{/number}","issue_comment_url":"https://api.github.com/repos/CGAL/cgal/issues/comments{/number}","contents_url":"https://api.github.com/repos/CGAL/cgal/contents/{+path}","compare_url":"https://api.github.com/repos/CGAL/cgal/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CGAL/cgal/merges","archive_url":"https://api.github.com/repos/CGAL/cgal/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CGAL/cgal/downloads","issues_url":"https://api.github.com/repos/CGAL/cgal/issues{/number}","pulls_url":"https://api.github.com/repos/CGAL/cgal/pulls{/number}","milestones_url":"https://api.github.com/repos/CGAL/cgal/milestones{/number}","notifications_url":"https://api.github.com/repos/CGAL/cgal/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CGAL/cgal/labels{/name}","releases_url":"https://api.github.com/repos/CGAL/cgal/releases{/id}","created_at":"2014-10-01T12:22:47Z","updated_at":"2015-10-29T06:50:02Z","pushed_at":"2015-10-29T06:56:23Z","git_url":"git://github.com/CGAL/cgal.git","ssh_url":"git@github.com:CGAL/cgal.git","clone_url":"https://github.com/CGAL/cgal.git","svn_url":"https://github.com/CGAL/cgal","homepage":"http://www.cgal.org","size":626672,"stargazers_count":128,"watchers_count":128,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":78,"mirror_url":null,"open_issues_count":88,"forks":78,"open_issues":88,"watchers":128,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/434"},"html":{"href":"https://github.com/CGAL/cgal/pull/434"},"issue":{"href":"https://api.github.com/repos/CGAL/cgal/issues/434"},"comments":{"href":"https://api.github.com/repos/CGAL/cgal/issues/434/comments"},"review_comments":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/434/comments"},"review_comment":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/CGAL/cgal/pulls/434/commits"},"statuses":{"href":"https://api.github.com/repos/CGAL/cgal/statuses/cef08091f627f3f6d9bf17cd60afb9fb23291ccd"}}}}