diff --git a/BGL/include/CGAL/boost/graph/named_function_params.h b/BGL/include/CGAL/boost/graph/named_function_params.h index c8df45cdcb3..543e1b0a103 100644 --- a/BGL/include/CGAL/boost/graph/named_function_params.h +++ b/BGL/include/CGAL/boost/graph/named_function_params.h @@ -68,6 +68,8 @@ namespace CGAL { enum get_cost_policy_params_t { get_cost_policy_params } ; enum get_placement_policy_t { get_placement_policy } ; enum get_placement_policy_params_t { get_placement_policy_params } ; + enum edge_is_constrained_t { edge_is_constrained } ; + enum edge_is_constrained_params_t { edge_is_constrained_params } ; #if BOOST_VERSION >= 105100 template @@ -166,6 +168,22 @@ namespace CGAL { typedef cgal_bgl_named_params Params; return Params(p, *this); } + + template + cgal_bgl_named_params + edge_is_constrained_map(const EdgeIsConstrained& em) const + { + typedef cgal_bgl_named_params Params; + return Params(em, *this); + } + + template + cgal_bgl_named_params + edge_is_constrained_map_params(const EdgeIsConstrainedParams& em) const + { + typedef cgal_bgl_named_params Params; + return Params(em, *this); + } }; #else template @@ -270,6 +288,22 @@ namespace CGAL { typedef cgal_bgl_named_params Params; return Params(p, *this); } + + template + cgal_bgl_named_params + edge_is_constrained_map(const EdgeIsConstrained& em) const + { + typedef cgal_bgl_named_params Params; + return Params(em, *this); + } + + template + cgal_bgl_named_params + edge_is_constrained_map_params(const EdgeIsConstrainedParams& em) const + { + typedef cgal_bgl_named_params Params; + return Params(em, *this); + } }; template @@ -373,6 +407,22 @@ namespace CGAL { typedef cgal_bgl_named_params Params; return Params(p); } + + template + cgal_bgl_named_params + edge_is_constrained_map(const EdgeIsConstrained& em) + { + typedef cgal_bgl_named_params Params; + return Params(em); + } + + template + cgal_bgl_named_params + edge_is_constrained_map_params(const EdgeIsConstrainedParams& em) + { + typedef cgal_bgl_named_params Params; + return Params(em); + } } //namespace CGAL #if BOOST_VERSION >= 105100 diff --git a/Installation/changes.html b/Installation/changes.html index 7b9f1c4c8ce..dfcb612de6a 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -230,6 +230,12 @@ and src/ directories).
  • Hilbert sort ipelet implements two policies
  • +

    Triangulated Surface Mesh Simplification

    +
      +
    • Fix a bug in the way edges can be marked as non-removable by adding + a named-parameter edge_is_constrained_map to the function + edge_collapse
    • +

    Release 4.3

    diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h new file mode 100644 index 00000000000..6dbd277a059 --- /dev/null +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h @@ -0,0 +1,38 @@ + +namespace CGAL { +namespace Surface_mesh_simplification { + +/*! +\ingroup PkgSurfaceMeshSimplification + +The class `Constrained_placement` is a model for the `GetPlacement` concept +provided the template parameter `BasePlacement` is such a model. +The placement of the vertex resulting from a contraction of an edge adjacent to a constrained edge +is the point of the common vertex. Otherwise the placement is the one computed by `BasePlacement`. + +\tparam BasePlacement a model of `GetPlacement`. +\tparam EdgeIsConstrainedMap a model of `boost::ReadablePropertyMap` with `GetPlacement::Profile::edge_descriptor` + as key type and `bool` as value type indicating if an edge is constrained. + +\cgalModels `GetPlacement` + +*/ +template +class Constrained_placement : public BasePlacement +{ +public: + +/// \name Creation +/// @{ + +/*! +Constructor +*/ + Constrained_placement( + EdgeIsConstrainedMap map=EdgeIsConstrainedMap(), + BasePlacement base= BasePlacement() ); +/// @} + +}; /* end Surface_mesh_simplification::Midpoint_placement */ +} /* end namespace Surface_Mesh_Simplification */ +} /* end namespace CGAL */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/edge_collapse.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/edge_collapse.h index 33808048b5a..ea97c7b7d52 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/edge_collapse.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/edge_collapse.h @@ -94,6 +94,20 @@ and whose `value_type` is `bool`. %Default: the property map obtained by calling `get(edge_is_border,surface)`. +\cgalHeading{edge_is_constrained_map(EdgeIsConstrainedMap ecm)} + +Maps each undirected edge in the surface into a Boolean value +which indicates if the edge is constrained. +`EdgeIsConstrainedMap` must be a model +`ReadablePropertyMap` whose `key_type` is +`boost::graph_traits::%edge_descriptor` +and whose `value_type` is `bool`. + +\attention If this parameter is provided, `surface` must be a model of the +`EdgeCollapsableMeshWithConstraints` concept. + +%Default: A property map always returning `false`, that is no edge is constrained. + \cgalHeading{get_cost(GetCost gc)} The policy which returns the collapse cost for an edge. diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMesh.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMesh.h index 7c45a870de8..ea3bff4a4e9 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMesh.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMesh.h @@ -16,9 +16,11 @@ It can have any number of connected components, boundaries \cgalHeading{Valid Expressions} -The mesh simplification algorithm requires the free function `halfedge_collapse()`. - -Let `v0` be the source and `v1` be the target vertices of `v0v1`. +Let `v0v1` an edge of the triangulated surface mesh `ecm` and +`v0` and `v1` being the source and target vertices of that edge. +The mesh simplification algorithm requires the call to the function `halfedge_collapse(v0v1,ecm)` +to be valid and to return the vertex not removed after collapsing +the undirected edge `(v0v1,v1v0)`. For `e` \f$ \in \{\f$ `v0v1,v1v0` \f$ \}\f$, let `en` and `ep` be the next and previous edges, that is `en = next_edge(e, mesh)`, `ep = prev_edge(e,mesh)`, and let @@ -30,15 +32,14 @@ Then, after the collapse of `(v0v1,v1v0)` the following holds:
    • The edge `e` is no longer in `mesh`.
    • One of \f$ \{\f$`v0,v1`\f$ \}\f$ is no longer in `mesh` while the other remains. -\cgalFootnote{Even though it would appear that v0 can always be the vertex being removed, there is a case when removing the edge `e` requires `v1` to be removed as well. See figure \ref CollapseFigure5.} +\cgalFootnote{Most of the time v0 is the vertex being removed but in some cases removing the edge e requires v1 to be removed. See Figure \ref CollapseFigure5.} Let `vgone` be the removed vertex and `vkept` be the remaining vertex.
    • If `e` was a border edge, that is `get(is_border, e, mesh) == true`, then `next_edge(ep) == en`, and `prev_edge(en) == ep`.
    • If `e` was not a border edge, that is `get(is_border, e, mesh) == false`, then `ep` and `epo` are no longer in `mesh` while `en` and `eno` are kept in `mesh`.
    • For all edges `ie` in `in_edges(vgone,mesh)`, `target(ie,mesh) == vkept` and `source(opposite_edge(ie),mesh) == vkept`.
    • No other incidence information has changed in `mesh`. -
    + -The function returns vertex `vkept` (which can be either `v0` or `v1`). \image html general_collapse.png \image latex general_collapse.png @@ -64,7 +65,7 @@ When the collapsing edge is itself a border, only 1 triangle is removed. Thus, even if \f$ (ep',epo')\f$ exists, it's not removed. -\anchor CollapseFigure5 +\anchor CollapseFigure5 \image html border_collapse4.png \image latex border_collapse4.png
    @@ -73,9 +74,8 @@ This figure illustrates the single exceptional case when removing \f$ remains.
    -\cgalHasModel `CGAL::Polyhedron_3` (If it has only triangular faces, and via -External Adaptation, which is described in \cgalCite{cgal:sll-bgl-02} -and this Bgl web page: http://www.boost.org/libs/graph/doc/leda_conversion.html). +\cgalHasModel `CGAL::Polyhedron_3` (If it has only triangular faces), +using the specialization \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink. \sa \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink \sa `CGAL::halfedge_graph_traits< CGAL::Polyhedron_3 >` @@ -88,9 +88,9 @@ public: /*! Collapses the undirected edge `(v0v1,v1v0)` replacing it with `v0` or `v1`, -as described in the following paragraph. +as described in the paragraph above. \pre This function requires `mesh` to be an oriented 2-manifold with or without boundaries. Furthermore, the undirected edge `(v0v1,v1v0)` must satisfy the link condition \cgalCite{degn-tpec-98}, which guarantees that the surface is also 2-manifold after the edge collapse. -\relates EdgeCollapsableMesh +\relates EdgeCollapsableMesh */ template typename boost::graph_traits::vertex_descriptor diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMeshWithConstraints.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMeshWithConstraints.h new file mode 100644 index 00000000000..370c67f5903 --- /dev/null +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapsableMeshWithConstraints.h @@ -0,0 +1,61 @@ + +/*! +\ingroup PkgSurfaceMeshSimplificationConcepts +\cgalConcept + +The concept `EdgeCollapsableMeshWithConstraints` describes additional requirements +for the type of triangulated surface meshes that can be passed to the +simplification algorithm. + +\cgalRefines `EdgeCollapsableMesh` + +\cgalHeading{Valid Expressions} + +Let `v0v1` be an edge of the triangulated surface mesh `ecm` and +`v0` and `v1` being the source and target vertices of that edge. +The mesh simplification algorithm requires the call to the function `halfedge_collapse(v0v1,ecm)` +to be valid and to return the vertex not removed after collapsing +the undirected edge `(v0v1,v1v0)`. + +For `e` \f$ \in \{\f$ `v0v1,v1v0` \f$ \}\f$, let `en` and `ep` be the next and previous +edges, that is `en = next_edge(e, mesh)`, `ep = prev_edge(e,mesh)`, and let +`eno` and `epo` be their opposite edges, that is +`eno = opposite_edge(en, mesh)` and `epo = opposite_edge(ep,mesh)`. + +Then, after the collapse of `(v0v1,v1v0)` the invariants described in the concept `EdgeCollapsableMesh` hold +if `ep` is not constrained. Otherwise, it is `en` that is removed from `ecm`. + +\image html collapse_constraints.png +\image latex collapse_constraints.png + +\cgalHasModel `CGAL::Polyhedron_3` (If it has only triangular faces), +using the specialization \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink. + +\sa \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink +\sa `CGAL::halfedge_graph_traits< CGAL::Polyhedron_3 >` + +*/ + +class EdgeCollapsableMeshWithConstraints { +public: +}; /* end EdgeCollapsableMeshWithConstraints */ + +/*! +Collapses the undirected edge `(v0v1,v1v0)` replacing it with `v0` or `v1`, +as described in the paragraph above and guarantees that an halfedge `he`, for which `get(edge_is_constrained_map, he)==true`, is not removed after the collapse. +\tparam EdgeCollapsableMeshWithConstraints a model of `HalfedgeGraph` +\tparam EdgeIsConstrainedMap a model of `ReadablePropertyMap` with the edge descriptor of + `EdgeCollapsableMeshWithConstraints` as key type and a boolean as value type. + It indicates if an edge is constrained or not. +\pre This function requires `mesh` to be an oriented 2-manifold with or without boundaries. Furthermore, the undirected edge `(v0v1,v1v0)` must satisfy the link condition \cgalCite{degn-tpec-98}, which guarantees that the surface is also 2-manifold after the edge collapse. +\pre `get(edge_is_constrained_map, v0v1)==get(edge_is_constrained_map, v1v0)==false`. +\pre `v0` and `v1` are not both incident to a constrained edge. +\relates EdgeCollapsableMeshWithConstraints +*/ +template +typename boost::graph_traits::vertex_descriptor +halfedge_collapse(typename boost::graph_traits::edge_descriptor const& ue, + EdgeCollapsableMeshWithConstraints& mesh, + EdgeIsConstrainedMap edge_is_constrained_map); + + diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeProfile.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeProfile.h index 694d5fa87e4..8b14664ff0b 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeProfile.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeProfile.h @@ -132,6 +132,11 @@ Indicates if `v0v1` belongs to a finite face of the mesh (i.e, `v1v0` is not a b */ bool right_face_exits() const; +/*! +Returns the surface the edge belongs to. +*/ +const ECM& surface() const; + /// @} }; /* end EdgeProfile */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h index f0fd4187121..29bbb156a37 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h @@ -12,7 +12,6 @@ The placement returned is a `boost::optional` value (i.e., it can be absent). An absent result indicates that the remaining vertex must be kept in place, not moved to a new position. -\cgalRefines `DefaultConstructible` \cgalRefines `CopyConstructible` \cgalHasModel `CGAL::Surface_mesh_simplification::Midpoint_placement` diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt index 6c778a8ea5d..131c098a45b 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/PackageDescription.txt @@ -25,6 +25,7 @@ ## Concepts ## - `EdgeCollapsableMesh` +- `EdgeCollapsableMeshWithConstraints` - `EdgeProfile` - `StopPredicate` - `GetCost` @@ -43,6 +44,7 @@ - `CGAL::Surface_mesh_simplification::Midpoint_placement` - `CGAL::Surface_mesh_simplification::LindstromTurk_cost` - `CGAL::Surface_mesh_simplification::LindstromTurk_placement` +- `CGAL::Surface_mesh_simplification::Constrained_placement` */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt index e9663bfcb7c..96d93a1448e 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt @@ -288,12 +288,14 @@ and how to use a visitor object to track the simplification process. \cgalExample{Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp} -\subsection Surface_mesh_simplificationExamplewithedges Example with edges marked as non-removable +\subsection Surface_mesh_simplificationExamplewithedges Example with Edges Marked as Non-Removable -The following example shows how to use the optional named parameter `edge_is_border_map` to prevent -edges from being removed even if they are not really borders. +The following examples show how to use the optional named parameter `edge_is_constrained_map` to prevent +edges from being removed. Edges marked as contrained are guaranteed to be in the final mesh. However, +the vertices of the constrained edges may change and the placement may change the points. +The wrapper `CGAL::Constrained_placement` guarantees that these points are not changed. -\cgalExample{Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cpp} +\cgalExample{Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp} */ } /* namespace CGAL */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/examples.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/examples.txt index 555a93b051c..3b6b6ca834e 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/examples.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/examples.txt @@ -1,5 +1,6 @@ /*! \example Surface_mesh_simplification/edge_collapse_polyhedron.cpp \example Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp -\example Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cpp +\example Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp +\example Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/collapse_constraints.png b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/collapse_constraints.png new file mode 100644 index 00000000000..65e0ef4c1fb Binary files /dev/null and b/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig/collapse_constraints.png differ diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/cube-meshed.off b/Surface_mesh_simplification/examples/Surface_mesh_simplification/cube-meshed.off new file mode 100644 index 00000000000..270f60aa6b4 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/cube-meshed.off @@ -0,0 +1,2598 @@ +OFF +866 1728 0 + +-0.875 1 -0.875 +-0.75 1 -0.75 +-0.875 1 -0.625 +-1 0.75 0.5 +-1 0.75 0.25 +-1 0.875 0.375 +-0.875 -0.375 1 +-0.875 -0.125 1 +-0.75 -0.25 1 +0.25 -1 -0 +0.375 -1 -0.125 +0.25 -1 -0.25 +1 -0.25 1 +0.875 -0.375 1 +0.875 -0.125 1 +0.25 1 0.75 +0.25 1 1 +0.125 1 0.875 +-0 1 1 +-0 0.75 1 +-0.125 0.875 1 +-1 0.875 0.625 +-1 1 0.5 +0.375 1 -0.875 +0.25 1 -0.75 +0.25 1 -1 +0.875 -1 0.875 +0.875 -1 1 +1 -1 0.875 +-0.625 -0.125 1 +-0.5 -0 1 +-0.5 -0.25 1 +-1 -1 -0.375 +-1 -0.875 -0.375 +-1 -1 -0.25 +-0.875 -1 -0.375 +0.75 -0.5 -1 +0.75 -0.25 -1 +0.625 -0.375 -1 +1 -0.25 0.75 +1 -0.375 0.875 +1 0.375 -0.875 +1 0.5 -0.75 +1 0.5 -1 +0.875 -1 -0.625 +0.875 -1 -0.875 +0.75 -1 -0.75 +1 -0.25 -0.25 +1 -0.125 -0.375 +1 -0.25 -0.5 +-0.5 -1 1 +-0.375 -1 0.875 +-0.5 -1 0.75 +1 -0 -0.75 +1 -0.125 -0.625 +1 -0 -0.5 +0.75 -0.75 -1 +0.875 -0.625 -1 +1 -1 -0 +1 -0.875 0.125 +1 -0.875 -0.125 +-0.75 0.5 1 +-0.875 0.625 1 +-0.75 0.75 1 +1 0.5 -0 +1 0.375 0.125 +1 0.5 0.25 +-1 -0.375 0.125 +-1 -0.25 -0 +-1 -0.25 0.25 +1 -0.75 -1 +1 -0.75 -0.75 +1 -0.625 -0.875 +-0.375 0.625 -1 +-0.25 0.5 -1 +-0.25 0.75 -1 +-0.25 -1 1 +-0.25 -1 0.75 +0.125 1 -1 +0.125 1 -0.875 +-0 1 -1 +0.125 0.875 -1 +1 -0.625 0.125 +1 -0.75 0.25 +1 -0.625 0.375 +-1 -0.875 0.125 +-1 -1 -0 +-1 -0.875 -0.125 +-1 -0.375 -0.625 +-1 -0.25 -0.75 +-1 -0.25 -0.5 +-0.875 -0.625 1 +-0.75 -0.75 1 +-0.875 -0.875 1 +-0.625 -0.375 1 +0.75 -0 -1 +0.625 0.125 -1 +0.625 -0.125 -1 +-0.375 0.625 1 +-0.25 0.5 1 +-0.375 0.375 1 +0.625 1 -0.375 +0.625 1 -0.125 +0.5 1 -0.25 +-1 -0.625 -0.875 +-1 -0.5 -0.75 +-1 -0.625 -0.625 +-0.375 -1 -0.625 +-0.5 -1 -0.75 +-0.5 -1 -0.5 +-0.125 0.875 -1 +-0.25 1 -1 +1 0.125 0.625 +1 -0 0.5 +1 -0 0.75 +-0 -1 -0.5 +-0.125 -1 -0.625 +-0.125 -1 -0.375 +0.75 1 -0.25 +0.75 1 -0 +1 -0.5 -0 +1 -0.5 0.25 +-1 0.25 -0.5 +-1 0.375 -0.375 +-1 0.25 -0.25 +-0.375 -1 -0.875 +-1 0.125 -0.625 +-1 0.125 -0.875 +-1 0.25 -0.75 +-0 -1 0.75 +-0 -1 0.5 +-0.125 -1 0.625 +-1 -0.75 1 +-1 -0.75 0.75 +-1 -0.625 0.875 +0.5 -1 0.5 +0.5 -1 0.75 +0.625 -1 0.625 +1 0.75 -0.25 +1 0.625 -0.375 +1 0.625 -0.125 +1 0.625 -0.875 +-0.5 -1 -0.25 +-0.625 -1 -0.375 +-1 1 0.625 +-0.875 1 0.625 +-0.25 -1 -0.75 +-0.25 -1 -0.5 +1 -0.75 -0 +1 -0.75 -0.25 +-0.75 1 -1 +-0.75 0.75 -1 +-0.625 0.875 -1 +-0.625 1 -1 +-0.5 1 -1 +-0.625 1 -0.875 +0.125 -1 0.875 +0.125 -1 0.625 +-0.5 1 -0.75 +-0.5 1 -0.5 +-0.625 1 -0.625 +-0.625 0.125 -1 +-0.625 0.375 -1 +-0.75 0.25 -1 +1 0.625 0.875 +1 0.75 0.75 +1 0.625 0.625 +0.5 -0.75 -1 +0.375 -0.875 -1 +0.5 -1 -1 +-0.75 -1 -0.5 +-0.875 -1 -0.625 +-0.375 -0.375 1 +-0.5 -0.5 1 +-0.75 -1 -0.75 +-0.625 -1 -0.625 +1 -0.25 0.5 +1 -0.375 0.625 +-1 -0.375 0.875 +-1 -0.25 0.75 +-1 -0.25 1 +1 0.25 -0 +1 0.25 0.25 +-0.125 0.625 1 +-0.25 0.75 1 +-0.25 -0.75 1 +-0.25 -0.5 1 +-0.125 -0.625 1 +1 0.875 -0.375 +1 0.875 -0.125 +0.5 -0.25 -1 +-0.625 0.125 1 +-0.875 1 -0.375 +-0.875 1 -0.125 +-1 1 -0.25 +-0.375 -1 -0.375 +-0.375 -1 -0.125 +-0.625 0.375 1 +-0.5 0.25 1 +1 0.75 -0 +1 0.875 0.125 +1 0.375 1 +0.875 0.375 1 +1 0.5 1 +1 0.375 0.875 +-0.125 -0.375 1 +-0.125 -0.125 1 +-0 -0.25 1 +-0 1 -0.75 +-0.125 1 -0.875 +-1 0.875 0.125 +-1 0.75 -0 +-1 0.875 -0.125 +-0 1 0.5 +-0.125 1 0.625 +-0.125 1 0.375 +1 -0.125 0.125 +1 -0.25 0.25 +1 -0 0.25 +-1 -0.25 -0.25 +-1 -0.375 -0.125 +0.125 -0.875 1 +0.25 -0.75 1 +0.25 -1 1 +-0.125 -1 0.875 +-0 -1 1 +-0.375 -0.625 1 +-1 0.375 -1 +-1 0.5 -1 +-1 0.375 -0.875 +-0.875 0.375 -1 +1 -1 -0.5 +1 -0.875 -0.625 +1 -1 -0.625 +1 0.75 0.25 +1 0.875 -0.625 +1 0.75 -0.5 +-0.375 1 1 +-0.375 0.875 1 +-0.5 1 1 +-0.375 1 0.875 +-0.5 0.75 1 +-0.625 0.625 1 +-0.625 0.875 1 +1 0.75 -0.75 +1 0.875 -0.875 +1 0.75 -1 +0.375 -0.875 1 +0.375 -0.625 1 +0.5 -0.75 1 +0.5 -1 1 +0.625 -1 0.875 +-1 -0.125 -0.625 +-1 -0.125 -0.875 +-1 -0 -0.75 +1 0.625 0.375 +1 0.75 0.5 +-0.375 0.875 -1 +1 0.75 1 +0.875 1 -0.375 +1 1 -0.25 +0.875 1 -0.125 +0.75 1 -0.75 +0.875 1 -0.875 +0.875 1 -0.625 +0.75 0.75 -1 +0.75 1 -1 +0.625 0.875 -1 +-1 0.5 1 +-1 0.5 0.75 +-1 0.625 0.875 +1 -0.75 -0.5 +1 0.375 -0.625 +1 0.375 -0.375 +1 0.5 -0.5 +-0.75 1 -0 +-0.75 1 -0.25 +-0.625 1 -0.125 +-0.25 -0 -1 +-0.25 0.25 -1 +-0.375 0.125 -1 +-1 0.25 0.75 +-1 0.125 0.625 +-1 0.25 0.5 +-1 0.625 1 +-1 0.75 1 +1 -0.125 -1 +1 -0 -1 +0.875 -0.125 -1 +1 -0.125 -0.875 +1 0.25 -0.75 +1 0.25 -0.5 +0.375 -0.625 -1 +0.25 -0.75 -1 +-0 0.5 1 +-0.125 0.375 1 +0.625 -0.375 1 +0.75 -0.25 1 +0.75 -0.5 1 +-0.875 0.375 1 +-0.625 -0.875 -1 +-0.75 -0.75 -1 +-0.75 -1 -1 +-0.75 -0 1 +-0.75 0.25 1 +0.5 1 -0.75 +0.5 1 -1 +-0.75 -1 1 +-0.625 -1 0.875 +-0.75 -1 0.75 +0.5 -1 0.25 +0.375 -1 0.125 +0.375 -1 0.375 +-0.25 1 -0.25 +-0.25 1 -0 +-0.375 1 -0.125 +-1 1 0.375 +-0.875 1 0.375 +-1 0.5 -0.5 +-1 0.375 -0.625 +-1 0.5 -0.75 +-0.625 -0.875 1 +-0.5 -0.75 1 +1 -0.125 1 +1 -0.125 0.875 +-1 -0.625 0.625 +-1 -0.625 0.375 +-1 -0.5 0.5 +-1 0.5 0.5 +-1 0.625 0.625 +-0 -1 -0.75 +-0 -1 -1 +-0.125 -1 -0.875 +-1 1 -0.625 +-1 1 -0.5 +-1 0.875 -0.625 +0.625 0.875 1 +0.625 0.625 1 +0.5 0.75 1 +0.375 0.625 -1 +0.5 0.75 -1 +0.375 0.875 -1 +0.875 0.875 -1 +0.875 0.625 1 +0.75 0.75 1 +0.875 0.875 1 +-0 -0.75 1 +-0 -0.5 1 +0.125 -0.625 1 +-0.25 -0.25 1 +-0.375 -0.125 1 +-0.375 0.375 -1 +1 0.625 -0.625 +-1 -1 0.875 +-0.875 -1 0.875 +-1 -1 0.75 +-1 -0.875 0.875 +1 -0.625 -0.375 +1 -0.5 -0.25 +1 -0.5 -0.5 +0.875 0.125 -1 +-0.75 -1 -0.25 +-0.875 -1 1 +-1 -0.5 -0.25 +-1 -0.625 -0.375 +-1 -0.5 -0.5 +0.875 -0.375 -1 +0.375 -1 0.875 +0.375 -1 0.625 +-0.125 0.375 -1 +-0.125 0.125 -1 +0.25 -1 -1 +0.25 0.25 -1 +0.375 0.125 -1 +0.375 0.375 -1 +0.875 0.125 1 +0.75 -0 1 +0.75 0.25 1 +-1 1 -0.375 +-1 0.875 -0.375 +0.875 -0.625 1 +1 -0.5 1 +0.75 1 0.5 +0.875 1 0.375 +0.875 1 0.625 +-0.25 1 0.75 +-0.25 1 1 +-1 0.125 -0.125 +-1 0.25 -0 +-1 -0 -0 +1 -0.125 0.375 +0.375 1 -0.375 +0.375 1 -0.125 +0.25 1 -0.25 +-1 0.75 -0.5 +-0.25 -1 -0.25 +-0.25 -1 -0 +-0.125 -1 -0.125 +-1 -0.75 0.5 +-0 -1 0.25 +0.125 -1 0.375 +0.125 -1 0.125 +0.75 -1 0.25 +0.875 -1 0.125 +0.75 -1 -0 +-0.375 0.125 1 +0.625 -0.875 1 +-0.5 0.5 1 +-1 -0.875 1 +1 -0.625 1 +1 -0.75 1 +1 -0.625 0.875 +1 -0.125 0.625 +0.25 0.75 -1 +0.25 0.5 -1 +-0.625 1 0.125 +-0.625 1 0.375 +-0.75 1 0.25 +-0.25 -1 0.5 +-0.25 -1 0.25 +-0.375 -1 0.375 +1 0.875 -1 +0.5 -1 -0.5 +0.5 -1 -0.75 +0.375 -1 -0.625 +-1 -0.625 -0.125 +0.75 0.25 -1 +-0.5 -0.75 -1 +-0.625 -0.625 -1 +0.625 1 0.875 +0.5 1 0.75 +0.625 1 0.625 +1 -0.875 -0.375 +0.5 1 1 +0.375 1 0.875 +0.375 -0.375 -1 +0.375 -0.125 -1 +0.375 0.875 1 +0.125 1 0.375 +0.25 1 0.25 +0.25 1 0.5 +-0.625 -0.625 1 +1 -0.5 -0.75 +1 -0.5 -1 +-1 -1 1 +1 -1 -0.875 +1 -1 -0.75 +1 -0.875 -0.875 +0.125 -0.125 -1 +0.25 -0.25 -1 +0.25 -0 -1 +1 0.25 1 +0.5 1 0.5 +0.375 1 0.625 +-0.75 1 -0.5 +1 0.375 -1 +0.875 0.375 -1 +-1 -1 -0.125 +-0.875 -1 -0.125 +-0 -0.75 -1 +-0.125 -0.875 -1 +-0.125 -0.375 -1 +-0.25 -0.5 -1 +-0.125 -0.625 -1 +-1 1 -0 +1 -0.5 0.75 +1 0.5 -0.25 +1 0.125 0.875 +-1 0.25 0.25 +-1 0.125 0.375 +-1 0.125 0.125 +0.75 -1 -0.25 +0.875 -1 -0.375 +0.75 -1 -0.5 +0.75 -1 0.5 +0.875 -1 0.375 +0.375 -1 -0.875 +1 0.625 0.125 +-0.5 -1 -1 +-0.625 -1 -0.875 +0.625 1 0.375 +0.75 1 0.25 +1 -0.625 -0.625 +-0.375 1 -0.375 +-0.25 1 -0.5 +0.25 -1 0.5 +1 0.25 -0.25 +1 0.125 -0.125 +0.125 -0.625 -1 +0.125 -0.875 -1 +-1 -0.125 0.125 +-1 -0.125 0.375 +0.25 1 -0 +1 1 -0.75 +-1 0.375 0.875 +-1 0.75 -0.25 +1 0.875 0.375 +1 -0.375 0.125 +1 -0.25 -0 +-0.875 -0.375 -1 +-1 -0.5 -1 +-0.875 -0.625 -1 +-0.125 -0.875 1 +-0.625 -0.375 -1 +-0.5 -0.25 -1 +-0.625 -0.125 -1 +-0.75 1 0.75 +-0.75 1 1 +-0.875 1 0.875 +-0.75 -1 0.25 +-0.75 -1 0.5 +-0.625 -1 0.375 +-0.5 -1 -0 +1 -0.375 -0.125 +1 -0.375 -0.375 +-0.875 -1 0.375 +-0.875 -1 0.125 +-1 -0.75 -0.75 +-1 -0.75 -0.5 +-1 -0.875 -0.625 +0.5 -0.5 1 +-0.5 0.75 -1 +-0.75 -0.25 -1 +-1 -0.5 0.75 +1 1 -0.5 +-0 0.25 1 +-0 -0 1 +-0.125 0.125 1 +1 -0 1 +-1 0.625 -0.125 +0.75 -1 1 +0.75 -1 0.75 +0.5 -0.25 1 +0.625 -0.125 1 +0.75 1 0.75 +0.75 1 1 +-1 -0.875 -0.875 +-1 -1 -0.75 +-0 1 0.25 +-1 -1 0.25 +-1 -0.875 0.375 +0.25 -0.5 1 +1 -1 1 +1 -0.875 0.875 +0.75 0.5 1 +0.625 0.375 1 +-1 0.5 -0.25 +-1 0.5 -0 +-0.625 1 -0.375 +-0.5 1 -0.25 +-1 0.125 -0.375 +0.625 1 -0.875 +1 -0.75 0.75 +-0.75 -0.5 -1 +0.5 -1 -0.25 +0.625 -1 -0.375 +-1 0.375 1 +-1 0.25 1 +0.625 0.375 -1 +0.625 0.625 -1 +0.5 0.5 -1 +-1 -0.375 -0.375 +-0.875 0.875 1 +0.5 -0 -1 +0.875 1 0.125 +1 1 0.5 +1 0.875 0.625 +1 1 0.625 +-1 0.75 0.75 +-1 -0.75 -0.25 +-0.125 1 0.875 +-0.25 -0 1 +-1 -0.125 0.875 +-1 -0 0.75 +-1 -0 1 +-0.875 -1 0.625 +-0.375 1 0.125 +-0.25 1 0.25 +-0.375 1 0.375 +0.25 -1 0.25 +-0.125 1 0.125 +-0.125 1 1 +0.125 1 -0.625 +-0.375 -1 0.125 +1 0.5 0.5 +1 0.375 0.375 +0.25 1 -0.5 +-0.5 0.25 -1 +-0.75 -0.5 1 +1 -0.75 0.5 +0.625 -1 0.125 +0.5 -1 -0 +0.375 -0.375 1 +-1 0.25 -1 +-1 -1 0.125 +1 -0.25 -0.75 +0.875 0.625 -1 +-0.875 0.125 -1 +-1 -0 -1 +-0.875 -0.125 -1 +-1 -0.5 -0 +-0.375 1 -1 +-0.375 1 -0.875 +0.625 -1 0.375 +-0 1 0.75 +-0.375 1 0.625 +-0.25 -0.75 -1 +-0.375 -0.625 -1 +0.625 1 -1 +-1 -0 0.25 +0.125 1 -0.125 +0.375 1 -0.625 +-0.625 -1 0.625 +-0.5 -1 0.5 +-1 -0.375 1 +-0.875 -1 -0.875 +-1 0.375 -0.125 +0.625 -0.625 1 +1 0.125 -0.875 +1 0.125 -0.625 +1 0.125 -1 +-1 -0.5 0.25 +-0.25 -0.25 -1 +-0.125 -0.125 -1 +-1 0.75 -0.75 +-1 0.75 -1 +-1 0.875 -0.875 +0.875 -1 0.625 +-1 -0.375 -0.875 +1 -0 -0 +1 0.125 0.125 +0.625 -1 -0.875 +0.625 -1 -0.625 +-0.5 -0.5 -1 +0.125 1 0.125 +-0.375 -0.375 -1 +-1 -1 -0.625 +-1 -1 -0.5 +-1 0.625 0.375 +-1 -0.25 -1 +0.75 -1 -1 +-1 -0.125 0.625 +-1 -0 0.5 +1 -1 -0.125 +1 -1 -0.25 +0.875 -1 -0.125 +-1 -0.125 -0.375 +-1 -0 -0.5 +-1 0.875 0.875 +-0.5 1 0.5 +-0.5 1 0.75 +1 0.125 -0.375 +1 -1 0.25 +1 -0.875 0.375 +-0.25 0.25 1 +1 1 -0.625 +-1 -0.25 0.5 +-1 -0.375 0.375 +-0.125 -1 -1 +-0.25 1 -0.75 +1 -0.375 0.375 +0.125 1 0.625 +1 0.375 0.625 +1 0.5 0.75 +1 1 -0.125 +0.25 -0 1 +0.375 -0.125 1 +0.25 -0.25 1 +1 -1 -0.375 +-1 -0 -0.25 +-0.125 -1 1 +-1 0.125 0.875 +1 -0.5 0.5 +1 -0.625 0.625 +0.125 0.625 -1 +-0.625 1 0.625 +-0.625 1 0.875 +0.25 -1 0.75 +0.125 1 -0.375 +-0 1 -0.25 +-0 1 -0.5 +0.5 1 -0.5 +-1 -0.125 -0.125 +-0.75 -1 -0 +0.125 -0.375 1 +-0.125 1 -0.625 +-0.875 1 0.125 +-0.75 1 0.5 +-0.75 0.5 -1 +-0.875 0.625 -1 +0.625 0.125 1 +-1 0.375 0.125 +-1 0.375 0.375 +-0.25 -1 -1 +-0 -0.5 -1 +-0.875 0.875 -1 +1 0.125 0.375 +-0.375 -1 -1 +-0.375 -0.875 -1 +-0.375 -0.125 -1 +-0.5 -0 -1 +0.5 -0 1 +0.125 0.875 1 +0.125 0.625 1 +1 0.875 0.875 +1 1 0.75 +-0.625 -1 -0.125 +0.5 0.25 -1 +0.375 1 0.375 +0.5 1 0.25 +0.875 1 0.875 +0.125 -1 -0.125 +0.125 -1 -0.375 +0.625 -1 -0.125 +0.25 -0.5 -1 +1 -1 0.75 +0.25 -1 -0.5 +0.375 -1 -0.375 +-0.375 -0.875 1 +0.375 0.625 1 +0.25 0.75 1 +-0.25 1 0.5 +-0 -0.25 -1 +0.5 0.25 1 +-0 0.75 -1 +-1 -0.125 -1 +0.375 0.375 1 +0.5 0.5 1 +-0.125 1 -1 +0.125 -1 -0.875 +1 -0.375 -0.875 +1 -0.875 -1 +0.875 -0.875 -1 +-1 -0.5 1 +0.125 -0.375 -1 +-0.625 -1 0.125 +-0 -1 -0.25 +1 0.875 1 +0.125 0.375 1 +-0 1 -0 +-0.5 1 0.25 +0.125 0.125 -1 +0.125 0.375 -1 +-0 0.25 -1 +1 0.25 -1 +1 -0.375 -0.625 +0.75 1 -0.5 +0.125 0.125 1 +-1 -0.625 1 +0.375 1 -1 +-0 0.5 -1 +1 -0.875 0.625 +-1 0.625 -0.375 +1 1 0.25 +1 1 0.375 +-0 -1 -0 +0.125 -1 -0.625 +0.875 -0.875 1 +-1 -0.375 0.625 +0.625 1 0.125 +0.625 1 -0.625 +-1 0.125 -1 +-1 1 0.125 +-1 1 0.25 +-1 -0.75 -1 +-1 -0.875 -1 +-0.875 -0.875 -1 +-0.875 0.125 1 +1 1 0.125 +0.25 -1 -0.75 +1 -0.25 -1 +0.375 0.125 1 +0.25 0.25 1 +0.5 -0.5 -1 +-1 0.625 -0.625 +-1 -1 0.625 +-1 -0.875 0.625 +-0.5 -1 0.25 +0.375 1 1 +0.75 0.5 -1 +-1 0.625 0.125 +1 -0.625 -0.125 +-1 1 0.75 +-1 1 0.875 +0.125 -0.125 1 +0.375 -1 -1 +1 0.375 -0.125 +-1 0.875 -1 +-1 1 -1 +-1 0.5 0.25 +-0.5 1 -0 +1 -0.125 -0.125 +-0.375 -1 0.625 +-0.125 1 -0.375 +-0.125 1 -0.125 +-1 1 -0.125 +-0.125 -1 0.125 +1 -0 -0.25 +1 1 0.875 +-1 1 -0.75 +-1 1 -0.875 +0.25 0.5 1 +1 0.25 0.5 +0.75 -0.75 1 +1 1 -0 +-0.75 -0 -1 +1 1 -1 +1 1 -0.875 +1 -0.875 1 +0.875 -1 -1 +1 -1 -1 +0.875 1 -1 +-0.125 -1 0.375 +0.625 -0.875 -1 +1 0.25 0.75 +-1 0.625 -0.875 +-1 -0.375 -1 +-1 -0.75 -0 +0.625 -1 1 +0.375 -1 1 +0.625 -0.625 -1 +0.875 1 1 +-0.875 1 -1 +1 -0.375 1 +1 0.125 1 +-0 -0 -1 +-1 0.625 -1 +-1 0.375 0.625 +1 -0.375 -1 +-1 -0.125 1 +-0.375 -1 1 +0.625 -1 -1 +-1 -0.75 0.25 +-1 -0.625 0.125 +0.5 1 -0 +0.375 1 0.125 +1 -0.625 -1 +-0.625 -1 1 +-0.5 0.5 -1 +-0.625 0.625 -1 +0.125 1 1 +1 0.625 -1 +1 -1 0.375 +1 -1 0.5 +0.125 -1 1 +0.125 -1 -1 +0.625 1 1 +-0.375 1 -0.625 +-0.875 1 1 +-1 1 1 +-0.125 0.625 -1 +-1 0.125 1 +-1 -1 0.5 +1 0.625 1 +-1 -1 -0.875 +-1 -1 -1 +-0.875 -1 -1 +-1 -0.625 -1 +-0.625 -1 -1 +1 1 -0.375 +-1 -1 0.375 +-1 0.875 1 +1 -1 0.625 +1 1 1 +-0.625 1 1 +1 -1 0.125 +3 0 2 1 +3 3 5 4 +3 6 8 7 +3 9 11 10 +3 12 14 13 +3 15 17 16 +3 18 20 19 +3 21 22 5 +3 23 25 24 +3 26 28 27 +3 29 31 30 +3 32 34 33 +3 35 34 32 +3 36 38 37 +3 39 12 40 +3 41 43 42 +3 44 46 45 +3 47 49 48 +3 50 52 51 +3 53 55 54 +3 56 36 57 +3 58 60 59 +3 61 63 62 +3 64 66 65 +3 67 69 68 +3 70 72 71 +3 73 75 74 +3 51 77 76 +3 78 80 79 +3 81 80 78 +3 25 79 24 +3 82 84 83 +3 85 87 86 +3 88 90 89 +3 91 93 92 +3 8 94 29 +3 95 97 96 +3 98 100 99 +3 101 103 102 +3 104 106 105 +3 107 109 108 +3 110 75 111 +3 112 114 113 +3 115 117 116 +3 118 102 119 +3 120 121 82 +3 122 124 123 +3 125 107 108 +3 126 128 127 +3 129 131 130 +3 132 134 133 +3 135 137 136 +3 138 140 139 +3 42 43 141 +3 142 143 109 +3 22 21 144 +3 22 144 145 +3 116 147 146 +3 60 149 148 +3 150 152 151 +3 153 155 154 +3 153 154 152 +3 156 129 157 +3 158 160 159 +3 161 163 162 +3 164 166 165 +3 167 169 168 +3 170 35 171 +3 172 31 173 +3 174 175 170 +3 176 39 177 +3 178 180 179 +3 181 65 182 +3 20 184 183 +3 185 187 186 +3 188 189 138 +3 38 190 97 +3 29 30 191 +3 192 194 193 +3 195 196 142 +3 197 191 198 +3 189 200 199 +3 201 203 202 +3 201 204 203 +3 180 6 7 +3 205 207 206 +3 80 209 208 +3 210 212 211 +3 213 215 214 +3 216 218 217 +3 219 220 68 +3 221 223 222 +3 224 129 225 +3 185 186 226 +3 227 229 228 +3 230 227 228 +3 231 233 232 +3 231 44 233 +3 199 200 234 +3 235 188 236 +3 237 239 238 +3 240 239 237 +3 241 243 242 +3 195 142 109 +3 191 30 198 +3 244 246 245 +3 247 249 248 +3 250 136 251 +3 252 254 253 +3 255 256 166 +3 257 75 73 +3 165 258 164 +3 67 68 220 +3 259 261 260 +3 262 264 263 +3 265 267 266 +3 268 270 269 +3 271 232 71 +3 272 274 273 +3 275 277 276 +3 278 280 279 +3 281 283 282 +3 284 62 285 +3 284 285 270 +3 83 148 82 +3 286 288 287 +3 289 286 287 +3 272 291 290 +3 292 168 293 +3 294 183 295 +3 296 298 297 +3 268 299 62 +3 300 302 301 +3 303 191 304 +3 305 306 23 +3 304 191 197 +3 307 309 308 +3 310 312 311 +3 313 315 314 +3 316 22 317 +3 5 22 316 +3 318 320 319 +3 321 50 322 +3 323 14 12 +3 324 323 12 +3 325 327 326 +3 328 269 329 +3 330 332 331 +3 333 334 2 +3 333 335 334 +3 336 338 337 +3 339 341 340 +3 263 266 262 +3 342 265 266 +3 235 236 244 +3 343 345 344 +3 346 348 347 +3 349 350 172 +3 74 351 73 +3 236 352 244 +3 353 355 354 +3 353 356 355 +3 357 359 358 +3 288 95 360 +3 361 35 170 +3 362 307 93 +3 362 354 307 +3 363 365 364 +3 79 80 208 +3 36 37 366 +3 367 368 136 +3 369 370 279 +3 371 293 168 +3 372 374 373 +3 375 377 376 +3 378 194 192 +3 378 379 194 +3 249 247 250 +3 380 381 13 +3 382 384 383 +3 385 240 386 +3 387 389 388 +3 218 390 217 +3 391 393 392 +3 335 394 379 +3 395 397 396 +3 325 326 398 +3 399 401 400 +3 402 404 403 +3 405 100 198 +3 250 406 249 +3 198 407 197 +3 408 132 356 +3 408 93 132 +3 409 380 410 +3 411 409 410 +3 412 114 324 +3 386 238 184 +3 339 414 413 +3 415 417 416 +3 418 420 419 +3 223 247 222 +3 421 246 342 +3 245 246 421 +3 20 386 184 +3 157 130 400 +3 422 424 423 +3 425 363 364 +3 95 96 426 +3 427 300 428 +3 224 77 131 +3 429 431 430 +3 231 232 432 +3 430 434 433 +3 435 436 190 +3 433 437 338 +3 438 440 439 +3 322 173 441 +3 118 101 102 +3 72 443 442 +3 444 353 354 +3 444 356 353 +3 445 447 446 +3 45 445 446 +3 448 450 449 +3 451 202 375 +3 452 453 430 +3 454 192 276 +3 455 43 41 +3 455 456 43 +3 457 86 87 +3 458 86 457 +3 459 331 460 +3 291 272 273 +3 461 463 462 +3 210 464 212 +3 465 177 40 +3 466 140 64 +3 467 114 112 +3 468 470 469 +3 471 473 472 +3 132 93 91 +3 202 377 375 +3 402 475 474 +3 183 184 99 +3 423 476 169 +3 66 477 255 +3 478 108 479 +3 480 382 481 +3 482 357 271 +3 483 313 484 +3 157 400 485 +3 486 181 487 +3 488 489 459 +3 69 491 490 +3 492 392 393 +3 478 125 108 +3 493 263 264 +3 233 446 232 +3 233 44 446 +3 268 269 494 +3 212 495 211 +3 200 496 234 +3 497 498 217 +3 499 501 500 +3 225 346 502 +3 334 335 379 +3 503 505 504 +3 427 478 300 +3 506 508 507 +3 509 511 510 +3 142 196 512 +3 513 358 514 +3 515 516 509 +3 517 519 518 +3 248 249 520 +3 152 154 521 +3 503 522 505 +3 325 523 327 +3 105 365 88 +3 235 524 188 +3 525 527 526 +3 528 375 14 +3 495 529 211 +3 14 297 13 +3 413 25 341 +3 530 531 26 +3 14 376 297 +3 532 296 533 +3 267 340 306 +3 379 495 212 +3 534 429 535 +3 167 168 292 +3 536 537 519 +3 538 213 438 +3 320 228 229 +3 539 540 85 +3 376 533 297 +3 222 541 348 +3 28 543 542 +3 544 337 545 +3 199 234 477 +3 150 1 155 +3 350 31 172 +3 352 42 141 +3 150 155 153 +3 150 153 152 +3 546 547 529 +3 277 549 548 +3 550 124 122 +3 551 306 305 +3 552 410 543 +3 549 483 159 +3 446 447 232 +3 553 501 499 +3 345 535 344 +3 104 105 500 +3 422 555 554 +3 556 557 299 +3 556 494 557 +3 558 560 559 +3 220 561 363 +3 360 95 426 +3 62 562 285 +3 296 532 520 +3 97 563 96 +3 564 481 383 +3 565 567 566 +3 565 384 567 +3 270 285 568 +3 243 507 63 +3 518 569 364 +3 99 184 98 +3 29 94 31 +3 385 386 570 +3 571 206 527 +3 572 574 573 +3 367 136 250 +3 354 575 309 +3 576 578 577 +3 311 312 579 +3 577 215 580 +3 581 386 20 +3 570 386 581 +3 79 582 24 +3 441 321 322 +3 512 196 583 +3 584 585 66 +3 391 586 393 +3 513 497 120 +3 134 523 325 +3 161 162 587 +3 91 92 588 +3 84 589 83 +3 590 310 591 +3 592 541 248 +3 127 128 593 +3 0 1 150 +3 126 122 128 +3 539 594 516 +3 539 85 594 +3 595 289 54 +3 246 596 342 +3 236 138 139 +3 597 599 598 +3 600 67 220 +3 257 111 75 +3 601 111 257 +3 601 602 111 +3 310 590 603 +3 604 18 17 +3 605 240 385 +3 550 122 126 +3 606 607 462 +3 569 425 364 +3 485 400 579 +3 608 306 551 +3 267 306 608 +3 491 609 490 +3 492 393 610 +3 391 611 586 +3 124 387 388 +3 511 613 612 +3 614 6 180 +3 614 180 178 +3 302 174 615 +3 616 124 388 +3 617 520 249 +3 618 290 619 +3 287 620 618 +3 287 360 620 +3 453 440 15 +3 326 327 621 +3 622 278 623 +3 624 626 625 +3 319 123 318 +3 474 627 531 +3 241 242 407 +3 472 473 44 +3 500 105 628 +3 245 235 244 +3 487 630 629 +3 479 174 302 +3 46 632 631 +3 633 427 428 +3 492 610 634 +3 130 399 400 +3 462 635 622 +3 568 21 3 +3 6 91 588 +3 415 275 417 +3 636 637 519 +3 171 637 636 +3 3 4 638 +3 639 628 89 +3 239 243 241 +3 46 631 640 +3 641 642 491 +3 214 570 604 +3 503 553 522 +3 467 528 114 +3 438 439 634 +3 643 644 60 +3 643 645 644 +3 21 5 3 +3 646 647 252 +3 188 260 189 +3 646 252 90 +3 21 568 648 +3 649 650 605 +3 612 52 308 +3 368 135 136 +3 55 619 651 +3 633 428 503 +3 59 653 652 +3 100 654 99 +3 655 524 235 +3 655 264 524 +3 656 69 657 +3 331 658 460 +3 331 332 658 +3 111 602 659 +3 89 252 253 +3 584 66 255 +3 497 217 660 +3 213 604 661 +3 662 663 204 +3 447 70 71 +3 584 663 662 +3 260 664 189 +3 260 261 664 +3 206 571 349 +3 96 558 426 +3 665 667 666 +3 644 668 432 +3 644 472 668 +3 646 669 647 +3 256 496 566 +3 308 52 50 +3 470 388 389 +3 595 54 49 +3 670 225 502 +3 670 224 225 +3 463 606 462 +3 259 118 261 +3 575 515 510 +3 574 671 573 +3 106 517 518 +3 672 465 673 +3 413 674 81 +3 675 676 650 +3 677 485 368 +3 678 680 679 +3 94 441 173 +3 305 611 681 +3 219 682 669 +3 516 683 509 +3 207 347 684 +3 484 685 659 +3 686 193 464 +3 281 557 494 +3 603 590 402 +3 687 145 506 +3 604 570 18 +3 688 689 151 +3 376 377 690 +3 339 413 341 +3 691 468 692 +3 693 146 125 +3 552 411 410 +3 377 545 690 +3 694 463 461 +3 684 347 348 +3 660 217 176 +3 363 561 365 +3 607 635 462 +3 400 401 579 +3 451 201 202 +3 451 204 201 +3 667 541 592 +3 695 150 151 +3 112 113 696 +3 54 289 53 +3 469 470 609 +3 697 693 125 +3 698 693 697 +3 100 405 654 +3 197 242 61 +3 160 548 159 +3 504 700 699 +3 532 533 701 +3 19 703 702 +3 611 391 681 +3 566 705 704 +3 706 142 512 +3 628 88 89 +3 663 166 164 +3 332 146 693 +3 470 468 388 +3 473 46 44 +3 135 310 603 +3 96 563 707 +3 213 661 438 +3 140 477 64 +3 560 339 340 +3 137 531 251 +3 689 625 695 +3 708 452 709 +3 710 534 535 +3 711 712 11 +3 591 554 713 +3 714 292 293 +3 715 28 26 +3 715 543 28 +3 64 477 66 +3 661 15 440 +3 424 717 716 +3 718 76 185 +3 160 454 548 +3 566 704 165 +3 437 720 719 +3 215 577 721 +3 276 277 548 +3 722 694 461 +3 545 723 690 +3 81 724 80 +3 725 253 598 +3 599 725 598 +3 506 507 676 +3 723 727 726 +3 709 452 480 +3 328 329 638 +3 728 111 209 +3 728 110 111 +3 65 585 182 +3 572 641 179 +3 330 331 729 +3 94 173 31 +3 143 361 170 +3 346 347 187 +3 442 443 730 +3 490 609 389 +3 77 418 131 +3 731 732 70 +3 447 731 70 +3 412 39 176 +3 733 178 523 +3 483 315 313 +3 190 436 563 +3 234 496 256 +3 288 37 95 +3 106 364 365 +3 488 734 714 +3 485 579 312 +3 80 724 110 +3 429 430 433 +3 68 490 682 +3 68 69 490 +3 139 140 466 +3 295 183 99 +3 8 29 303 +3 509 735 511 +3 347 207 205 +3 736 115 712 +3 113 114 412 +3 509 683 735 +3 209 685 208 +3 518 33 569 +3 616 691 547 +3 258 737 345 +3 258 704 737 +3 294 738 703 +3 179 641 656 +3 278 279 370 +3 202 343 544 +3 642 469 609 +3 10 717 554 +3 610 679 739 +3 740 578 576 +3 741 743 742 +3 230 597 593 +3 218 113 390 +3 744 290 618 +3 360 426 456 +3 595 745 730 +3 262 746 264 +3 503 428 553 +3 439 440 708 +3 190 563 97 +3 461 462 622 +3 525 747 738 +3 132 748 134 +3 132 91 748 +3 582 79 208 +3 53 618 619 +3 472 44 231 +3 198 100 407 +3 133 134 325 +3 432 232 271 +3 416 417 687 +3 432 271 149 +3 749 25 23 +3 341 25 749 +3 119 564 261 +3 742 743 750 +3 332 116 146 +3 461 622 623 +3 589 552 751 +3 635 699 622 +3 752 318 546 +3 647 550 126 +3 187 205 186 +3 340 559 560 +3 413 81 25 +3 592 520 532 +3 689 695 151 +3 753 754 496 +3 753 383 754 +3 19 20 183 +3 399 755 401 +3 572 573 641 +3 712 115 756 +3 410 380 757 +3 672 660 177 +3 482 72 442 +3 9 311 579 +3 178 758 523 +3 759 480 481 +3 745 442 730 +3 337 338 727 +3 305 23 611 +3 294 703 19 +3 590 713 404 +3 590 591 713 +3 101 760 681 +3 149 271 357 +3 761 127 593 +3 597 761 593 +3 610 678 679 +3 60 432 149 +3 622 699 278 +3 762 763 686 +3 210 763 762 +3 764 765 536 +3 764 766 765 +3 471 555 473 +3 148 83 59 +3 423 169 631 +3 767 304 299 +3 768 753 200 +3 768 564 753 +3 358 359 514 +3 424 769 476 +3 595 770 289 +3 195 395 196 +3 10 11 717 +3 98 184 238 +3 771 772 665 +3 15 16 434 +3 342 596 265 +3 47 498 513 +3 65 66 585 +3 482 442 359 +3 38 773 190 +3 156 677 223 +3 225 129 156 +3 573 282 642 +3 584 166 663 +3 31 350 30 +3 232 447 71 +3 296 297 533 +3 586 24 582 +3 454 276 548 +3 774 318 752 +3 355 775 575 +3 355 776 775 +3 419 420 583 +3 420 777 583 +3 778 16 437 +3 434 16 778 +3 583 196 396 +3 311 591 310 +3 426 558 779 +3 309 510 612 +3 780 529 547 +3 136 137 251 +3 615 171 537 +3 619 290 291 +3 143 170 175 +3 33 87 569 +3 781 120 82 +3 511 777 613 +3 644 432 60 +3 244 141 246 +3 548 549 159 +3 241 98 238 +3 598 254 127 +3 428 301 553 +3 420 613 777 +3 595 730 770 +3 681 391 103 +3 366 37 288 +3 651 291 486 +3 253 254 598 +3 615 174 171 +3 782 783 508 +3 648 783 782 +3 282 469 642 +3 134 733 523 +3 632 423 631 +3 784 667 665 +3 69 656 491 +3 491 642 609 +3 477 234 255 +3 283 468 469 +3 299 61 62 +3 785 168 169 +3 476 785 169 +3 374 372 414 +3 488 293 489 +3 242 197 407 +3 298 13 297 +3 435 190 773 +3 65 786 64 +3 466 64 786 +3 527 654 571 +3 787 788 695 +3 626 788 787 +3 539 516 515 +3 115 330 756 +3 789 780 547 +3 19 702 18 +3 646 219 669 +3 716 756 769 +3 637 33 519 +3 790 549 277 +3 791 498 47 +3 671 557 281 +3 549 790 315 +3 767 7 303 +3 791 216 498 +3 649 605 578 +3 644 645 472 +3 792 77 51 +3 226 172 173 +3 691 789 547 +3 519 33 518 +3 366 288 770 +3 496 565 566 +3 189 199 138 +3 122 123 319 +3 793 680 685 +3 208 685 680 +3 645 58 403 +3 616 388 691 +3 468 691 388 +3 214 721 385 +3 117 397 395 +3 219 68 682 +3 146 147 107 +3 668 231 432 +3 668 472 231 +3 344 336 337 +3 431 452 430 +3 793 313 794 +3 275 193 686 +3 515 509 510 +3 795 464 193 +3 795 212 464 +3 144 21 782 +3 144 782 145 +3 337 544 344 +3 458 361 683 +3 584 255 166 +3 796 396 397 +3 307 321 92 +3 308 309 612 +3 30 405 198 +3 248 541 222 +3 797 55 651 +3 798 705 710 +3 704 705 798 +3 525 738 294 +3 492 634 439 +3 107 147 195 +3 220 219 561 +3 799 0 800 +3 799 800 626 +3 801 719 720 +3 264 259 524 +3 701 723 771 +3 158 154 155 +3 755 736 711 +3 104 764 517 +3 315 576 314 +3 802 696 182 +3 714 449 435 +3 406 530 803 +3 261 564 804 +3 251 531 530 +3 751 552 543 +3 714 734 449 +3 790 415 740 +3 779 265 596 +3 161 805 163 +3 433 338 336 +3 383 384 565 +3 806 807 245 +3 806 263 807 +3 808 757 542 +3 543 808 542 +3 527 206 526 +3 174 170 171 +3 809 732 810 +3 45 809 810 +3 117 395 147 +3 384 534 710 +3 811 266 263 +3 342 266 811 +3 241 238 239 +3 384 710 705 +3 650 676 239 +3 617 803 298 +3 113 412 390 +3 723 726 771 +3 714 293 488 +3 575 510 309 +3 638 329 3 +3 3 329 568 +3 769 729 371 +3 786 181 486 +3 750 743 369 +3 518 364 106 +3 682 389 387 +3 321 441 92 +3 544 545 377 +3 130 812 399 +3 418 419 812 +3 236 188 138 +3 640 813 56 +3 258 345 343 +3 804 768 200 +3 804 564 768 +3 474 475 627 +3 589 751 653 +3 764 536 517 +3 301 302 766 +3 736 117 115 +3 465 40 381 +3 218 629 630 +3 758 179 656 +3 108 109 175 +3 207 526 206 +3 449 450 436 +3 672 673 84 +3 298 380 13 +3 411 465 381 +3 449 436 435 +3 482 71 72 +3 380 298 803 +3 196 395 396 +3 777 512 583 +3 460 693 606 +3 651 619 291 +3 7 8 303 +3 2 454 1 +3 607 427 633 +3 814 662 204 +3 422 423 632 +3 797 791 48 +3 624 625 815 +3 372 741 742 +3 128 122 319 +3 679 680 793 +3 299 304 61 +3 681 103 101 +3 466 273 274 +3 143 175 109 +3 707 374 560 +3 186 205 349 +3 52 612 613 +3 647 254 252 +3 92 441 588 +3 736 712 711 +3 754 565 496 +3 754 383 565 +3 456 426 779 +3 744 41 290 +3 360 456 744 +3 816 628 639 +3 499 816 639 +3 726 772 771 +3 490 389 682 +3 546 616 547 +3 275 276 193 +3 594 86 516 +3 594 85 86 +3 85 817 87 +3 818 530 406 +3 818 251 530 +3 264 746 259 +3 119 759 481 +3 819 250 247 +3 819 367 250 +3 522 553 499 +3 820 813 167 +3 821 710 535 +3 345 821 535 +3 813 820 56 +3 820 36 56 +3 14 375 376 +3 470 389 609 +3 39 412 324 +3 36 366 57 +3 57 366 443 +3 357 482 359 +3 283 692 468 +3 248 222 247 +3 695 788 822 +3 800 822 788 +3 634 538 438 +3 629 218 216 +3 772 747 665 +3 525 526 747 +3 650 239 240 +3 340 341 306 +3 823 13 381 +3 40 823 381 +3 807 493 245 +3 807 263 493 +3 824 375 528 +3 467 824 528 +3 536 519 517 +3 219 646 90 +3 19 183 294 +3 694 459 463 +3 489 293 371 +3 330 116 332 +3 463 459 460 +3 393 586 678 +3 641 573 642 +3 722 623 825 +3 129 130 157 +3 826 625 689 +3 815 625 826 +3 255 234 256 +3 586 582 678 +3 189 804 200 +3 254 647 126 +3 606 698 607 +3 318 123 546 +3 437 16 720 +3 50 718 322 +3 661 17 15 +3 760 551 305 +3 760 305 681 +3 779 558 559 +3 461 623 722 +3 307 354 309 +3 504 699 635 +3 584 662 585 +3 663 164 203 +3 814 204 451 +3 199 140 138 +3 15 434 453 +3 338 719 727 +3 706 512 735 +3 767 299 557 +3 281 827 283 +3 709 480 759 +3 707 560 558 +3 385 570 214 +3 197 61 304 +3 739 538 634 +3 338 437 719 +3 633 503 504 +3 453 434 430 +3 270 568 329 +3 270 329 269 +3 684 667 784 +3 256 566 165 +3 99 654 295 +3 772 726 801 +3 712 716 11 +3 180 572 179 +3 262 760 746 +3 226 718 185 +3 828 366 770 +3 730 828 770 +3 119 481 564 +3 169 167 813 +3 71 482 271 +3 404 645 403 +3 404 471 645 +3 318 774 320 +3 624 815 774 +3 774 815 320 +3 624 774 394 +3 335 624 394 +3 261 118 119 +3 76 502 185 +3 746 760 101 +3 829 7 574 +3 829 574 572 +3 672 84 121 +3 830 76 718 +3 830 51 76 +3 113 218 696 +3 620 744 618 +3 620 360 744 +3 592 248 520 +3 307 92 93 +3 132 133 356 +3 831 813 640 +3 631 831 640 +3 74 369 279 +3 192 193 276 +3 379 394 495 +3 394 752 495 +3 334 192 2 +3 672 177 465 +3 256 165 166 +3 382 534 384 +3 700 161 587 +3 792 420 418 +3 51 52 792 +3 52 613 792 +3 226 186 172 +3 792 613 420 +3 349 172 186 +3 274 42 352 +3 244 352 141 +3 202 544 377 +3 769 371 476 +3 423 424 476 +3 723 701 690 +3 16 702 720 +3 85 832 817 +3 832 833 817 +3 834 835 709 +3 484 313 793 +3 686 763 317 +3 786 486 273 +3 70 836 72 +3 70 57 836 +3 833 621 600 +3 61 242 63 +3 139 466 274 +3 735 512 777 +3 466 786 273 +3 474 531 137 +3 552 589 673 +3 837 308 50 +3 837 50 321 +3 380 803 757 +3 459 694 488 +3 567 705 566 +3 567 384 705 +3 348 541 684 +3 207 784 526 +3 413 414 674 +3 303 304 767 +3 616 123 124 +3 546 123 616 +3 427 698 478 +3 606 693 698 +3 747 526 784 +3 629 216 791 +3 121 120 497 +3 734 448 449 +3 747 784 665 +3 358 513 120 +3 58 643 60 +3 58 645 643 +3 523 758 327 +3 588 94 8 +3 245 421 806 +3 27 542 757 +3 27 28 542 +3 295 654 527 +3 792 418 77 +3 322 718 226 +3 322 226 173 +3 73 351 838 +3 587 838 351 +3 669 124 550 +3 647 669 550 +3 774 752 394 +3 645 471 472 +3 368 312 135 +3 121 497 660 +3 672 121 660 +3 147 395 195 +3 485 312 368 +3 2 192 454 +3 393 678 610 +3 431 534 382 +3 480 431 382 +3 480 452 431 +3 611 24 586 +3 611 23 24 +3 560 374 339 +3 374 414 339 +3 399 796 755 +3 605 721 578 +3 328 638 789 +3 675 687 506 +3 506 676 675 +3 649 675 650 +3 578 721 577 +3 98 241 407 +3 649 578 740 +3 789 691 692 +3 223 677 367 +3 677 368 367 +3 561 219 90 +3 633 504 635 +3 561 90 88 +3 365 561 88 +3 11 9 711 +3 521 73 838 +3 722 825 448 +3 722 448 734 +3 460 606 463 +3 115 116 330 +3 559 340 267 +3 213 214 604 +3 588 8 6 +3 734 488 694 +3 712 756 716 +3 722 734 694 +3 551 760 262 +3 266 551 262 +3 218 630 696 +3 182 696 630 +3 487 181 630 +3 835 492 439 +3 181 182 630 +3 406 803 617 +3 617 249 406 +3 493 655 235 +3 493 264 655 +3 355 575 354 +3 356 133 776 +3 776 133 398 +3 133 325 398 +3 356 776 355 +3 486 291 273 +3 530 757 803 +3 627 26 531 +3 627 715 26 +3 751 543 715 +3 165 704 258 +3 117 147 116 +3 534 431 429 +3 535 336 344 +3 265 559 267 +3 600 621 67 +3 673 411 552 +3 48 54 55 +3 274 272 42 +3 559 265 779 +3 585 662 802 +3 814 802 662 +3 545 337 727 +3 673 465 411 +3 209 111 659 +3 658 693 460 +3 658 332 693 +3 151 839 688 +3 163 805 597 +3 604 17 661 +3 254 126 127 +3 152 839 151 +3 152 521 839 +3 840 18 702 +3 17 18 840 +3 799 2 0 +3 335 799 626 +3 624 335 626 +3 841 43 596 +3 141 43 841 +3 359 442 745 +3 125 146 107 +3 698 427 607 +3 842 843 475 +3 842 653 843 +3 505 522 805 +3 105 88 628 +3 379 212 194 +3 664 804 189 +3 664 261 804 +3 680 582 208 +3 545 727 723 +3 724 674 750 +3 674 724 81 +3 814 451 467 +3 422 632 555 +3 632 473 555 +3 39 324 12 +3 114 528 324 +3 844 223 221 +3 844 156 223 +3 167 773 820 +3 473 632 46 +3 571 654 405 +3 772 801 738 +3 703 738 801 +3 634 610 739 +3 747 772 738 +3 178 179 758 +3 331 459 489 +3 769 756 729 +3 756 330 729 +3 845 489 371 +3 729 845 371 +3 680 678 582 +3 414 372 742 +3 242 243 63 +3 755 796 397 +3 414 742 674 +3 674 742 750 +3 736 397 117 +3 755 397 736 +3 677 157 485 +3 295 527 525 +3 685 209 659 +3 607 633 635 +3 107 195 109 +3 703 801 720 +3 438 661 440 +3 702 703 720 +3 521 838 839 +3 158 155 160 +3 155 1 160 +3 454 160 1 +3 758 656 657 +3 327 758 657 +3 588 441 94 +3 721 214 215 +3 538 215 213 +3 525 294 295 +3 733 91 6 +3 59 60 148 +3 590 404 402 +3 76 77 224 +3 225 221 346 +3 348 346 221 +3 677 156 157 +3 348 221 222 +3 739 580 538 +3 538 580 215 +3 682 387 669 +3 577 580 314 +3 780 4 211 +3 4 210 211 +3 275 686 417 +3 574 7 767 +3 671 282 573 +3 281 282 671 +3 401 711 9 +3 755 711 401 +3 217 498 216 +3 791 47 48 +3 351 74 279 +3 549 315 483 +3 791 797 629 +3 629 797 487 +3 741 372 450 +3 448 741 450 +3 448 825 741 +3 743 741 825 +3 721 605 385 +3 419 396 796 +3 650 240 605 +3 475 843 627 +3 35 637 171 +3 846 433 336 +3 429 433 846 +3 653 751 843 +3 471 713 555 +3 404 713 471 +3 713 554 555 +3 514 47 513 +3 514 49 47 +3 716 769 424 +3 717 11 716 +3 554 717 422 +3 282 283 469 +3 84 673 589 +3 521 257 73 +3 659 847 484 +3 483 484 847 +3 847 159 483 +3 158 159 847 +3 145 687 317 +3 436 450 373 +3 450 372 373 +3 317 22 145 +3 417 317 687 +3 82 121 84 +3 135 312 310 +3 135 603 137 +3 603 474 137 +3 686 317 417 +3 5 763 210 +3 4 5 210 +3 149 781 148 +3 149 357 781 +3 781 358 120 +3 148 781 82 +3 797 48 55 +3 373 707 563 +3 436 373 563 +3 33 34 87 +3 62 63 562 +3 145 508 506 +3 568 285 648 +3 848 849 562 +3 508 849 848 +3 21 648 782 +3 145 782 508 +3 507 562 63 +3 253 639 89 +3 724 850 110 +3 851 767 557 +3 851 557 671 +3 599 499 639 +3 522 499 599 +3 522 599 805 +3 805 599 597 +3 850 75 110 +3 850 74 75 +3 850 369 74 +3 373 374 707 +3 343 344 544 +3 602 158 847 +3 602 847 659 +3 204 663 203 +3 202 203 343 +3 683 706 735 +3 154 158 602 +3 154 257 521 +3 415 416 740 +3 692 328 789 +3 649 740 416 +3 649 416 675 +3 416 687 675 +3 541 667 684 +3 349 571 350 +3 789 638 780 +3 638 4 780 +3 405 350 571 +3 350 405 30 +3 142 706 143 +3 743 825 370 +3 784 207 684 +3 600 220 363 +3 452 708 453 +3 802 182 585 +3 29 191 303 +3 656 641 491 +3 453 708 440 +3 801 726 719 +3 835 708 709 +3 835 439 708 +3 576 577 314 +3 726 727 719 +3 315 790 576 +3 740 576 790 +3 739 794 580 +3 177 660 176 +3 177 39 40 +3 162 839 838 +3 587 162 838 +3 163 688 162 +3 679 793 794 +3 679 794 739 +3 580 794 314 +3 313 314 794 +3 617 296 520 +3 617 298 296 +3 412 176 390 +3 834 392 835 +3 392 492 835 +3 229 593 128 +3 391 392 103 +3 102 103 834 +3 103 392 834 +3 65 181 786 +3 53 619 55 +3 707 558 96 +3 41 272 290 +3 41 42 272 +3 780 211 529 +3 752 546 529 +3 752 529 495 +3 790 277 415 +3 415 277 275 +3 511 735 777 +3 154 601 257 +3 154 602 601 +3 327 657 621 +3 163 597 230 +3 163 230 688 +3 230 689 688 +3 230 228 689 +3 320 815 228 +3 319 229 128 +3 320 229 319 +3 540 832 85 +3 852 515 575 +3 776 398 540 +3 540 398 832 +3 776 540 852 +3 836 443 72 +3 836 57 443 +3 493 235 245 +3 532 666 592 +3 666 532 701 +3 131 418 812 +3 311 9 10 +3 591 311 10 +3 513 498 497 +3 579 401 9 +3 666 771 665 +3 666 667 592 +3 224 131 129 +3 745 595 49 +3 514 359 745 +3 102 759 119 +3 102 834 759 +3 834 709 759 +3 140 199 477 +3 853 343 203 +3 164 853 203 +3 46 640 45 +3 640 56 732 +3 854 615 537 +3 536 854 537 +3 855 856 854 +3 765 855 854 +3 765 856 855 +3 44 45 446 +3 494 827 281 +3 494 269 827 +3 328 827 269 +3 280 351 279 +3 283 827 692 +3 827 328 692 +3 280 587 351 +3 706 361 143 +3 690 701 533 +3 699 280 278 +3 376 690 533 +3 699 700 280 +3 700 587 280 +3 817 425 569 +3 833 600 425 +3 833 425 817 +3 361 706 683 +3 764 104 857 +3 501 764 857 +3 820 38 36 +3 820 773 38 +3 857 104 500 +3 501 857 500 +3 37 97 95 +3 48 49 54 +3 744 455 41 +3 744 456 455 +3 657 69 67 +3 657 67 621 +3 583 396 419 +3 289 287 53 +3 53 287 618 +3 288 360 287 +3 167 292 773 +3 478 858 300 +3 478 479 858 +3 732 57 70 +3 732 56 57 +3 858 302 300 +3 858 479 302 +3 402 403 475 +3 475 403 652 +3 524 859 188 +3 524 259 859 +3 361 458 35 +3 481 382 383 +3 859 260 188 +3 859 259 260 +3 753 564 383 +3 200 753 496 +3 458 34 35 +3 292 714 435 +3 292 435 773 +3 86 458 516 +3 852 860 515 +3 852 540 860 +3 422 717 424 +3 817 569 87 +3 832 398 326 +3 832 326 833 +3 326 621 833 +3 352 139 274 +3 106 365 105 +3 187 347 205 +3 90 252 89 +3 130 131 812 +3 502 346 187 +3 860 539 515 +3 860 540 539 +3 83 589 653 +3 603 402 474 +3 59 83 653 +3 516 458 683 +3 479 108 175 +3 479 175 174 +3 300 301 428 +3 553 301 501 +3 104 517 106 +3 301 766 501 +3 501 766 764 +3 530 27 757 +3 530 26 27 +3 161 505 805 +3 700 505 161 +3 504 505 700 +3 502 187 185 +3 217 390 176 +3 701 771 666 +3 685 484 793 +3 750 369 850 +3 724 750 850 +3 651 486 487 +3 797 651 487 +3 781 357 358 +3 591 10 554 +3 100 98 407 +3 812 419 796 +3 205 206 349 +3 399 812 796 +3 779 596 456 +3 456 596 43 +3 802 112 696 +3 814 112 802 +3 814 467 112 +3 425 600 363 +3 743 370 369 +3 623 370 825 +3 623 278 370 +3 669 387 124 +3 688 839 162 +3 510 511 612 +3 352 236 139 +3 746 118 259 +3 746 101 118 +3 38 97 37 +3 514 745 49 +3 856 302 615 +3 766 302 856 +3 640 732 809 +3 45 640 809 +3 258 343 853 +3 164 258 853 +3 268 62 284 +3 268 284 270 +3 285 562 861 +3 285 861 648 +3 507 848 562 +3 508 848 507 +3 861 562 849 +3 861 849 783 +3 783 849 508 +3 861 783 648 +3 537 636 519 +3 171 636 537 +3 535 846 336 +3 429 846 535 +3 228 826 689 +3 815 826 228 +3 748 733 134 +3 748 91 733 +3 626 800 788 +3 799 333 2 +3 799 335 333 +3 246 841 596 +3 141 841 246 +3 381 380 409 +3 411 381 409 +3 715 627 862 +3 751 715 862 +3 862 627 843 +3 751 862 843 +3 625 787 695 +3 626 787 625 +3 345 737 821 +3 695 822 150 +3 0 150 822 +3 775 852 575 +3 775 776 852 +3 421 342 811 +3 806 811 263 +3 421 811 806 +3 250 818 406 +3 250 251 818 +3 266 608 551 +3 267 608 266 +3 410 757 808 +3 543 410 808 +3 307 308 837 +3 307 837 321 +3 863 798 821 +3 737 863 821 +3 737 798 863 +3 737 704 798 +3 821 798 710 +3 800 0 822 +3 864 507 243 +3 676 507 864 +3 239 864 243 +3 676 864 239 +3 169 813 831 +3 631 169 831 +3 865 59 652 +3 403 865 652 +3 58 59 865 +3 403 58 865 +3 362 93 408 +3 444 408 356 +3 444 362 408 +3 444 354 362 +3 45 810 445 +3 810 732 731 +3 445 810 731 +3 445 731 447 +3 536 765 854 +3 856 615 854 +3 765 766 856 +3 194 795 193 +3 194 212 795 +3 464 762 686 +3 210 762 464 +3 34 457 87 +3 458 457 34 +3 639 253 725 +3 599 639 725 +3 574 767 851 +3 574 851 671 +3 76 670 502 +3 76 224 670 +3 180 7 829 +3 180 829 572 +3 18 581 20 +3 570 581 18 +3 16 840 702 +3 17 840 16 +3 598 127 761 +3 597 598 761 +3 80 728 209 +3 80 110 728 +3 331 489 845 +3 729 331 845 +3 451 375 824 +3 467 451 824 +3 770 288 286 +3 289 770 286 +3 25 78 79 +3 81 78 25 +3 528 14 323 +3 324 528 323 +3 225 844 221 +3 225 156 844 +3 500 628 816 +3 499 500 816 +3 652 842 475 +3 652 653 842 +3 593 229 227 +3 230 593 227 +3 268 556 299 +3 268 494 556 +3 763 316 317 +3 5 316 763 +3 637 32 33 +3 35 32 637 +3 733 6 614 +3 733 614 178 +3 443 366 828 +3 730 443 828 +3 223 819 247 +3 223 367 819 +3 386 237 238 +3 240 237 386 +3 371 168 785 +3 476 371 785 +3 334 378 192 +3 334 379 378 +3 478 697 125 +3 698 697 478 +3 433 778 437 +3 434 778 433 +3 50 830 718 +3 50 51 830 +3 306 749 23 +3 341 749 306 +3 12 13 823 +3 40 12 823 + diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cmd b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cmd new file mode 100644 index 00000000000..a65c2d34d7b --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cmd @@ -0,0 +1 @@ +cube-meshed.off diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp new file mode 100644 index 00000000000..1a7704bade6 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp @@ -0,0 +1,157 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Polyhedron_3 Surface; +typedef boost::graph_traits::edge_descriptor edge_descriptor; + +namespace SMS = CGAL::Surface_mesh_simplification ; + + +typedef Surface::Facet_iterator Facet_iterator; +typedef Surface::Halfedge_handle Halfedge_handle; +typedef Surface::Halfedge_iterator Halfedge_iterator; + + +// +// BGL property map which indicates whether an edge is marked as non-removable +// +struct Constrained_edge_map : public boost::put_get_helper +{ + typedef boost::readable_property_map_tag category; + typedef bool value_type; + typedef bool reference; + typedef edge_descriptor key_type; + + Constrained_edge_map(const CGAL::Unique_hash_map& aConstraints) + : mConstraints(aConstraints) {} + + reference operator[](key_type const& e) const { return is_constrained(e); } + + bool is_constrained( key_type const& e ) const { + return mConstraints.is_defined(e) ? mConstraints[e] : false ; } + +private: + const CGAL::Unique_hash_map& mConstraints; +}; + +int main( int argc, char** argv ) +{ + CGAL::Unique_hash_map constraint_hmap(false); + + Surface surface; + + if (argc!=2){ + std::cerr<< "Usage: " << argv[0] << " input.off\n"; + return 1; + } + + std::ifstream is(argv[1]); + if(!is){ + std::cerr<< "Filename provided is invalid\n"; + return 1; + } + + is >> surface ; + + Constrained_edge_map constraints_map(constraint_hmap); + SMS::Constrained_placement, + Constrained_edge_map > placement(constraints_map); + + // map used to check that constrained_edges and the points of its vertices + // are preserved at the end of the simplification + // Warning: the computation of the diedral angle is only an approximation and can + // be far from the real value and could influence the detection of sharp + // edges after the simplification + std::map >constrained_edges; + std::size_t nb_sharp_edges=0; + + // detect sharp edges + std::ofstream cst_output("constrained_edges.cgal"); + for(Surface::Edge_iterator eb = surface.edges_begin(), ee = surface.edges_end() ; eb != ee ; ++eb ) + { + if ( eb->is_border_edge() ){ + ++nb_sharp_edges; + constraint_hmap[eb]=true; + constraint_hmap[eb->opposite()]=true; + constrained_edges[eb]=std::make_pair( eb->opposite()->vertex()->point(), + eb->vertex()->point() ); + } + else{ + double angle = CGAL::Mesh_3::dihedral_angle( + eb->opposite()->vertex()->point(), + eb->vertex()->point(), + eb->next()->vertex()->point(), + eb->opposite()->next()->vertex()->point() ); + if ( std::abs(angle)<100 ){ + ++nb_sharp_edges; + constraint_hmap[eb]=true; + constraint_hmap[eb->opposite()]=true; + constrained_edges[eb]=std::make_pair( eb->opposite()->vertex()->point(), + eb->vertex()->point() ); + cst_output << "2 " << eb->opposite()->vertex()->point() << " " + << " " << eb->vertex()->point() << "\n"; + } + } + } + cst_output.close(); + + // Contract the surface as much as possible + SMS::Count_stop_predicate stop(0); + + int r + = SMS::edge_collapse(surface + ,stop + ,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface)) + .edge_index_map (boost::get(CGAL::edge_external_index ,surface)) + .edge_is_constrained_map(constraints_map) + .get_placement(placement) + ); + + std::cout << "\nFinished...\n" << r << " edges removed.\n" + << (surface.size_of_halfedges()/2) << " final edges.\n" ; + std::ofstream os(argc > 2 ? argv[2] : "out.off") ; os << surface ; + + std::cout << "Checking sharped edges were preserved...\n"; + // check sharp edges were preserved + for(Surface::Edge_iterator eb = surface.edges_begin(), ee = surface.edges_end() ; eb != ee ; ++eb ) + { + if ( eb->is_border_edge() ){ + --nb_sharp_edges; + assert( + constrained_edges[eb]==std::make_pair( eb->opposite()->vertex()->point(), + eb->vertex()->point() ) ); + } + else{ + double angle = CGAL::Mesh_3::dihedral_angle( + eb->opposite()->vertex()->point(), + eb->vertex()->point(), + eb->next()->vertex()->point(), + eb->opposite()->next()->vertex()->point() ); + if ( std::abs(angle)<100 ){ + ++nb_sharp_edges; + assert( + constrained_edges[eb]==std::make_pair( eb->opposite()->vertex()->point(), + eb->vertex()->point() ) ); + } + } + } + std::cout << "OK\n"; + + return 0; +} diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cmd b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cmd new file mode 100644 index 00000000000..74c878f26a1 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cmd @@ -0,0 +1 @@ +mesh_with_border.off diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp new file mode 100644 index 00000000000..e37e07d8a15 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp @@ -0,0 +1,118 @@ +#include +#include +#include + +#include +#include +#include + +// Adaptor for Polyhedron_3 +#include + +// Simplification function +#include + +// Midpoint placement policy +#include + +//Placement wrapper +#include + +// Stop-condition policy +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Polyhedron_3 Surface; + +namespace SMS = CGAL::Surface_mesh_simplification ; + +// +// BGL property map which indicates whether an edge is marked as non-removable +// +struct Border_is_constrained_edge_map{ + typedef boost::graph_traits::edge_descriptor key_type; + typedef bool value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + friend bool get(Border_is_constrained_edge_map, key_type edge) { + return edge->is_border_edge(); + } +}; + +// +// Placement class +// +typedef SMS::Constrained_placement, + Border_is_constrained_edge_map > Placement; + +int main( int argc, char** argv ) +{ + Surface surface; + + if (argc!=2){ + std::cerr<< "Usage: " << argv[0] << " input.off\n"; + return 1; + } + + std::ifstream is(argv[1]); + if(!is){ + std::cerr<< "Filename provided is invalid\n"; + return 1; + } + + is >> surface ; + + // map used to check that constrained_edges and the points of its vertices + // are preserved at the end of the simplification + std::map >constrained_edges; + std::size_t nb_border_edges=0; + + for (Surface::Halfedge_iterator hit=surface.halfedges_begin(), + hit_end=surface.halfedges_end(); hit!=hit_end; + ++hit ) + { + if ( hit->is_border() ){ + constrained_edges[hit]=std::make_pair( hit->opposite()->vertex()->point(), + hit->vertex()->point() ); + ++nb_border_edges; + } + } + + // Contract the surface as much as possible + SMS::Count_stop_predicate stop(0); + + // This the actual call to the simplification algorithm. + // The surface and stop conditions are mandatory arguments. + // The index maps are needed because the vertices and edges + // of this surface lack an "id()" field. + int r = SMS::edge_collapse + (surface + ,stop + ,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface)) + .edge_index_map (boost::get(CGAL::edge_external_index ,surface)) + .edge_is_constrained_map(Border_is_constrained_edge_map()) + .get_placement(Placement()) + ); + + std::cout << "\nFinished...\n" << r << " edges removed.\n" + << (surface.size_of_halfedges()/2) << " final edges.\n" ; + + std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ; + + // now check! + for (Surface::Halfedge_iterator hit=surface.halfedges_begin(), + hit_end=surface.halfedges_end(); hit!=hit_end; + ++hit ) + { + if (hit->is_border()){ + --nb_border_edges; + assert( constrained_edges[hit] == + std::make_pair( hit->opposite()->vertex()->point(), + hit->vertex()->point() ) ); + } + } + assert( nb_border_edges==0 ); + + return 0 ; +} diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cmd b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cmd deleted file mode 100644 index 5cea844d830..00000000000 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cmd +++ /dev/null @@ -1 +0,0 @@ -cube.off diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cpp deleted file mode 100644 index 2044d1d220e..00000000000 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_polyhedron.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include - -#include -#include -#include - -// Adaptor for Polyhedron_3 -#include - -// Simplification function -#include - -// Stop-condition policy -#include - -// Map used to mark edges as fixed -#include - -typedef CGAL::Simple_cartesian Kernel; -typedef CGAL::Polyhedron_3 Surface; - -namespace SMS = CGAL::Surface_mesh_simplification ; - -// -// BGL property map which indicates whether an edge is border OR is marked as non-removable -// -class Constrains_map : public boost::put_get_helper -{ -public: - - typedef boost::readable_property_map_tag category; - typedef bool value_type; - typedef bool reference; - typedef boost::graph_traits::edge_descriptor key_type; - - Constrains_map() : mConstrains(false) {} - - reference operator[](key_type const& e) const { return e->is_border() || is_constrained(e) ; } - - void set_is_constrained ( key_type const& e, bool is ) { mConstrains[e]=is; } - - bool is_constrained( key_type const& e ) const { return mConstrains.is_defined(e) ? mConstrains[e] : false ; } - -private: - - CGAL::Unique_hash_map mConstrains ; - -}; - -int main( int argc, char** argv ) -{ - Surface surface; - - std::ifstream is(argv[1]) ; is >> surface ; - - // This is a stop predicate (defines when the algorithm terminates). - // In this example, the simplification stops when the number of undirected edges - // left in the surface drops below the specified number (1000) - SMS::Count_stop_predicate stop(10); - - Constrains_map constrains_map ; - - - // This example marks ALL edges as non-removable, but a real world application would mark only selected ones. - for( Surface::Halfedge_iterator eb = surface.halfedges_begin(), ee = surface.halfedges_end() ; eb != ee ; ++ eb ) - constrains_map.set_is_constrained(eb,true); - - // This the actual call to the simplification algorithm. - // The surface and stop conditions are mandatory arguments. - // The index maps are needed because the vertices and edges - // of this surface lack an "id()" field. - int r = SMS::edge_collapse - (surface - ,stop - ,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface)) - .edge_index_map (boost::get(CGAL::edge_external_index ,surface)) - .edge_is_border_map(constrains_map) - ); - - std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (surface.size_of_halfedges()/2) << " final edges.\n" ; - - std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ; - - return 0 ; -} diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/mesh_with_border.off b/Surface_mesh_simplification/examples/Surface_mesh_simplification/mesh_with_border.off new file mode 100644 index 00000000000..16cd6b1e2c7 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/mesh_with_border.off @@ -0,0 +1,1566 @@ +OFF +548 1014 0 + +92.0896999051 77.41989209583 -1.916832684148 +86.39100962126 72.78664496906 15.78278094865 +77.09376525879 89.87973022461 14.55043506622 +90.98168945312 96.21558380127 3.65913438797 +82.71570084509 81.86220870549 16.44397321995 +92.31691908737 86.77964878854 1.043011456447 +89.37290527712 74.91208629563 6.905433125042 +84.03774261475 93.04766845703 9.104772567749 +87.91614428888 83.98367629501 8.885449941462 +92.08308562722 91.51009411435 2.561394143404 +79.93436140773 85.95867809642 15.71871673187 +92.16810072909 82.08661851225 -0.4813870638146 +84.95054383138 77.42281772836 16.37560573549 +84.22521839805 85.24324921259 12.54660366583 +87.28833145411 78.56473572586 11.06770318225 +88.53858617073 89.67622996838 7.078736038751 +90.21472024103 80.41696412654 4.846493577097 +87.81428016343 73.7864628996 11.33105836088 +90.80739519912 76.15358418737 2.490105437257 +90.23304320467 85.72684363719 5.157361043466 +80.56578826904 91.463722229 11.8276386261 +87.50969696045 94.63160705566 6.381914138794 +85.28558449034 88.85493917666 10.09354883143 +85.27758279004 81.37161616953 13.2681149885 +82.42035268114 88.37159009099 12.28321454594 +88.64910272783 80.44739317924 8.19157083558 +91.34705696923 83.71941907076 2.518356602206 +86.54332632431 76.21153148326 13.50411389672 +91.67848926288 93.87171420986 3.215234177501 +92.10816413641 79.75050243058 -1.206542332568 +92.29622765622 89.13884414744 1.826720300829 +89.70542995812 92.32964625679 5.425094029631 +90.59106423297 89.29868580891 4.596301969103 +91.17972407486 79.36567116545 1.91073903372 +86.33903036171 91.18877364247 8.487076777961 +87.52474663172 87.12023386306 8.676494963161 +78.49607673255 87.91733917969 15.15035040429 +86.99901132535 81.62634788796 10.68441922028 +88.58945681826 74.33088989454 9.115347731003 +88.62578378798 77.40042441075 8.552444264328 +89.49626856147 82.8803041145 6.515565583687 +90.11337785606 75.52304884182 4.696506235514 +82.30175018311 92.25574493408 10.46619224548 +86.19309520102 85.47015639124 10.53423349659 +83.62519737065 83.26930177161 14.30213272629 +82.0111827497 86.17046138772 13.90531750866 +85.62502595062 78.76016915029 14.06135119224 +78.82978057861 90.67166137695 13.1890039444 +89.45795733185 78.72045615552 6.562115009714 +85.6876237692 83.36697320818 11.86120221103 +90.44759176655 78.12728045561 3.939338198359 +80.48132290292 88.08344582991 13.73552924292 +81.36934673359 83.95779586913 16.1769257545 +85.75871853097 75.11699965987 16.11420674811 +83.88932229025 79.65919077394 16.47804590138 +92.26242604584 84.4270568131 0.271220829177 +87.82876868723 76.19362041729 10.58641505821 +87.06673968633 73.27518730634 13.55175677477 +91.45894636523 76.78940059593 0.2867129567336 +89.1360658561 87.2730913458 6.776971477474 +91.27271853367 87.17795258214 3.336373635784 +87.86365825812 92.32249801315 6.989370325119 +89.24565124512 95.42362213135 5.020479202271 +85.77369689941 93.83967590332 7.74334526062 +84.1530047653 90.8891150393 10.01020383373 +84.7473737152 87.01795663413 11.27019134425 +90.49631836036 82.69742911034 4.431726418335 +89.14774062234 85.0408944843 6.999973531134 +91.46289377915 81.61758663607 1.630732294048 +82.3132325122 90.30474632652 11.36096779886 +86.90111626841 89.15160207096 8.72203909917 +84.11950356501 81.16699817827 15.0140687604 +86.28939352036 79.79002703214 12.40403490101 +80.46573968642 89.74182843265 12.71429924485 +89.60865143194 76.76812793407 6.178829509292 +90.89270834008 91.26374173479 4.176033399443 +86.80521922435 83.70802005279 10.38215960895 +89.48178847126 80.95757614811 6.534276165285 +88.11169455465 79.04731345898 9.395346300457 +88.583493635 82.36236771915 8.124783175307 +90.84324437988 81.26551998519 3.330565985771 +83.87247641686 88.5955192875 11.20891472132 +83.19459245527 86.7501647852 12.6283671037 +90.40385047626 87.51383281538 4.886414759175 +86.16951796704 87.23207527998 9.953337633655 +91.60399930071 85.59586026518 2.336331753486 +90.75668901041 84.4323814451 4.044852809319 +87.29901191592 75.34268635555 12.09818461047 +86.57400034054 77.89258327773 12.67355564934 +85.79080099281 76.54570082726 15.07525566634 +91.77179896274 80.57408744558 0.281974535061 +91.5475556147 89.95641279222 3.1931760263 +90.3442663496 93.92285130091 4.585233593477 +86.45794665313 74.70284569722 14.49144487954 +79.05721494196 89.10127736985 13.9682290256 +92.09571263016 78.58472307811 -1.56269428567 +91.61324652266 78.65370278208 0.2413144683142 +88.95158085097 93.87160551314 5.76487891664 +88.93172774873 91.16524184997 6.380833459336 +83.1217686748 84.84727135728 13.80594048831 +89.60708732727 88.78765137181 5.981576801907 +90.92546945959 77.800373802 2.393472143492 +89.88360646754 84.27551327628 5.789320637377 +87.82352645612 80.66325786631 9.616310711501 +80.65753881345 84.96774500172 15.96810193465 +81.91399561614 84.87065850033 14.91313114612 +90.704329777 79.64984094159 3.428700832615 +84.55592036845 83.70275449477 13.0115763795 +92.21273042203 83.25630400946 -0.1087730360537 +88.21238360604 88.22000875015 7.707421885366 +88.15959122892 85.57676575574 8.297069621225 +88.81394466763 78.89692552288 7.991139144449 +87.59941965207 82.59759096357 9.584046736566 +86.06838273588 81.83162256321 11.96328549717 +87.03192126414 80.10893594721 11.0553375274 +88.46537703634 75.92217371895 9.137222873303 +87.94183853539 77.63062238945 10.0069676505 +84.73188438726 79.65427763894 15.09106477496 +89.99572259739 90.6013158789 5.326148605559 +89.08109552443 76.28510581649 7.571875818205 +87.45358755135 90.32287833068 7.925755467503 +85.80653793821 90.02205488241 9.287945386385 +84.90573883057 93.44362640381 8.424060821533 +85.02462957381 91.82100314902 9.080210762303 +82.53828964184 83.53532004812 15.31098692782 +87.24565314739 85.21590788642 9.462906429098 +88.76907792079 83.77269954437 7.686026722444 +87.26020862849 77.16918094688 11.56186126234 +79.21183662051 86.93976318432 15.44173627227 +80.6772357635 86.72750384054 14.55134866499 +89.96968019319 81.91329385452 5.544516060987 +91.04107866369 92.74354582432 3.959510149799 +89.93672918584 77.98593262991 5.347731087816 +91.02614651348 85.78683581428 3.633030004003 +85.13548572186 85.65452792654 11.50140805416 +86.58175312226 92.53969079587 7.807716427241 +91.73194481166 83.03368102701 1.268949655066 +91.6054686603 88.52647150388 2.928124991176 +82.0440222159 87.34001414513 13.1416907498 +85.52842652024 80.03896830107 13.54193677916 +85.36404016149 77.88755226405 15.12055517891 +86.0765084065 77.46013649534 13.89021585768 +90.46661968935 75.83685629421 3.592188671691 +90.19681065692 76.89784761499 4.538397099543 +84.56138644799 82.48691782071 13.65137294073 +83.30403327714 82.36071585563 15.29489338667 +86.64169311523 94.23564147949 7.062632083893 +89.15075042396 77.62070306986 7.311016382239 +91.77578816761 77.10568331543 -0.8146003184522 +92.31458355115 87.95769882393 1.431302885641 +84.27631718922 89.64398620348 10.47724464253 +91.16950185257 82.39458802729 2.677383847529 +86.87516040998 74.96862991509 13.27991264815 +89.18314931403 79.84626795266 7.164286304372 +84.44360901566 78.54784372864 16.4455387666 +85.99928322555 84.35958928423 11.12543897065 +90.96268806848 88.23215442693 3.99433103563 +91.79917398165 86.86770228776 2.211270347125 +91.35660160611 95.04584327368 3.454739655752 +90.11364746094 95.81958770752 4.33976650238 +91.8114226106 84.52104497723 1.537204226449 +89.92268062963 79.29372508096 5.47162553997 +87.80022427991 74.99940383723 10.98461017787 +88.98391421327 74.61712962187 8.011383213137 +88.41189669657 86.76113359695 7.762849859456 +89.83990585597 86.78305575769 5.804147791076 +86.47708307705 82.70982487065 11.10320850079 +85.05990301504 84.41623279402 12.11437941264 +89.32975770952 89.98303370895 6.172890167703 +87.43364445809 73.52682079937 12.44056066412 +81.26149028386 88.68493750348 12.8445643021 +79.59530025292 87.7552167202 14.55929982062 +81.56095704279 89.65865012342 12.12054795257 +83.74650335188 87.5173532649 11.81482990264 +82.05580562551 82.9262281906 16.33684179161 +77.79110462112 88.89988096489 14.85615961682 +85.38491825728 76.27397332034 16.26002634304 +83.30952273933 80.76277415836 16.47482934558 +86.09057899059 73.95418022421 15.9528063478 +92.22202721814 90.32419016346 2.207048185808 +92.13015228425 80.91751070159 -0.8477875752077 +91.91128748784 92.69412778407 2.905822503365 +92.30352960777 85.60185389102 0.6571861560139 +88.80397882864 92.35845957816 6.230165128969 +87.56350554293 93.48546833814 6.794415435958 +86.77515477948 87.99073532884 9.163124693164 +91.2921995218 77.76012886914 1.141073203928 +87.24563285669 91.51266122799 7.717013849969 +91.05693732674 80.38765116816 2.536987922097 +88.09868991582 81.66739940773 8.994784785804 +88.20079182886 74.0545900789 10.22315122432 +91.13838295799 76.47160421784 1.38837785964 +89.74903229875 75.21462640485 5.800678292534 +86.7248444178 73.03032641041 14.66755655857 +91.42198188351 80.44639618037 1.409354415978 +86.70248244291 86.20631702261 9.772311187611 +85.32357668702 82.51604988631 12.67539856556 +83.34415171148 90.3563044528 10.73296744307 +83.16972351074 92.65168762207 9.785503387451 +83.16370643034 91.45261184562 10.33452960078 +88.3776473999 95.02765655518 5.701191902161 +79.6978225708 91.06776428223 12.50832748413 +81.43376159668 91.85966491699 11.14694881439 +77.96181488037 90.27571105957 13.8696937561 +82.88320612077 89.23701510152 11.54197182646 +90.59709590487 77.0431090884 3.326233951924 +90.4385053569 81.50740377165 4.417289906702 +90.92399955002 83.20459553336 3.474223453509 +90.04153909139 83.12197296545 5.464420913909 +84.84455473976 80.53727723718 14.34532209905 +88.97115981828 81.39918470952 7.526398209826 +88.19184958435 90.76480154662 7.16373228865 +88.95207671701 88.40527714282 6.846825372554 +86.85188444752 76.78765884766 12.56411815235 +91.82868788219 82.06718063471 0.6263483943344 +87.83397570175 89.26724425275 7.860215245696 +85.63889122331 86.49196601989 10.70444370687 +84.289256929 86.25422337269 12.00150866214 +85.28132021495 87.75990875058 10.52113336767 +87.61493912667 79.70302658741 10.17261837774 +89.34878250085 83.96799192039 6.745304265489 +89.71060304788 85.34737396029 6.077644732881 +89.04670719873 86.17050776147 7.033811940758 +83.33616210627 85.71360239737 13.08930299415 +80.90981870091 85.73270169067 15.12615535105 +91.21497714171 84.80822967201 3.070330870078 +90.64792720154 86.4992805173 4.432689133307 +90.32498894608 79.39071047162 4.441071424401 +86.59113065075 81.0079681309 11.48087340359 +88.20529733344 75.14799817208 9.928778947458 +91.46932714668 91.82413160531 3.426693900819 +84.05625152588 92.04026031494 9.551273345947 +81.34168250145 90.67680250169 11.74296930792 +91.55259019351 79.61359965956 0.734537667934 +86.14928903969 88.82644504097 9.435758125875 +86.63480151744 90.17649516787 8.626415734013 +85.61112519056 92.54511608244 8.415443520635 +90.77235413367 78.64450546717 3.044471825873 +86.03015612476 80.84246483408 12.39859916442 +84.09084387379 80.31011079893 15.65381057678 +87.42963074907 86.1429197771 9.024362828801 +84.58304230312 81.54684584424 14.13916022685 +82.71823885608 84.27191904384 14.58204533128 +86.14318337822 78.875724971 13.05390603302 +87.26466369629 79.24705505371 11.27718162537 +87.46308063449 88.31600007416 8.437690516399 +81.19461313203 87.2774180299 13.78930881295 +90.33868384664 83.96273511603 4.894040729647 +86.24349253624 75.76941990672 14.45146228254 +89.62070466303 79.96751622986 6.215618617518 +89.86045031553 87.81767110116 5.714444063781 +90.32493653663 92.86181087998 4.742895505028 +91.83660492574 79.70232495475 -0.2327343256045 +87.5598870147 81.60536240291 9.845685702366 +90.24277677565 91.55416058234 4.951816512248 +90.62251838342 90.33539527205 4.550076062657 +88.3684628344 84.57954172437 8.178119845641 +84.91706095676 90.18792368357 9.834589545214 +83.9286208171 84.51052198464 13.22924134799 +89.42617545693 75.90524494088 6.691736706803 +89.91402634483 76.30110923329 5.324186755154 +89.57647684262 77.76935141695 6.265239627438 +90.26302274 88.48759436779 5.08800413955 +85.56081184425 90.97427099583 9.095988527362 +80.00626334278 89.03147537546 13.41898396371 +79.37286329558 89.82291469539 13.32549985972 +88.14755221554 76.67312076792 9.744962597196 +89.65531497262 93.32206911079 5.323482453556 +91.22225608436 89.12207284975 3.629908520633 +83.96795217196 82.30680594897 14.49836357631 +83.45877795223 81.4494251123 15.73631635087 +89.94620514167 89.59487371469 5.467634763391 +82.29238891602 91.29810333252 10.90618038177 +90.811639497 82.22302301049 3.582510020635 +80.52007293701 90.59206390381 12.24966716766 +88.29109077723 78.09038216257 9.190419558197 +87.71177444011 78.74996062053 10.22093064536 +88.46730306671 79.57337952733 8.628829838468 +88.33761245464 83.26134698128 8.394543381393 +89.36645737065 81.92077744538 6.769106527411 +89.89907582446 80.92451760593 5.635455680689 +89.00589702596 82.86301063417 7.377557640286 +90.59027668966 94.87526374646 4.171108393016 +87.42512737492 76.17020838692 11.52442944207 +91.02426936631 93.72302643884 3.916591269877 +89.8870358383 94.74290090133 4.809697443233 +87.05838461737 82.52158227934 10.3681851657 +86.56171579354 84.61481200814 10.40923667174 +87.28978037789 84.22135089334 9.650016622116 +91.99796250152 85.97382150086 1.519676157958 +91.41983478308 86.34049730935 2.903012247065 +86.98268430651 78.05139466641 11.81754825277 +91.81560657137 78.14260723897 -0.6524242830686 +86.8722058784 87.03288787543 9.354827421718 +91.35672928113 78.7639907204 1.17125485171 +91.53968604339 77.7202798909 0.2403441317094 +84.86545927303 78.71558791114 15.51626244516 +86.79722653072 93.3408647828 7.342636373913 +91.63020782938 90.91409015372 3.14840834059 +87.25531824172 74.47592155632 12.52927221104 +86.07425696252 75.21362038574 15.21297464765 +91.16106283305 81.48663482954 2.492502407732 +90.5757893716 80.50375765165 3.922765152667 +82.67168107606 86.33491475752 13.27365472624 +82.96487921529 87.60913204281 12.329282444 +87.82636242729 84.88753643638 8.842631330747 +84.35474740005 87.83056859068 11.21352843057 +84.55876620841 88.79983575754 10.6423089934 +83.17465723672 88.40634089228 11.76835493646 +90.85284906504 87.33686142924 4.121887080868 +86.72724152045 73.8489141689 14.2127483518 +86.42355444031 73.80296018704 15.09471583991 +86.93659826144 75.89680908807 12.73505114447 +83.54500604627 89.52185961323 10.99503048512 +88.83978565047 75.58107846602 8.260375606895 +88.72239336258 76.48510243038 8.436356181968 +91.66303103922 87.64914656063 2.668165150909 +86.12595505386 76.63627073986 14.24302571059 +90.63286939882 85.3266640223 4.382207547975 +85.1824586822 79.69308786923 14.30335998377 +90.22312494777 84.82135828186 5.152478488357 +91.95415466013 83.85535866474 0.9179829688677 +88.23374725874 92.97600033614 6.514255895342 +88.15189788739 93.96486724046 6.24411450713 +85.3800757181 76.98502795314 15.73048748873 +84.80319976807 92.65283203125 8.842200279236 +89.09641550807 89.22223592452 6.551811823289 +85.8175845876 88.16254355025 9.930269660873 +87.66547683905 77.09918437201 10.72152242862 +78.94045741667 88.39228989734 14.52370677822 +79.71511631602 88.43273633661 14.0000620674 +89.61954054135 91.41099822565 5.649216608215 +89.23067474365 94.6247253418 5.391794204712 +91.14098067071 90.46179999326 3.826403976189 +91.93963698747 89.54916561137 2.519897373028 +90.67907607165 92.08784992503 4.414110286577 +92.00748229705 88.36647480616 2.15883145893 +87.31342900202 80.76548024745 10.42083525356 +88.54108873981 81.32345228217 8.303818225533 +86.29197840378 83.55138824339 11.06344748072 +91.63576602179 81.14048734557 0.926761868349 +91.96373053199 81.33067011421 -0.1021323030729 +88.10058326017 82.54123945134 8.854680095962 +87.02030891857 74.10770397135 13.29008336436 +88.66114033185 85.22844041822 7.687983749868 +83.37451380026 84.06156417283 14.06219752259 +82.3656683929 85.31267926977 14.18556991487 +81.62659745583 85.67233020136 14.57361705313 +79.91235379794 86.99394195408 14.90861860817 +91.92134843838 79.00929111616 -0.7694692860489 +87.93559569912 86.4273596092 8.393204653578 +90.64911812118 83.58820518874 4.189330441393 +90.19847423323 78.53839085091 4.690054556929 +82.70591734945 82.54285737196 15.89561516193 +87.55644665574 74.60603473099 11.72233372584 +86.59650472634 78.69950252896 12.30020046608 +85.76543352653 77.28645400239 14.66293197255 +88.30923622 91.57787766767 6.847835587868 +88.78585426569 90.38592908654 6.684616642745 +81.39871557718 87.91580271512 13.23167464013 +77.44239816095 89.3917582412 14.70647816142 +78.2346321736 89.45395679512 14.22778685506 +89.93552467668 77.14410101136 5.302068334108 +84.85307911288 90.96940089197 9.550021626143 +91.07435434956 77.22910817763 1.777355579159 +91.53472676551 84.75175611001 2.296705553252 +91.07428743866 84.0006697594 3.253891270141 +87.57206861003 83.44109160119 9.452703099751 +86.46837704385 77.01830345632 13.28299203037 +88.24534904025 80.33910657831 8.94283369881 +86.03946980836 78.22531162763 13.56218249175 +85.12085057396 83.64329737652 12.4032963563 +83.99859345837 83.65910767374 13.64917308958 +91.1068447306 78.5125448281 1.950304716625 +88.93743904592 77.0416921546 7.862316649276 +81.89763387706 84.16300891638 15.47949979105 +84.17142822011 79.10427843247 16.46661667861 +90.1977196189 77.71826121309 4.613359081808 +91.46686301969 82.4573958955 1.86560046256 +85.17639263798 78.97291532426 14.76262265383 +81.25829074791 85.01580337653 15.40024671834 +85.57806257522 75.69618258949 16.18963166867 +90.6740474846 77.84868862773 3.208271283977 +88.39299437575 88.93655007712 7.376023566561 +88.02443178926 87.46291572177 8.066227217816 +88.69549876852 87.75415760413 7.255780630642 +90.83584527911 76.98060581503 2.533464600951 +90.24894299365 86.54477235102 5.141658921075 +89.6976072794 83.56866623825 6.139232569616 +90.95815006486 79.5860525514 2.65996163632 +90.54331172733 78.9237771769 3.77410403802 +85.45053954275 84.87164856816 11.51553144517 +89.01834595117 80.58443177613 7.473181777199 +88.84104627055 78.03470716764 8.002824388128 +85.67184761911 78.03529306301 14.39524142803 +86.53578569197 81.78319067054 11.31637757513 +85.60993633696 81.75701177328 12.63336621461 +85.80387144362 82.58918845105 12.02841449852 +88.50429153833 75.12400624369 9.178192908443 +84.48876628209 84.50364974112 12.66249526191 +89.41742707428 86.59282506324 6.459802357741 +89.14239643036 75.46130015491 7.488269950964 +88.8400388208 93.12543610622 6.022451468792 +84.35601236007 79.54349955601 15.80498719226 +85.72661361084 91.66288450582 8.710852466457 +81.35632656989 86.57100524067 14.14937345639 +80.30996143596 86.3295074551 15.12856879422 +80.51503942099 87.4160358727 14.17386056988 +88.82555358781 79.70698776571 7.908609004999 +88.47215841331 78.74225769992 8.723597569818 +89.15110921007 79.03160706289 7.254502463971 +89.52260410248 84.66512629317 6.423342033217 +86.62964224798 80.05172781141 11.73751161387 +87.28315315953 79.35507964116 10.84288117454 +78.39582061768 90.47370910645 13.52938842773 +89.42167039058 88.09489616508 6.301769902343 +88.59964322506 86.00871702093 7.658460101584 +82.20010929418 89.13086851198 12.01494409867 +89.92675339147 80.15382280797 5.522754060304 +87.41138994867 77.77647847548 11.06513801808 +89.32906590509 76.65549889054 6.913354804829 +89.41991350218 90.72714883996 5.963601242846 +83.84750712961 85.91736606737 12.54230305646 +84.70610177702 77.98854431145 16.41686504562 +86.55716047843 75.25385523287 13.94340207575 +79.82708740234 90.28623199463 12.78842067719 +86.00337982178 93.08626556396 7.952734470367 +86.60580976688 91.80148730574 8.072677376784 +87.22050151166 92.6603694961 7.33227675047 +88.16716263207 75.91256782034 9.852927479006 +86.72900679298 85.25690869653 10.0289813322 +88.26398948523 77.33772345921 9.36442753796 +84.48457755837 80.3785157358 15.0009805203 +86.90911612862 90.76068403985 8.224517995328 +87.99764207043 89.9437017199 7.547420421772 +87.17673875088 89.73814630364 8.325225356834 +91.27346915349 80.9035465747 2.006769025922 +87.96093644471 79.91600342135 9.518832922801 +89.77981626992 94.04055669295 5.089906242403 +82.77049394816 85.64393889715 13.61366577784 +86.36565938384 89.5909865994 9.02122595877 +85.37867446359 89.55990884413 9.762504200646 +82.93187929823 89.91362149273 11.18538301618 +90.40184120368 77.36763120377 3.978408478545 +83.05097214393 83.5778676545 14.72926797176 +89.72248932475 78.42898288903 5.918966931824 +91.67516532539 83.73576836354 1.656707294069 +78.71974914613 89.79709073339 13.73515288393 +90.92734145902 89.78390610645 4.112839472319 +89.00168562649 84.3598607859 7.279939209434 +81.71748951367 83.44541399728 16.26328327578 +85.63151466028 80.6783179693 13.07487257959 +85.2061604245 80.70675069058 13.70207637819 +89.67707012829 76.04729367448 5.994030004774 +91.80352195174 93.28461363862 3.066921973103 +92.09239955624 78.00218956873 -1.739866962382 +86.92069711747 77.41143533536 12.17691558281 +88.95079812341 82.13893390599 7.523756483162 +91.95468325146 82.85228212281 0.526891242366 +90.81599675904 80.36183194305 3.237449743645 +90.54766845703 96.017578125 3.999451637268 +92.0055241551 85.22912795386 1.269253743002 +89.88338535679 86.02225332199 5.764867970561 +81.84564932064 88.23991492601 12.73434009247 +85.93024321957 74.5364087842 16.03535734115 +84.82059474593 82.96593066196 13.08379381789 +89.68150719318 82.24151111624 6.159472595437 +90.19728828303 82.48156059828 5.093752428947 +89.71125544255 81.47605972064 6.071317743465 +83.72882271397 81.77689831853 15.14467408305 +86.25218261707 74.5079949549 15.1626753312 +85.00988855546 78.03025378603 15.74992136855 +90.18405860601 81.13314612602 4.994330226107 +85.65257806689 85.78328208136 10.96127222822 +84.83030951908 86.3240240171 11.50096113237 +84.61082060889 85.59183835254 12.02018475677 +86.18189079471 86.17576795044 10.30566166154 +86.74048774938 74.51238814105 13.8384304986 +90.4003943129 76.54491258221 3.884703534253 +81.81327505325 86.83154980488 13.62882318444 +91.31694022014 87.95524252007 3.365571118591 +91.11867506879 86.49884415014 3.536760369568 +91.31518166869 85.6281458942 2.994287968664 +90.94835188199 85.05695431771 3.705049918602 +88.43889418727 76.69555098254 9.075219277086 +89.43228854681 85.86706706099 6.500004845721 +82.73513628171 90.71773976847 10.92107545621 +91.98887439509 87.6326927391 2.007190497912 +91.52793371682 94.46079285745 3.343908937295 +86.09082407967 90.54507374952 8.898060742125 +80.63731155247 88.65047179233 13.26168529876 +91.35347577036 83.01191364709 2.327252349276 +85.6788758969 76.12079563979 15.63082402037 +89.21793908226 78.32106678605 7.123794200307 +81.89286506116 90.88075220467 11.33043282293 +80.96296280172 90.02565655652 12.27699603282 +87.18562304132 83.17319429571 10.03197094628 +85.94523835859 79.61159497471 13.06151633859 +89.54586658536 87.39575929373 6.202245926172 +84.19560615902 86.93932821561 11.75398955827 +82.64923765358 87.17546494488 12.80072555853 +85.57182703976 79.40049630906 13.80412587682 +92.11813422526 80.3336940627 -1.0274672359 +91.58969915559 89.26351826489 3.053117287076 +82.90513702073 82.93644120087 15.35797196151 +83.51087357062 82.76432473619 14.76703486348 +90.13510669594 76.2169664233 4.66747957696 +90.64913923384 93.33554679517 4.353233685676 +84.13267337331 83.00396580987 13.88201394276 +84.87243712271 81.85866336116 13.57925886949 +89.28944999749 91.98966703195 5.879106347835 +87.81999722862 91.35373114943 7.320547757033 +91.93708444299 80.37746807551 -0.360749318184 +85.84211427154 85.13059367186 11.01535006381 +85.56820387932 84.18880644955 11.66829122503 +91.48388065108 92.79963299821 3.436939740116 +83.75276774305 86.54362591673 12.30003839505 +90.33403260788 89.84300780106 4.947890651582 +91.17155781479 95.62999233702 3.555330232582 +81.08768683738 86.17984327111 14.63971208729 +90.38594006628 83.29347411891 4.750388981447 +87.98665421745 78.28535011375 9.784775030141 +82.3679546364 89.67867529519 11.635015703 +83.74534240316 85.1538186026 13.04163202392 +91.63708732988 82.17328836847 1.27095837172 +85.97074285508 75.8696789085 15.06787457704 +88.78623129313 74.47325883927 8.562521367548 +84.53518886933 91.56446841495 9.484550907027 +84.32967128058 90.25555108377 10.18170123086 +84.85811913064 89.38922071855 10.19417118041 +92.05118344848 84.5308652651 0.9058592816885 +88.24781393992 81.01711913492 8.844436451774 +85.27588195651 87.09941342014 10.79102642662 +88.3946809784 83.91013776736 8.227404481239 +87.55246737728 75.47893998843 11.44680253484 +87.72693552863 85.56194386854 8.827585540933 +82.36266194973 87.7872771424 12.65064169419 +90.99625808495 81.84789400481 3.029675030284 +87.12534937579 76.26893668453 12.16272998574 +90.51427577132 90.99750450867 4.669163752209 +88.75231293904 87.09091301546 7.292276779629 +81.77196144489 88.83586075055 12.43768637401 +80.99975585938 91.66167449951 11.48725414276 +80.78927139352 89.16541907359 12.85188992007 +87.66350506837 78.08952304598 10.47636582897 +91.93329295926 77.26298047189 -1.365480028674 +83.43715667725 91.99025726318 9.931365013123 +83.88444128096 91.49158214368 9.898426233423 +3 110 256 305 +3 43 473 476 +3 316 137 336 +3 240 195 293 +3 238 228 412 +3 218 84 532 +3 15 383 434 +3 119 374 420 +3 227 16 302 +3 283 127 328 +3 106 302 459 +3 207 66 351 +3 344 110 416 +3 31 254 331 +3 199 197 486 +3 144 196 509 +3 65 474 499 +3 348 171 407 +3 119 314 315 +3 278 8 533 +3 301 151 378 +3 88 291 456 +3 324 140 356 +3 66 207 273 +3 11 214 458 +3 251 31 267 +3 75 255 539 +3 181 9 230 +3 83 165 250 +3 15 326 383 +3 161 132 445 +3 297 184 428 +3 34 427 433 +3 226 133 318 +3 256 110 344 +3 265 47 425 +3 405 246 479 +3 189 79 338 +3 276 78 521 +3 266 116 431 +3 74 261 362 +3 116 275 431 +3 190 162 229 +3 40 279 281 +3 208 40 388 +3 260 74 362 +3 150 307 313 +3 166 49 339 +3 112 189 253 +3 346 45 439 +3 99 242 346 +3 117 209 319 +3 128 36 171 +3 14 276 544 +3 466 130 468 +3 107 371 465 +3 49 371 514 +3 161 227 352 +3 352 227 390 +3 264 73 543 +3 81 173 308 +3 246 51 359 +3 239 71 432 +3 46 243 370 +3 273 151 537 +3 365 85 461 +3 276 14 413 +3 283 87 538 +3 93 248 424 +3 169 299 354 +3 100 250 415 +3 59 415 498 +3 208 102 247 +3 19 226 318 +3 254 118 331 +3 282 92 285 +3 34 404 427 +3 121 257 263 +3 257 441 529 +3 204 24 417 +3 65 218 532 +3 80 188 459 +3 207 151 273 +3 102 208 388 +3 79 278 281 +3 108 11 458 +3 73 265 425 +3 304 24 308 +3 218 22 327 +3 64 257 528 +3 241 71 269 +3 241 144 509 +3 37 166 286 +3 228 114 412 +3 264 51 330 +3 143 260 362 +3 131 284 515 +3 288 287 430 +3 126 278 533 +3 48 161 445 +3 408 153 410 +3 103 219 337 +3 275 78 409 +3 114 228 337 +3 278 126 281 +3 302 80 459 +3 80 273 537 +3 307 81 313 +3 81 204 313 +3 82 173 516 +3 82 223 303 +3 226 83 309 +3 226 309 481 +3 234 185 327 +3 195 84 293 +3 289 182 461 +3 85 365 482 +3 133 482 483 +3 207 351 366 +3 87 312 538 +3 464 300 470 +3 312 213 538 +3 213 88 456 +3 381 176 492 +3 248 89 317 +3 96 233 252 +3 32 271 517 +3 268 91 503 +3 31 251 254 +3 284 131 507 +3 248 27 424 +3 90 340 341 +3 194 90 233 +3 292 148 295 +3 294 186 373 +3 322 323 402 +3 146 21 184 +3 100 168 271 +3 109 212 385 +3 242 99 345 +3 258 107 372 +3 331 118 421 +3 118 168 421 +3 364 191 386 +3 221 102 411 +3 247 102 320 +3 288 367 496 +3 278 79 342 +3 224 347 380 +3 242 345 444 +3 105 242 375 +3 188 33 389 +3 227 106 390 +3 99 258 345 +3 167 371 399 +3 182 55 530 +3 70 185 234 +3 433 120 435 +3 35 240 293 +3 125 195 240 +3 25 392 408 +3 111 408 410 +3 166 76 286 +3 256 8 305 +3 72 238 412 +3 396 196 397 +3 328 419 544 +3 114 219 413 +3 314 119 401 +3 116 328 544 +3 328 127 419 +3 12 423 471 +3 255 118 539 +3 271 118 517 +3 115 314 398 +3 115 398 429 +3 184 61 428 +3 98 211 357 +3 234 121 440 +3 22 234 327 +3 236 122 426 +3 198 7 231 +3 122 236 325 +3 135 236 426 +3 124 242 444 +3 177 4 270 +3 76 287 288 +3 125 288 430 +3 220 126 449 +3 126 256 449 +3 419 14 544 +3 56 283 328 +3 129 348 407 +3 128 171 348 +3 104 10 224 +3 347 224 519 +3 220 40 281 +3 247 351 520 +3 251 131 335 +3 161 16 227 +3 132 161 352 +3 133 226 481 +3 482 225 483 +3 76 166 339 +3 474 134 475 +3 235 34 433 +3 135 187 427 +3 321 136 446 +3 378 151 491 +3 309 60 481 +3 173 82 304 +3 45 346 347 +3 23 241 509 +3 139 209 452 +3 376 54 403 +3 243 88 370 +3 27 213 312 +3 205 382 386 +3 18 142 205 +3 143 443 478 +3 205 142 478 +3 319 139 501 +3 209 71 241 +3 52 375 450 +3 345 44 444 +3 146 184 297 +3 135 297 428 +3 147 393 493 +3 153 48 410 +3 316 336 487 +3 30 149 336 +3 150 528 529 +3 528 257 529 +3 26 446 491 +3 68 301 378 +3 299 169 343 +3 77 210 279 +3 161 48 249 +3 423 154 471 +3 167 391 514 +3 134 391 475 +3 156 268 480 +3 60 309 480 +3 157 316 487 +3 336 149 487 +3 62 159 285 +3 159 282 285 +3 160 321 446 +3 26 365 446 +3 16 280 472 +3 161 249 418 +3 17 162 190 +3 6 163 401 +3 163 314 401 +3 164 384 540 +3 212 59 385 +3 67 221 411 +3 385 59 540 +3 113 166 395 +3 196 49 397 +3 107 258 399 +3 371 107 399 +3 168 118 271 +3 168 100 326 +3 299 87 354 +3 17 169 354 +3 170 490 543 +3 138 246 359 +3 51 171 330 +3 94 264 330 +3 274 232 495 +3 69 172 232 +3 173 304 308 +3 218 65 306 +3 174 124 353 +3 4 174 353 +3 264 94 265 +3 171 36 329 +3 89 324 356 +3 324 89 492 +3 71 239 270 +3 117 296 403 +3 248 93 300 +3 310 193 311 +3 91 334 503 +3 230 9 298 +3 233 90 252 +3 11 180 341 +3 454 181 515 +3 160 365 461 +3 5 182 289 +3 98 331 421 +3 61 357 511 +3 183 61 322 +3 61 184 322 +3 350 35 384 +3 35 185 245 +3 96 186 294 +3 148 58 295 +3 187 61 511 +3 357 211 511 +3 301 68 436 +3 33 188 194 +3 279 210 457 +3 210 25 338 +3 38 229 398 +3 38 190 229 +3 186 191 364 +3 186 58 191 +3 261 74 420 +3 41 260 506 +3 53 300 464 +3 57 193 310 +3 33 294 373 +3 33 194 233 +3 287 43 430 +3 216 84 476 +3 371 167 514 +3 113 396 397 +3 42 199 272 +3 64 197 199 +3 64 199 547 +3 202 42 272 +3 199 546 547 +3 198 231 546 +3 97 332 438 +3 184 21 323 +3 73 274 495 +3 73 264 265 +3 202 494 542 +3 20 232 274 +3 360 2 361 +3 417 172 522 +3 204 417 522 +3 352 50 377 +3 364 101 373 +3 280 130 472 +3 351 66 520 +3 208 247 520 +3 351 86 366 +3 130 466 467 +3 279 40 466 +3 209 139 319 +3 117 239 432 +3 210 77 392 +3 25 210 392 +3 326 15 358 +3 215 120 434 +3 100 212 326 +3 212 100 415 +3 88 368 370 +3 88 213 368 +3 180 502 512 +3 458 214 524 +3 212 109 383 +3 185 70 245 +3 84 216 532 +3 474 217 499 +3 217 474 475 +3 13 422 475 +3 441 22 529 +3 22 218 307 +3 219 114 337 +3 219 103 437 +3 126 220 281 +3 67 411 449 +3 400 462 485 +3 19 221 462 +3 222 400 485 +3 462 221 485 +3 223 82 422 +3 99 223 523 +3 346 105 347 +3 104 224 380 +3 365 160 446 +3 26 225 365 +3 165 83 387 +3 83 226 387 +3 106 227 302 +3 50 352 390 +3 113 228 238 +3 166 37 395 +3 162 56 229 +3 314 115 315 +3 255 75 333 +3 75 230 298 +3 123 231 325 +3 257 64 363 +3 202 272 494 +3 292 96 349 +3 96 292 295 +3 257 121 441 +3 70 234 440 +3 235 433 435 +3 70 235 435 +3 123 236 404 +3 236 123 325 +3 237 101 382 +3 50 237 382 +3 238 72 451 +3 23 396 451 +3 54 177 239 +3 239 177 270 +3 240 35 350 +3 125 240 535 +3 465 144 508 +3 144 241 269 +3 242 124 375 +3 242 105 346 +3 139 497 501 +3 72 243 497 +3 291 88 355 +3 88 243 355 +3 70 215 245 +3 215 109 245 +3 129 246 405 +3 171 51 407 +3 19 318 320 +3 366 86 483 +3 213 27 368 +3 27 248 317 +3 48 153 249 +3 153 77 249 +3 250 100 262 +3 83 250 262 +3 332 285 438 +3 92 251 267 +3 29 252 502 +3 189 103 253 +3 228 37 337 +3 254 251 335 +3 75 254 335 +3 333 91 448 +3 156 32 268 +3 305 125 535 +3 110 305 535 +3 123 263 363 +3 263 257 363 +3 258 99 523 +3 13 258 523 +3 41 192 260 +3 192 6 259 +3 259 74 453 +3 74 260 453 +3 147 261 420 +3 410 48 493 +3 32 156 262 +3 156 83 262 +3 263 34 489 +3 121 263 489 +3 490 264 543 +3 51 264 490 +3 2 203 361 +3 266 115 429 +3 56 266 429 +3 97 267 402 +3 323 97 402 +3 255 333 448 +3 118 255 517 +3 145 269 469 +3 44 269 505 +3 145 353 504 +3 269 71 469 +3 32 262 271 +3 262 100 271 +3 272 199 486 +3 272 486 494 +3 80 206 273 +3 206 66 273 +3 47 201 425 +3 201 20 274 +3 111 393 409 +3 374 39 393 +3 219 276 413 +3 219 78 276 +3 369 277 437 +3 25 277 369 +3 288 8 367 +3 8 278 367 +3 77 279 468 +3 279 466 468 +3 249 280 418 +3 249 77 280 +3 281 279 457 +3 79 281 457 +3 92 282 284 +3 92 284 507 +3 283 56 534 +3 87 283 534 +3 28 284 488 +3 267 97 438 +3 62 285 332 +3 112 253 286 +3 253 37 286 +3 391 155 514 +3 473 43 513 +3 367 112 496 +3 76 288 496 +3 85 157 289 +3 157 5 289 +3 60 157 290 +3 157 85 290 +3 244 291 355 +3 244 14 291 +3 29 95 349 +3 95 292 349 +3 84 185 293 +3 185 35 293 +3 33 233 294 +3 233 96 294 +3 58 186 295 +3 186 96 295 +3 46 319 501 +3 319 46 379 +3 122 63 426 +3 63 146 297 +3 9 179 298 +3 179 91 298 +3 152 299 343 +3 152 87 299 +3 93 310 311 +3 188 301 436 +3 188 80 301 +3 16 206 302 +3 206 80 302 +3 246 138 479 +3 304 82 500 +3 500 138 536 +3 138 359 463 +3 8 288 305 +3 288 125 305 +3 173 499 516 +3 173 81 306 +3 218 306 307 +3 306 81 307 +3 24 204 308 +3 204 81 308 +3 83 156 309 +3 309 156 480 +3 57 310 343 +3 169 57 343 +3 193 1 311 +3 1 178 311 +3 87 152 312 +3 152 27 312 +3 197 313 442 +3 197 150 313 +3 315 39 374 +3 119 315 374 +3 39 315 484 +3 275 39 431 +3 157 60 316 +3 268 137 480 +3 317 89 356 +3 141 317 356 +3 86 247 320 +3 318 86 320 +3 296 117 379 +3 117 319 379 +3 102 221 320 +3 221 19 320 +3 55 108 321 +3 136 458 524 +3 322 184 323 +3 183 322 402 +3 21 200 323 +3 200 97 323 +3 176 324 492 +3 176 12 324 +3 231 7 325 +3 7 122 325 +3 326 212 383 +3 168 326 358 +3 185 84 327 +3 84 218 327 +3 116 266 328 +3 266 56 328 +3 36 175 329 +3 175 360 361 +3 171 329 330 +3 329 94 330 +3 331 98 510 +3 31 331 510 +3 97 200 332 +3 200 62 332 +3 75 298 333 +3 298 91 333 +3 91 179 334 +3 179 30 334 +3 131 230 335 +3 230 75 335 +3 137 334 336 +3 334 30 336 +3 37 253 337 +3 253 103 337 +3 103 369 437 +3 369 103 531 +3 155 287 339 +3 287 76 339 +3 90 194 340 +3 68 340 436 +3 340 214 341 +3 214 11 341 +3 79 189 342 +3 189 112 342 +3 343 310 477 +3 152 343 477 +3 222 344 416 +3 222 67 344 +3 345 258 372 +3 44 345 372 +3 223 99 439 +3 99 346 439 +3 45 347 405 +3 45 405 479 +3 224 10 406 +3 10 128 406 +3 96 252 349 +3 252 29 349 +3 164 350 384 +3 110 350 416 +3 247 86 351 +3 225 366 483 +3 143 362 377 +3 362 132 377 +3 145 270 353 +3 270 4 353 +3 56 162 534 +3 162 17 354 +3 243 72 355 +3 72 244 355 +3 46 370 394 +3 370 141 394 +3 61 183 357 +3 183 98 357 +3 15 211 358 +3 211 98 358 +3 304 500 536 +3 24 304 536 +3 94 329 361 +3 329 175 361 +3 414 47 447 +3 47 265 447 +3 261 132 362 +3 132 352 377 +3 363 64 527 +3 123 363 527 +3 382 101 386 +3 186 364 373 +3 365 225 482 +3 85 289 461 +3 225 26 366 +3 26 207 366 +3 278 342 367 +3 342 112 367 +3 27 317 368 +3 317 141 368 +3 338 25 531 +3 25 369 531 +3 368 141 370 +3 141 356 394 +3 49 196 371 +3 371 196 465 +3 196 144 465 +3 44 372 508 +3 101 237 373 +3 33 373 389 +3 147 374 393 +3 374 147 420 +3 105 375 380 +3 347 105 380 +3 296 376 403 +3 296 154 376 +3 377 50 443 +3 143 377 443 +3 378 136 524 +3 68 378 524 +3 356 140 394 +3 140 296 379 +3 375 52 380 +3 52 104 380 +3 300 381 492 +3 300 53 381 +3 101 364 386 +3 50 382 443 +3 109 215 383 +3 383 215 434 +3 35 245 384 +3 245 109 384 +3 384 385 540 +3 384 109 385 +3 191 18 386 +3 18 205 386 +3 226 19 387 +3 400 165 462 +3 40 220 388 +3 220 102 388 +3 373 237 389 +3 237 106 389 +3 106 237 390 +3 237 50 390 +3 473 216 476 +3 155 391 513 +3 77 153 392 +3 392 153 408 +3 39 275 393 +3 393 275 409 +3 140 379 394 +3 379 46 394 +3 37 228 395 +3 228 113 395 +3 113 238 396 +3 396 238 451 +3 49 166 397 +3 166 113 397 +3 38 398 526 +3 258 13 399 +3 13 167 399 +3 222 59 400 +3 250 165 498 +3 119 259 401 +3 259 6 401 +3 267 31 402 +3 98 183 510 +3 54 239 403 +3 239 117 403 +3 34 263 404 +3 263 123 404 +3 405 347 519 +3 129 405 519 +3 128 348 406 +3 348 129 406 +3 51 246 407 +3 246 129 407 +3 111 277 408 +3 277 25 408 +3 78 277 409 +3 277 111 409 +3 393 111 493 +3 111 410 493 +3 102 220 411 +3 411 220 449 +3 114 244 412 +3 244 72 412 +3 14 244 413 +3 244 114 413 +3 361 203 447 +3 203 414 447 +3 415 250 498 +3 59 212 415 +3 350 164 416 +3 164 222 416 +3 359 170 463 +3 463 170 541 +3 280 16 418 +3 16 161 418 +3 127 291 419 +3 291 14 419 +3 74 259 420 +3 259 119 420 +3 168 358 421 +3 358 98 421 +3 499 217 516 +3 422 217 475 +3 140 324 471 +3 324 12 471 +3 27 152 424 +3 310 93 477 +3 201 274 425 +3 274 73 425 +3 63 297 426 +3 297 135 426 +3 404 236 427 +3 236 135 427 +3 61 187 428 +3 187 135 428 +3 398 229 429 +3 229 56 429 +3 84 195 476 +3 195 125 430 +3 431 39 484 +3 266 431 484 +3 71 209 432 +3 209 117 432 +3 427 187 433 +3 187 120 433 +3 120 211 434 +3 211 15 434 +3 120 215 435 +3 215 70 435 +3 340 194 436 +3 194 188 436 +3 277 78 437 +3 78 219 437 +3 285 92 438 +3 92 267 438 +3 45 303 439 +3 303 223 439 +3 34 235 489 +3 235 70 440 +3 121 234 441 +3 234 22 441 +3 313 204 442 +3 172 69 522 +3 382 205 443 +3 443 205 478 +3 124 444 504 +3 353 124 504 +3 132 261 445 +3 261 48 445 +3 136 378 491 +3 446 136 491 +3 265 94 447 +3 94 361 447 +3 91 268 448 +3 268 32 448 +3 256 344 449 +3 344 67 449 +3 375 124 450 +3 124 174 450 +3 451 139 452 +3 23 451 452 +3 209 241 452 +3 241 23 452 +3 260 192 453 +3 192 259 453 +3 284 28 515 +3 28 454 515 +3 148 292 545 +3 292 95 455 +3 291 127 456 +3 127 213 456 +3 210 338 457 +3 338 79 457 +3 136 321 458 +3 321 108 458 +3 188 389 459 +3 389 106 459 +3 158 282 518 +3 282 159 460 +3 461 182 530 +3 160 461 530 +3 165 387 462 +3 387 19 462 +3 417 24 541 +3 24 463 541 +3 311 178 470 +3 178 464 470 +3 372 107 508 +3 107 465 508 +3 40 208 466 +3 466 208 467 +3 66 206 467 +3 206 130 467 +3 130 280 468 +3 280 77 468 +3 71 270 469 +3 270 145 469 +3 300 93 470 +3 93 311 470 +3 154 296 471 +3 296 140 471 +3 130 206 472 +3 206 16 472 +3 391 134 513 +3 134 473 513 +3 216 473 474 +3 473 134 474 +3 391 167 475 +3 167 13 475 +3 195 430 476 +3 430 43 476 +3 93 424 477 +3 424 152 477 +3 143 478 506 +3 260 143 506 +3 138 303 479 +3 303 45 479 +3 137 316 480 +3 316 60 480 +3 60 290 481 +3 290 133 481 +3 133 290 482 +3 290 85 482 +3 86 318 483 +3 318 133 483 +3 315 115 484 +3 115 266 484 +3 221 67 485 +3 67 222 485 +3 197 442 486 +3 442 69 486 +3 149 5 487 +3 5 157 487 +3 284 282 488 +3 282 158 488 +3 235 440 489 +3 440 121 489 +3 170 359 490 +3 359 51 490 +3 151 207 491 +3 207 26 491 +3 492 89 525 +3 300 492 525 +3 48 261 493 +3 261 147 493 +3 486 69 494 +3 69 232 494 +3 232 172 495 +3 73 495 543 +3 112 286 496 +3 286 76 496 +3 139 451 497 +3 451 72 497 +3 165 400 498 +3 400 59 498 +3 173 306 499 +3 306 65 499 +3 82 303 500 +3 303 138 500 +3 497 243 501 +3 243 46 501 +3 90 341 512 +3 341 180 512 +3 334 137 503 +3 137 268 503 +3 145 504 505 +3 269 145 505 +3 504 444 505 +3 444 44 505 +3 478 142 506 +3 142 41 506 +3 131 251 507 +3 251 92 507 +3 144 269 508 +3 269 44 508 +3 196 396 509 +3 396 23 509 +3 183 402 510 +3 402 31 510 +3 211 120 511 +3 120 187 511 +3 502 252 512 +3 252 90 512 +3 43 287 513 +3 287 155 513 +3 155 339 514 +3 339 49 514 +3 181 230 515 +3 230 131 515 +3 217 422 516 +3 422 82 516 +3 255 448 517 +3 448 32 517 +3 282 460 518 +3 460 3 518 +3 224 406 519 +3 406 129 519 +3 66 467 520 +3 467 208 520 +3 78 275 521 +3 275 116 521 +3 69 442 522 +3 442 204 522 +3 223 422 523 +3 422 13 523 +3 214 340 524 +3 340 68 524 +3 89 248 525 +3 248 300 525 +3 398 314 526 +3 314 163 526 +3 546 231 547 +3 231 123 527 +3 150 197 528 +3 197 64 528 +3 22 307 529 +3 307 150 529 +3 55 321 530 +3 321 160 530 +3 103 189 531 +3 189 338 531 +3 216 474 532 +3 474 65 532 +3 8 256 533 +3 256 126 533 +3 162 354 534 +3 354 87 534 +3 240 350 535 +3 350 110 535 +3 138 463 536 +3 463 24 536 +3 151 301 537 +3 301 80 537 +3 213 127 538 +3 127 283 538 +3 118 254 539 +3 254 75 539 +3 59 222 540 +3 222 164 540 +3 495 172 543 +3 172 417 541 +3 494 232 542 +3 232 20 542 +3 172 541 543 +3 541 170 543 +3 276 521 544 +3 521 116 544 +3 292 455 545 +3 455 0 545 +3 199 42 546 +3 42 198 546 +3 231 527 547 +3 527 64 547 + diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h index 01763dbbd60..0745ab75802 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h @@ -80,6 +80,17 @@ bool handle_exists ( Iterator begin, Iterator end, Handle h ) return false ; } +template +struct No_constrained_edge_map{ + typedef typename boost::graph_traits::edge_descriptor key_type; + typedef bool value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + friend bool get(No_constrained_edge_map, key_type) { + return false; + } +}; + } // namespace Surface_mesh_simplification template diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h index b38d79ea315..b3355e6e27d 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h @@ -35,6 +35,7 @@ templateid() % xyz_to_string(p) ) ; + return boost::str( boost::format("[V%1%:%2%]") % get(Vertex_index_map,v) % xyz_to_string(p) ) ; } std::string edge_to_string ( const_edge_descriptor const& aEdge ) const { const_vertex_descriptor p,q ; boost::tie(p,q) = get_vertices(aEdge); - return boost::str( boost::format("{E%1% %2%->%3%}%4%") % aEdge->id() % vertex_to_string(p) % vertex_to_string(q) % ( is_border(aEdge) ? " (BORDER)" : ( is_border(aEdge->opposite()) ? " (~BORDER)": "" ) ) ) ; + return boost::str( boost::format("{E%1% %2%->%3%}%4%") % get(Edge_index_map,aEdge) % vertex_to_string(p) % vertex_to_string(q) % ( is_border(aEdge) ? " (BORDER)" : ( is_border(aEdge->opposite()) ? " (~BORDER)": "" ) ) ) ; } Cost_type get_cost ( Profile const& aProfile ) const @@ -321,18 +332,55 @@ private: } return rEdge ; } - + + /// Functions to ensure the backward compatibility before addition of the constrained edge map + template + vertex_descriptor + halfedge_collapse_bk_compatibility( + edge_descriptor const& pq, AEdgeIsConstrainedMap aEdge_is_constrained_map) + { + return halfedge_collapse(pq, mSurface, aEdge_is_constrained_map); + } + + template + vertex_descriptor + halfedge_collapse_bk_compatibility( + edge_descriptor const& pq, No_constrained_edge_map ) + { + return halfedge_collapse(pq, mSurface); + } + /// + + /// We wrap this test to avoid penalizing runtime when no constraints are present + template + bool + is_edge_adjacent_to_a_constrained_edge( + Profile const& aProfile, AEdgeIsConstrainedMap) + { + return is_constrained(aProfile.v0()) && is_constrained(aProfile.v1()); + } + + template + bool + is_edge_adjacent_to_a_constrained_edge( + edge_descriptor const&, No_constrained_edge_map ) + { + return false; + } + /// + private: ECM& mSurface ; - ShouldStop const& Should_stop ; - VertexIndexMap const& Vertex_index_map ; - EdgeIndexMap const& Edge_index_map ; - EdgeIsBorderMap const& Edge_is_border_map ; - GetCost const& Get_cost ; - GetPlacement const& Get_placement ; - VisitorT Visitor ; + ShouldStop const& Should_stop ; + VertexIndexMap const& Vertex_index_map ; + EdgeIndexMap const& Edge_index_map ; + EdgeIsBorderMap const& Edge_is_border_map; + EdgeIsConstrainedMap const& Edge_is_constrained_map; + GetCost const& Get_cost ; + GetPlacement const& Get_placement ; + VisitorT Visitor ; private: diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h index d60b4b429fd..83751ccf3c2 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h @@ -24,15 +24,16 @@ namespace CGAL { namespace Surface_mesh_simplification { -template -EdgeCollapse::EdgeCollapse( ECM& aSurface - , ShouldStop const& aShould_stop - , VertexIndexMap const& aVertex_index_map - , EdgeIndexMap const& aEdge_index_map - , EdgeIsBorderMap const& aEdge_is_border_map - , GetCost const& aGet_cost - , GetPlacement const& aGet_placement - , VisitorT aVisitor +template +EdgeCollapse::EdgeCollapse( ECM& aSurface + , ShouldStop const& aShould_stop + , VertexIndexMap const& aVertex_index_map + , EdgeIndexMap const& aEdge_index_map + , EdgeIsBorderMap const& aEdge_is_border_map + , EdgeIsConstrainedMap const& aEdge_is_constrained_map + , GetCost const& aGet_cost + , GetPlacement const& aGet_placement + , VisitorT aVisitor ) : mSurface (aSurface) @@ -40,6 +41,7 @@ EdgeCollapse::EdgeCollapse( ECM& aS ,Vertex_index_map (aVertex_index_map) ,Edge_index_map (aEdge_index_map) ,Edge_is_border_map (aEdge_is_border_map) + ,Edge_is_constrained_map (aEdge_is_constrained_map) ,Get_cost (aGet_cost) ,Get_placement (aGet_placement) ,Visitor (aVisitor) @@ -63,8 +65,8 @@ EdgeCollapse::EdgeCollapse( ECM& aS #endif } -template -int EdgeCollapse::run() +template +int EdgeCollapse::run() { CGAL_SURF_SIMPL_TEST_assertion( mSurface.is_valid() && mSurface.is_pure_triangle() ) ; @@ -85,8 +87,8 @@ int EdgeCollapse::run() return r ; } -template -void EdgeCollapse::Collect() +template +void EdgeCollapse::Collect() { CGAL_ECMS_TRACE(0,"Collecting edges..."); @@ -114,10 +116,12 @@ void EdgeCollapse::Collect() std::set zero_length_edges; undirected_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = undirected_edges(mSurface); eb!=ee; ++eb ) + for ( boost::tie(eb,ee) = undirected_edges(mSurface); eb!=ee; ++eb, id+=2 ) { edge_descriptor lEdge = *eb ; - + + if ( is_constrained(lEdge) ) continue;//no not insert constrainted edges + CGAL_assertion( get_directed_edge_id(lEdge) == id ) ; CGAL_assertion( get_directed_edge_id(opposite_edge(lEdge,mSurface)) == id+1 ) ; @@ -141,8 +145,6 @@ void EdgeCollapse::Collect() CGAL_ECMS_TRACE(2,edge_to_string(lEdge)); - - id += 2 ; } CGAL_SURF_SIMPL_TEST_assertion ( lInserted + lNotInserted == mInitialEdgeCount ) ; @@ -156,20 +158,48 @@ void EdgeCollapse::Collect() // edges of length 0 removed no longer need to be treated if ( lProfile.left_face_exists() ) - zero_length_edges.erase( primary_edge(lProfile.vL_v0()) ); - if ( lProfile.right_face_exists() ) - zero_length_edges.erase( primary_edge(lProfile.vR_v1()) ); + { + edge_descriptor lEdge_to_remove = is_constrained(lProfile.vL_v0()) ? + primary_edge(lProfile.v1_vL()) : + primary_edge(lProfile.vL_v0()) ; + zero_length_edges.erase( lEdge_to_remove ); + Edge_data& lData = get_data(lEdge_to_remove) ; + if ( lData.is_in_PQ() ){ + CGAL_ECMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ" ); + remove_from_PQ(lEdge_to_remove,lData); + } + --mCurrentEdgeCount; + } + + if ( lProfile.right_face_exists() ) + { + edge_descriptor lEdge_to_remove = is_constrained(lProfile.vR_v1()) ? + primary_edge(lProfile.v0_vR()) : + primary_edge(lProfile.vR_v1()) ; + zero_length_edges.erase( lEdge_to_remove ); + Edge_data& lData = get_data(lEdge_to_remove) ; + if ( lData.is_in_PQ() ){ + CGAL_ECMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ" ); + remove_from_PQ(lEdge_to_remove,lData); + } + --mCurrentEdgeCount; + } + + --mCurrentEdgeCount; //the placement is trivial, it's always the point itself Placement_type lPlacement = lProfile.p0(); - Collapse(lProfile ,lPlacement); + vertex_descriptor rResult + = halfedge_collapse_bk_compatibility(lProfile.v0_v1(), Edge_is_constrained_map); + put(vertex_point,mSurface,rResult,*lPlacement); + Visitor.OnCollapsed(lProfile,rResult); } - + CGAL_ECMS_TRACE(0,"Initial edge count: " << mInitialEdgeCount ) ; } -template -void EdgeCollapse::Loop() +template +void EdgeCollapse::Loop() { CGAL_ECMS_TRACE(0,"Collapsing edges...") ; @@ -180,18 +210,23 @@ void EdgeCollapse::Loop() // Pops and processes each edge from the PQ // optional lEdge ; + #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + int i_rm=0; + #endif while ( (lEdge = pop_from_PQ()) ) { CGAL_SURF_SIMPL_TEST_assertion ( lLoop_watchdog ++ < mInitialEdgeCount ) ; CGAL_ECMS_TRACE(1,"Poped " << edge_to_string(*lEdge) ) ; + + CGAL_assertion( !is_constrained(*lEdge) ); Profile const& lProfile = create_profile(*lEdge); - + Cost_type lCost = get_data(*lEdge).cost(); Visitor.OnSelected(lProfile,lCost,mInitialEdgeCount,mCurrentEdgeCount); - + if ( lCost ) { if ( Should_stop(*lCost,lProfile,mInitialEdgeCount,mCurrentEdgeCount) ) @@ -212,7 +247,22 @@ void EdgeCollapse::Loop() Placement_type lPlacement = get_placement(lProfile); if ( Is_collapse_geometrically_valid(lProfile,lPlacement) ) + { + #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + std::cout << "step " << i_rm << " " << source(*lEdge,mSurface)->point() << " " << target(*lEdge,mSurface)->point() << "\n"; + #endif Collapse(lProfile,lPlacement); + #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + std::stringstream sstr; + sstr << "debug/P-"; + if (i_rm<10) sstr << "0"; + if (i_rm<100) sstr << "0"; + sstr << i_rm << ".off"; + std::ofstream out(sstr.str().c_str()); + out << mSurface; + ++i_rm; + #endif + } } else { @@ -230,8 +280,8 @@ void EdgeCollapse::Loop() } } -template -bool EdgeCollapse::is_border( const_vertex_descriptor const& aV ) const +template +bool EdgeCollapse::is_border( const_vertex_descriptor const& aV ) const { bool rR = false ; @@ -249,22 +299,44 @@ bool EdgeCollapse::is_border( const_vertex_descriptor return rR ; } +template +bool EdgeCollapse::is_border_or_constrained( const_vertex_descriptor const& aV ) const +{ + const_in_edge_iterator eb, ee ; + for ( boost::tie(eb,ee) = in_edges(aV,mSurface) ; eb != ee ; ++ eb ) + { + const_edge_descriptor lEdge = *eb ; + if ( is_undirected_edge_a_border(lEdge) || is_constrained(lEdge) ) + return true; + } + return false; +} + +template +bool EdgeCollapse::is_constrained( const_vertex_descriptor const& aV ) const +{ + const_in_edge_iterator eb, ee ; + for ( boost::tie(eb,ee) = in_edges(aV,mSurface) ; eb != ee ; ++ eb ) + if ( is_constrained(*eb) ) return true; + return false; +} + // Some edges are NOT collapsable: doing so would break the topological consistency of the mesh. // This function returns true if a edge 'p->q' can be collapsed. // // An edge p->q can be collapsed iff it satisfies the "link condition" // (as described in the "Mesh Optimization" article of Hoppe et al (1993)) // -// The link conidition is as follows: for every vertex 'k' adjacent to both 'p and 'q', +// The link condition is as follows: for every vertex 'k' adjacent to both 'p and 'q', // "p,k,q" is a facet of the mesh. // -template -bool EdgeCollapse::Is_collapse_topologically_valid( Profile const& aProfile ) +template +bool EdgeCollapse::Is_collapse_topologically_valid( Profile const& aProfile ) { bool rR = true ; - CGAL_ECMS_TRACE(3,"Testing topological collapsabilty of p_q=V" << aProfile.v0()->id() << "(%" << aProfile.v0()->vertex_degree() << ")" - << "->V" << aProfile.v1()->id() << "(%" << aProfile.v1()->vertex_degree() << ")" + CGAL_ECMS_TRACE(3,"Testing topological collapsabilty of p_q=V" << get(Vertex_index_map,aProfile.v0()) << "(%" << aProfile.v0()->vertex_degree() << ")" + << "->V" << get(Vertex_index_map,aProfile.v1()) << "(%" << aProfile.v1()->vertex_degree() << ")" ); CGAL_ECMS_TRACE(4, "is p_q border:" << aProfile.is_v0_v1_a_border() ); @@ -274,13 +346,13 @@ bool EdgeCollapse::Is_collapse_topologically_valid( Pr out_edge_iterator eb2, ee2 ; CGAL_ECMS_TRACE(4," t=V" - << ( aProfile.left_face_exists() ? aProfile.vL()->id() : -1 ) + << ( aProfile.left_face_exists() ? get(Vertex_index_map,aProfile.vL()) : -1 ) << "(%" << ( aProfile.left_face_exists() ? aProfile.vL()->vertex_degree() : 0 ) << ")" ); CGAL_ECMS_TRACE(4," b=V" - << ( aProfile.right_face_exists() ? aProfile.vR()->id() : -1 ) + << ( aProfile.right_face_exists() ? get(Vertex_index_map,aProfile.vR()) : -1 ) << "(%" << ( aProfile.right_face_exists() ? aProfile.vR()->vertex_degree() :0 ) << ")" @@ -343,13 +415,13 @@ bool EdgeCollapse::Is_collapse_topologically_valid( Pr if ( !lIsFace ) { - CGAL_ECMS_TRACE(3," k=V" << k->id() << " IS NOT in a face with p-q. NON-COLLAPSABLE edge." ) ; + CGAL_ECMS_TRACE(3," k=V" << get(Vertex_index_map,k) << " IS NOT in a face with p-q. NON-COLLAPSABLE edge." ) ; rR = false ; break ; } else { - CGAL_ECMS_TRACE(4," k=V" << k->id() << " is in a face with p-q") ; + CGAL_ECMS_TRACE(4," k=V" << get(Vertex_index_map,k) << " is in a face with p-q") ; } } } @@ -358,6 +430,10 @@ bool EdgeCollapse::Is_collapse_topologically_valid( Pr if ( rR ) { + /// ensure two constrained edges cannot get merged + if ( is_edge_adjacent_to_a_constrained_edge( + aProfile, Edge_is_constrained_map) ) return false ; + if ( aProfile.is_v0_v1_a_border() ) { if ( Is_open_triangle(aProfile.v0_v1()) ) @@ -399,8 +475,8 @@ bool EdgeCollapse::Is_collapse_topologically_valid( Pr return rR ; } -template -bool EdgeCollapse::Is_tetrahedron( edge_descriptor const& h1 ) +template +bool EdgeCollapse::Is_tetrahedron( edge_descriptor const& h1 ) { // // Code copied from Polyhedron_3::is_tetrahedron() @@ -451,8 +527,8 @@ bool EdgeCollapse::Is_tetrahedron( edge_descriptor con return true; } -template -bool EdgeCollapse::Is_open_triangle( edge_descriptor const& h1 ) +template +bool EdgeCollapse::Is_open_triangle( edge_descriptor const& h1 ) { bool rR = false ; @@ -463,7 +539,7 @@ bool EdgeCollapse::Is_open_triangle( edge_descriptor c if ( next_edge(h3,mSurface) == h1 ) { // Now check if it is open - CGAL_ECMS_TRACE(4," p-q is a border edge... checking E" << h2->id() << " and E" << h3->id() ) ; + CGAL_ECMS_TRACE(4," p-q is a border edge... checking E" << get(Edge_index_map,h2) << " and E" << get(Edge_index_map,h3) ) ; rR = is_border(h2) && is_border(h3); @@ -482,8 +558,8 @@ bool EdgeCollapse::Is_open_triangle( edge_descriptor c // respective areas is no greater than a max value and the internal // dihedral angle formed by their supporting planes is no greater than // a given threshold -template -bool EdgeCollapse::are_shared_triangles_valid( Point const& p0, Point const& p1, Point const& p2, Point const& p3 ) const +template +bool EdgeCollapse::are_shared_triangles_valid( Point const& p0, Point const& p1, Point const& p2, Point const& p3 ) const { bool rR = false ; @@ -533,9 +609,9 @@ bool EdgeCollapse::are_shared_triangles_valid( Point c } // Returns the directed halfedge connecting v0 to v1, if exists. -template -typename EdgeCollapse::edge_descriptor -EdgeCollapse::find_connection ( const_vertex_descriptor const& v0, const_vertex_descriptor const& v1 ) const +template +typename EdgeCollapse::edge_descriptor +EdgeCollapse::find_connection ( const_vertex_descriptor const& v0, const_vertex_descriptor const& v1 ) const { out_edge_iterator eb, ee ; for ( boost::tie(eb,ee) = out_edges(v0,mSurface) ; eb != ee ; ++ eb ) @@ -549,10 +625,10 @@ EdgeCollapse::find_connection ( const_vertex_descripto } // Given the edge 'e' around the link for the collapsinge edge "v0-v1", finds the vertex that makes a triangle adjacent to 'e' but exterior to the link (i.e not containing v0 nor v1) -// If 'e' is a mnull handle OR 'e' is a border edge, there is no such triangle and a null handle is returned. -template -typename EdgeCollapse::vertex_descriptor -EdgeCollapse::find_exterior_link_triangle_3rd_vertex ( const_edge_descriptor const& e, const_vertex_descriptor const& v0, const_vertex_descriptor const& v1 ) const +// If 'e' is a null handle OR 'e' is a border edge, there is no such triangle and a null handle is returned. +template +typename EdgeCollapse::vertex_descriptor +EdgeCollapse::find_exterior_link_triangle_3rd_vertex ( const_edge_descriptor const& e, const_vertex_descriptor const& v0, const_vertex_descriptor const& v1 ) const { vertex_descriptor r ; @@ -581,15 +657,15 @@ EdgeCollapse::find_exterior_link_triangle_3rd_vertex ( } -// A collase is geometrically valid if, in the resulting local mesh no two adjacent triangles form an internal dihedral angle +// A collapse is geometrically valid if, in the resulting local mesh no two adjacent triangles form an internal dihedral angle // greater than a fixed threshold (i.e. triangles do not "fold" into each other) // -template -bool EdgeCollapse::Is_collapse_geometrically_valid( Profile const& aProfile, Placement_type k0) +template +bool EdgeCollapse::Is_collapse_geometrically_valid( Profile const& aProfile, Placement_type k0) { bool rR = true ; - CGAL_ECMS_TRACE(3,"Testing geometrical collapsabilty of v0-v1=E" << aProfile.v0_v1()->id() ); + CGAL_ECMS_TRACE(3,"Testing geometrical collapsabilty of v0-v1=E" << get(Edge_index_map,aProfile.v0_v1()) ); if ( k0 ) { // @@ -610,7 +686,7 @@ bool EdgeCollapse::Is_collapse_geometrically_valid( Pr vertex_descriptor k2 = * l ; vertex_descriptor k3 = *nx ; - CGAL_ECMS_TRACE(4," Screening link vertices k1=V" << k1->id() << " k2=V" << k2->id() << " k3=V" << k3->id() ) ; + CGAL_ECMS_TRACE(4," Screening link vertices k1=V" << get(Vertex_index_map,k1) << " k2=V" << get(Vertex_index_map,k2) << " k3=V" << get(Vertex_index_map,k3) ) ; edge_descriptor e12 = find_connection(k1,k2); edge_descriptor e23 = k3 != k1 ? find_connection(k2,k3) : edge_descriptor() ; @@ -622,7 +698,7 @@ bool EdgeCollapse::Is_collapse_geometrically_valid( Pr if ( !are_shared_triangles_valid( *k0, get_point(k1), get_point(k2), get_point(k3) ) ) { - CGAL_ECMS_TRACE(3," Triangles VX-V" << k1->id() << "-V" << k2->id() << " and VX-V" << k3->id() << " are not geometrically valid. Collapse rejected"); + CGAL_ECMS_TRACE(3," Triangles VX-V" << get(Vertex_index_map,k1) << "-V" << get(Vertex_index_map,k2) << " and VX-V" << get(Vertex_index_map,k3) << " are not geometrically valid. Collapse rejected"); rR = false ; } } @@ -635,11 +711,11 @@ bool EdgeCollapse::Is_collapse_geometrically_valid( Pr // There is indeed a triangle shared along e12 if ( handle_assigned(k4) ) { - CGAL_ECMS_TRACE(4," Found exterior link triangle shared along E" << e12->id() << " with third vertex: V" << k4->id() ) ; + CGAL_ECMS_TRACE(4," Found exterior link triangle shared along E" << get(Edge_index_map,e12) << " with third vertex: V" << get(Vertex_index_map,k4) ) ; if ( !are_shared_triangles_valid( get_point(k1), get_point(k4), get_point(k2), *k0 ) ) { - CGAL_ECMS_TRACE(3," Triangles V" << k1->id() << "-V" << k4->id() << " and V" << k2->id() << "-VX are not geometrically valid. Collapse rejected"); + CGAL_ECMS_TRACE(3," Triangles V" << get(Vertex_index_map,k1) << "-V" << get(Vertex_index_map,k4) << " and V" << get(Vertex_index_map,k2) << "-VX are not geometrically valid. Collapse rejected"); rR = false ; } } @@ -653,11 +729,11 @@ bool EdgeCollapse::Is_collapse_geometrically_valid( Pr // There is indeed a triangle shared along e12 if ( handle_assigned(k5) ) { - CGAL_ECMS_TRACE(4," Found exterior link triangle shared along E" << e23->id() << " with third vertex: V" << k5->id() ) ; + CGAL_ECMS_TRACE(4," Found exterior link triangle shared along E" << get(Edge_index_map,e23) << " with third vertex: V" << get(Vertex_index_map,k5) ) ; if ( !are_shared_triangles_valid( get_point(k2), get_point(k5), get_point(k3), *k0 ) ) { - CGAL_ECMS_TRACE(3," Triangles V" << k2->id() << "-V" << k5->id() << " and V" << k3->id() << "-VX are not geometrically valid. Collapse rejected"); + CGAL_ECMS_TRACE(3," Triangles V" << get(Vertex_index_map,k2) << "-V" << get(Vertex_index_map,k5) << " and V" << get(Vertex_index_map,k3) << "-VX are not geometrically valid. Collapse rejected"); rR = false ; } } @@ -669,8 +745,8 @@ bool EdgeCollapse::Is_collapse_geometrically_valid( Pr return rR ; } -template -void EdgeCollapse::Collapse( Profile const& aProfile, Placement_type aPlacement ) +template +void EdgeCollapse::Collapse( Profile const& aProfile, Placement_type aPlacement ) { CGAL_ECMS_TRACE(1,"S" << mStep << ". Collapsig " << edge_to_string(aProfile.v0_v1()) ) ; @@ -691,15 +767,17 @@ void EdgeCollapse::Collapse( Profile const& aProfile, if ( aProfile.left_face_exists() ) { edge_descriptor lV0VL = primary_edge(aProfile.vL_v0()); + if ( is_constrained(lV0VL) ) //make sure a constrained edge will not disappear + lV0VL=primary_edge(aProfile.v1_vL()); - CGAL_ECMS_TRACE(3,"V0VL E" << lV0VL->id() - << "(V" << lV0VL->vertex()->id() << "->V" << lV0VL->opposite()->vertex()->id() << ")" + CGAL_ECMS_TRACE(3,"V0VL E" << get(Edge_index_map,lV0VL) + << "(V" << get(Vertex_index_map,lV0VL->vertex()) << "->V" << get(Vertex_index_map,lV0VL->opposite()->vertex()) << ")" ) ; Edge_data& lData = get_data(lV0VL) ; if ( lData.is_in_PQ() ) { - CGAL_ECMS_TRACE(2,"Removing E" << lV0VL->id() << " from PQ" ) ; + CGAL_ECMS_TRACE(2,"Removing E" << get(Edge_index_map,lV0VL) << " from PQ" ) ; remove_from_PQ(lV0VL,lData) ; } @@ -710,22 +788,24 @@ void EdgeCollapse::Collapse( Profile const& aProfile, if ( aProfile.right_face_exists() ) { edge_descriptor lVRV1 = primary_edge(aProfile.vR_v1()); - - CGAL_ECMS_TRACE(3,"V1VRE" << lVRV1->id() - << "(V" << lVRV1->vertex()->id() << "->V" << lVRV1->opposite()->vertex()->id() << ")" + if ( is_constrained(lVRV1) ) //make sure a constrained edge will not disappear + lVRV1=primary_edge(aProfile.v0_vR()); + + CGAL_ECMS_TRACE(3,"V1VRE" << get(Edge_index_map,lVRV1) + << "(V" << get(Vertex_index_map,lVRV1->vertex()) << "->V" << get(Vertex_index_map,lVRV1->opposite()->vertex()) << ")" ) ; Edge_data& lData = get_data(lVRV1) ; if ( lData.is_in_PQ() ) { - CGAL_ECMS_TRACE(2,"Removing E" << lVRV1->id() << " from PQ") ; + CGAL_ECMS_TRACE(2,"Removing E" << get(Edge_index_map,lVRV1) << " from PQ") ; remove_from_PQ(lVRV1,lData) ; } -- mCurrentEdgeCount ; CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingEdgeCount ) ; } - CGAL_ECMS_TRACE(1,"Removing:\n v0v1: E" << aProfile.v0_v1()->id() << "(V" << aProfile.v0()->id() << "->V" << aProfile.v1()->id() << ")" ); + CGAL_ECMS_TRACE(1,"Removing:\n v0v1: E" << get(Edge_index_map,aProfile.v0_v1()) << "(V" << get(Vertex_index_map,aProfile.v0()) << "->V" << get(Vertex_index_map,aProfile.v1()) << ")" ); // Perform the actuall collapse. @@ -734,7 +814,7 @@ void EdgeCollapse::Collapse( Profile const& aProfile, // (PT and QB are removed if they are not null). // All other edges must be kept. // All directed edges incident to vertex removed are relink to the vertex kept. - rResult = halfedge_collapse(aProfile.v0_v1(),mSurface); + rResult = halfedge_collapse_bk_compatibility(aProfile.v0_v1(), Edge_is_constrained_map); CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingEdgeCount ) ; @@ -746,7 +826,7 @@ void EdgeCollapse::Collapse( Profile const& aProfile, CGAL_SURF_SIMPL_TEST_assertion( mSurface.is_valid() && mSurface.is_pure_triangle() ) ; - CGAL_ECMS_TRACE(1,"V" << rResult->id() << " kept." ) ; + CGAL_ECMS_TRACE(1,"V" << get(Vertex_index_map,rResult) << " kept." ) ; #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE out_edge_iterator eb1, ee1 ; @@ -767,8 +847,8 @@ void EdgeCollapse::Collapse( Profile const& aProfile, CGAL_ECMS_DEBUG_CODE ( ++mStep ; ) } -template -void EdgeCollapse::Update_neighbors( vertex_descriptor const& aKeptV ) +template +void EdgeCollapse::Update_neighbors( vertex_descriptor const& aKeptV ) { CGAL_ECMS_TRACE(3,"Updating cost of neighboring edges..." ) ; @@ -795,7 +875,7 @@ void EdgeCollapse::Update_neighbors( vertex_descriptor edge_descriptor lEdge2 = primary_edge(*eb2) ; Edge_data& lData2 = get_data(lEdge2); - CGAL_ECMS_TRACE(4,"Inedge around V" << lAdj_k->id() << edge_to_string(lEdge2) ) ; + CGAL_ECMS_TRACE(4,"Inedge around V" << get(Vertex_index_map,lAdj_k) << edge_to_string(lEdge2) ) ; // Only those edges still in the PQ _and_ not already collected are updated. if ( lData2.is_in_PQ() && lToUpdate.find(lEdge2) == lToUpdate.end() ) diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h new file mode 100644 index 00000000000..28c8df82550 --- /dev/null +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h @@ -0,0 +1,80 @@ +// Copyright (c) 2014 GeometryFactory (France). All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Sebastien Loriot +// +#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_CONSTRAINED_PLACEMENT_H +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_CONSTRAINED_PLACEMENT_H + +#include +#include + +namespace CGAL { + +namespace Surface_mesh_simplification +{ + +template +class Constrained_placement : public BasePlacement +{ +public: + + typedef typename BasePlacement::Profile Profile; + typedef typename BasePlacement::Point Point; + typedef optional result_type ; + EdgeIsConstrainedMap Edge_is_constrained_map; + +public: + Constrained_placement( + EdgeIsConstrainedMap map=EdgeIsConstrainedMap(), + BasePlacement base=BasePlacement() ) + : BasePlacement(base) + , Edge_is_constrained_map(map) + {} + + result_type operator()( Profile const& aProfile ) const + { + typedef typename Profile::ECM ECM; + typedef typename boost::graph_traits GraphTraits; + typedef typename GraphTraits::in_edge_iterator in_edge_iterator; + + in_edge_iterator eb, ee ; + for ( boost::tie(eb,ee) = in_edges(aProfile.v0(),aProfile.surface()) ; + eb != ee ; ++ eb ) + { + if( get(Edge_is_constrained_map, *eb) ) + return get(vertex_point, + aProfile.surface(), + aProfile.v0()); + } + for ( boost::tie(eb,ee) = in_edges(aProfile.v1(),aProfile.surface()) ; + eb != ee ; ++ eb ) + { + if( get(Edge_is_constrained_map, *eb) ) + return get(vertex_point, + aProfile.surface(), + aProfile.v1()); + } + + return static_cast(this)->operator()(aProfile); + } +}; + +} // namespace Surface_mesh_simplification + +} //namespace CGAL + +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_CONSTRAINED_PLACEMENT_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h index 6ec50601987..eb066093ec4 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace CGAL { @@ -35,23 +36,25 @@ template -int edge_collapse ( ECM& aSurface - , ShouldStop const& aShould_stop +int edge_collapse ( ECM& aSurface + , ShouldStop const& aShould_stop // optional mesh information policies - , VertexIndexMap const& aVertex_index_map // defaults to get(vertex_index,aSurface) - , EdgeIndexMap const& aEdge_index_map // defaults to get(edge_index,aSurface) - , EdgeIsBorderMap const& aEdge_is_border_map // defaults to get(edge_is_border,aSurface) + , VertexIndexMap const& aVertex_index_map // defaults to get(vertex_index,aSurface) + , EdgeIndexMap const& aEdge_index_map // defaults to get(edge_index,aSurface) + , EdgeIsBorderMap const& aEdge_is_border_map // defaults to get(edge_is_border,aSurface) + , EdgeIsConstrainedMap const& aEdge_is_constrained_map // defaults to No_constrained_edge_map() // optional strategy policies - defaults to LindstomTurk - , GetCost const& aGet_cost - , GetPlacement const& aGet_placement + , GetCost const& aGet_cost + , GetPlacement const& aGet_placement - , Visitor aVisitor + , Visitor aVisitor ) { typedef EdgeCollapse< ECM @@ -59,6 +62,7 @@ int edge_collapse ( ECM& aSurface , VertexIndexMap , EdgeIndexMap , EdgeIsBorderMap + , EdgeIsConstrainedMap , GetCost , GetPlacement , Visitor @@ -70,6 +74,7 @@ int edge_collapse ( ECM& aSurface , aVertex_index_map , aEdge_index_map , aEdge_is_border_map + , aEdge_is_constrained_map , aGet_cost , aGet_placement , aVisitor @@ -110,10 +115,11 @@ int edge_collapse ( ECM& aSurface ,choose_const_pmap(get_param(aParams,boost::vertex_index),aSurface,boost::vertex_index) ,choose_const_pmap(get_param(aParams,boost::edge_index),aSurface,boost::edge_index) ,choose_const_pmap(get_param(aParams,edge_is_border),aSurface,edge_is_border) + ,choose_param (get_param(aParams,edge_is_constrained),No_constrained_edge_map()) ,choose_param (get_param(aParams,get_cost_policy), LindstromTurk_cost()) ,choose_param (get_param(aParams,get_placement_policy), LindstromTurk_placement()) ,choose_param (get_param(aParams,vis), Dummy_visitor()) - ) ; + ); } diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/halfedge_collapse_Polyhedron_3.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/halfedge_collapse_Polyhedron_3.h index 59ced4834db..e2b08a9c7ff 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/halfedge_collapse_Polyhedron_3.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/halfedge_collapse_Polyhedron_3.h @@ -28,93 +28,162 @@ namespace CGAL { namespace Surface_mesh_simplification { +/* +Function responsible for contracting an edge while respecting constrained edges + +Notations used in the following function: +Top=TopFace +Btm=BottomFace + + t + / \ + / \ + / Top \ + p -------- q + \ Btm / + \ / + \ / + b + +Prerequisites: +If Top exists, amongst p-t and t-q only one is constrained +If Btm exists, amongst p-b and q-b only one is constrained +p-q is not constrained +*/ +template +typename boost::graph_traits< Polyhedron_3 >::vertex_descriptor +halfedge_collapse( typename boost::graph_traits< Polyhedron_3 >::edge_descriptor const& pq + , Polyhedron_3& aSurface + , EdgeIsConstrainedMap Edge_is_constrained_map + ) +{ + CGAL_assertion( !get(Edge_is_constrained_map,pq) ); + typedef Polyhedron_3 Surface ; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor ; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor ; + + edge_descriptor qp = opposite_edge(pq,aSurface); + edge_descriptor pt = opposite_edge(prev_edge(pq,aSurface),aSurface); + edge_descriptor qb = opposite_edge(prev_edge(qp,aSurface),aSurface); + edge_descriptor tq = pq->next()->opposite(); + edge_descriptor bp = qp->next()->opposite(); + + bool lTopFaceExists = !pq->is_border() ; + bool lBottomFaceExists = !qp->is_border() ; + + CGAL_precondition( !lTopFaceExists || (lTopFaceExists && ( pt->vertex()->vertex_degree() > 2 ) ) ) ; + CGAL_precondition( !lBottomFaceExists || (lBottomFaceExists && ( qb->vertex()->vertex_degree() > 2 ) ) ) ; + + vertex_descriptor q = pq->vertex(); + vertex_descriptor p = pq->opposite()->vertex(); + + CGAL_ECMS_TRACE(3, "Collapsing p-q E" << pq->id() << " (V" << p->id() << "->V" << q->id() << ")" ) ; + + //used to collect edges to remove from the surface + edge_descriptor edges_to_erase[2]; + edge_descriptor* edges_to_erase_ptr=edges_to_erase; + + // If the top facet exists, we need to choose one out of the two edges which one disappears: + // p-t if it is not constrained and t-q otherwise + if ( lTopFaceExists ) + { + CGAL_precondition( !pt->opposite()->is_border() ) ; // p-q-t is a face of the mesh + if ( !get(Edge_is_constrained_map,pt) ) + { + CGAL_ECMS_TRACE(3, "Removing p-t E" << pt->id() << " (V" << p->id() << "->V" << pt->vertex()->id()) ; + *edges_to_erase_ptr++=pt; + } + else + { + CGAL_ECMS_TRACE(3, "Removing t-q E" << pt->id() << " (V" << pt->vertex()->id() << "->V" << q->id() ) ; + CGAL_assertion( !get(Edge_is_constrained_map,tq) ); + *edges_to_erase_ptr++=tq; + } + } + + // If the bottom facet exists, we need to choose one out of the two edges which one disappears: + // q-b if it is not constrained and b-p otherwise + if ( lBottomFaceExists ) + { + if ( !get(Edge_is_constrained_map,qb) ) + { + CGAL_ECMS_TRACE(3, "Removing q-b E" << qb->id() << " (V" << q->id() << "->V" << qb->vertex()->id() ) ; + *edges_to_erase_ptr++=qb; + } + else{ + CGAL_ECMS_TRACE(3, "Removing b-p E" << qb->id() << " (V" << qb->vertex()->id() << "->V" << p->id() ) ; + CGAL_assertion( !get(Edge_is_constrained_map,bp) ); + *edges_to_erase_ptr++=bp; + } + } + + if (lTopFaceExists && lBottomFaceExists) + { + if ( edges_to_erase[0]->facet()==edges_to_erase[1]->facet() + && !edges_to_erase[0]->is_border() ) + { + // the vertex is of valence 3 and we simply need to remove the vertex + // and its indicent edges + bool lP_Erased=false; + edge_descriptor edge = + edges_to_erase[0]->next()==edges_to_erase[1]? + edges_to_erase[0]:edges_to_erase[1]; + if (edge->vertex()==p) + lP_Erased=true; + aSurface.erase_center_vertex(edge); + return lP_Erased? q : p; + } + else + { + if (!edges_to_erase[0]->is_border()) + aSurface.join_facet(edges_to_erase[0]); + else + aSurface.erase_facet(edges_to_erase[0]->opposite()); + if (!edges_to_erase[1]->is_border()) + aSurface.join_facet(edges_to_erase[1]); + else + aSurface.erase_facet(edges_to_erase[1]->opposite()); + aSurface.join_vertex(pq); + return q; + } + } + else + { + if (lTopFaceExists) + { + if (!edges_to_erase[0]->is_border()){ + aSurface.join_facet(edges_to_erase[0]); + aSurface.join_vertex(pq); + return q; + } + bool lQ_Erased=pq->next()->opposite()->is_border(); + aSurface.erase_facet(edges_to_erase[0]->opposite()); + return lQ_Erased?p:q; + } + + CGAL_assertion(lBottomFaceExists); + if (!edges_to_erase[0]->is_border()){ + aSurface.join_facet(edges_to_erase[0]); + aSurface.join_vertex(qp); + return p; + } + bool lP_Erased=qp->next()->opposite()->is_border(); + aSurface.erase_facet(edges_to_erase[0]->opposite()); + return lP_Erased?q:p; + }; +} template typename boost::graph_traits< Polyhedron_3 >::vertex_descriptor halfedge_collapse( typename boost::graph_traits< Polyhedron_3 >::edge_descriptor const& pq , Polyhedron_3& aSurface - ) + ) { - typedef Polyhedron_3 Surface ; - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor ; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor ; - - edge_descriptor qp = opposite_edge(pq,aSurface); - edge_descriptor pt = opposite_edge(prev_edge(pq,aSurface),aSurface); - edge_descriptor qb = opposite_edge(prev_edge(qp,aSurface),aSurface); - - bool lTopFaceExists = !pq->is_border() ; - bool lBottomFaceExists = !qp->is_border() ; - bool lTopLeftFaceExists = lTopFaceExists && !pt->is_border() ; - bool lBottomRightFaceExists = lBottomFaceExists && !qb->is_border() ; - - CGAL_precondition( !lTopFaceExists || (lTopFaceExists && ( pt->vertex()->vertex_degree() > 2 ) ) ) ; - CGAL_precondition( !lBottomFaceExists || (lBottomFaceExists && ( qb->vertex()->vertex_degree() > 2 ) ) ) ; - - vertex_descriptor q = pq->vertex(); - vertex_descriptor p = pq->opposite()->vertex(); - - CGAL_ECMS_TRACE(3, "Collapsing p-q E" << pq->id() << " (V" << p->id() << "->V" << q->id() << ")" ) ; - - bool lP_Erased = false, lQ_Erased = false ; - - if ( lTopFaceExists ) - { - CGAL_precondition( !pt->opposite()->is_border() ) ; // p-q-t is a face of the mesh - if ( lTopLeftFaceExists ) - { - CGAL_ECMS_TRACE(3, "Removing p-t E" << pt->id() << " (V" << p->id() << "->V" << pt->vertex()->id() << ") by joining top-left face" ) ; - - aSurface.join_facet (pt); - } - else - { - CGAL_ECMS_TRACE(3, "Removing p-t E" << pt->id() << " (V" << p->id() << "->V" << pt->vertex()->id() << ") by erasing top face" ) ; - - aSurface.erase_facet(pt->opposite()); - - if ( !lBottomFaceExists ) - { - CGAL_ECMS_TRACE(3, "Bottom face doesn't exist so vertex P already removed" ) ; - lP_Erased = true ; - } - } - } - - if ( lBottomFaceExists ) - { - CGAL_precondition( !qb->opposite()->is_border() ) ; // p-q-b is a face of the mesh - if ( lBottomRightFaceExists ) - { - CGAL_ECMS_TRACE(3, "Removing q-b E" << qb->id() << " (V" << q->id() << "->V" << qb->vertex()->id() << ") by joining bottom-right face" ) ; - aSurface.join_facet (qb); - } - else - { - CGAL_ECMS_TRACE(3, "Removing q-b E" << qb->id() << " (V" << q->id() << "->V" << qb->vertex()->id() << ") by erasing bottom face" ) ; - - aSurface.erase_facet(qb->opposite()); - - if ( !lTopFaceExists ) - { - CGAL_ECMS_TRACE(3, "Top face doesn't exist so vertex Q already removed" ) ; - lQ_Erased = true ; - } - } - } - - CGAL_assertion( !lP_Erased || !lQ_Erased ) ; - - if ( !lP_Erased && !lQ_Erased ) - { - CGAL_ECMS_TRACE(3, "Removing vertex P by joining pQ" ) ; - aSurface.join_vertex(pq); - lP_Erased = true ; - } - - return lP_Erased ? q : p ; -} + return halfedge_collapse( pq, + aSurface, + No_constrained_edge_map >() ); +} } // namespace Surface_mesh_simplification @@ -124,4 +193,4 @@ halfedge_collapse( typename boost::graph_traits< Polyhedron_3 >::edg #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_COLLAPSE_TRIANGULATION_EDGE_POLYHEDRON_3_H // EOF // - + diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp index 57675d8d4dc..5d14391ea0d 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp @@ -36,23 +36,25 @@ int main( int argc, char** argv ) Surface surface; is >> surface ; - + std::size_t initial_count = (surface.size_of_halfedges()/2); + std::cout << "Initial count " << initial_count << " edges.\n" ; // Contract the surface as much as possible SMS::Count_stop_predicate stop(0); - + int r = SMS::edge_collapse (surface ,stop ,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface)) .edge_index_map (boost::get(CGAL::edge_external_index ,surface)) ); - + std::cout << "\nFinished...\n" << r << " edges removed.\n" << (surface.size_of_halfedges()/2) << " final edges.\n" ; - + + assert( initial_count == (surface.size_of_halfedges()/2) + r ); // std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ; - + return 0 ; }