mirror of https://github.com/CGAL/cgal
Edge_profile added
This commit is contained in:
parent
81f0f74829
commit
77348ee54d
|
|
@ -44,7 +44,7 @@ of edges drops below a certain ratio.
|
|||
|
||||
\ccMethod
|
||||
{bool operator()( FT const& current_cost
|
||||
, edge_descriptor const& edge
|
||||
, Profile const& edge_profile
|
||||
, size_type initial_count
|
||||
, size_type current_count
|
||||
) const ;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ It returns \ccc{true} when the number of current edges drops below a certain thr
|
|||
|
||||
\ccMethod
|
||||
{bool operator()( FT const& current_cost
|
||||
, edge_descriptor const& edge
|
||||
, Profile const& edge_profile
|
||||
, size_type initial_count
|
||||
, size_type current_count
|
||||
) const ;
|
||||
|
|
|
|||
|
|
@ -60,14 +60,11 @@ The several callbacks given as member functions in the visitor are called from c
|
|||
|
||||
\ccMethod
|
||||
{void OnCollected( edge_descriptor const& edge
|
||||
, bool is_fixed
|
||||
, ECM& surface
|
||||
);
|
||||
}
|
||||
{Called during the {\em collecting phase} (when a cost is assigned to the edges),
|
||||
for each \ccc{edge} collected.\\
|
||||
\ccc{is_fixed} indicates whether \ccc{edge} is fixed or not.
|
||||
If it is fixed it will not be collapsed.
|
||||
for each \ccc{edge} collected.
|
||||
}
|
||||
|
||||
\ccMethod
|
||||
|
|
|
|||
|
|
@ -39,16 +39,10 @@ It computes the collapse cost as the squared length of the edge.
|
|||
\ccConstructor{Edge_length_cost<ECM>();}{Default constructor}
|
||||
|
||||
\ccHeading{Methods}
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, Params const* params
|
||||
) const;
|
||||
}
|
||||
\ccMethod{result_type operator()( Profile const& profile, optional<Point> const& placement ) const; }
|
||||
{Returns the {\em collapse cost} as the squared distance between the points
|
||||
of the source and target vertices of \ccc{edge}. All arguments
|
||||
except \ccc{edge} and \ccc{surface} are ignored.
|
||||
of the source and target vertices (that is, \ccc{profile.p0()} and \ccc{profile.p1()}.\
|
||||
The \ccc{placement} argument is ignored.
|
||||
}
|
||||
|
||||
\end{ccRefClass}
|
||||
|
|
|
|||
|
|
@ -22,27 +22,25 @@
|
|||
\ccCreationVariable{gc} %% choose variable name
|
||||
\ccDefinition
|
||||
|
||||
The concept \ccRefName\ describes the requirements for the {\em policy function object} which gets the {\em collapse cost} of an edge.
|
||||
The concept \ccRefName\ describes the requirements for the {\em policy function object}
|
||||
which gets the {\em collapse cost} of an edge.
|
||||
|
||||
The cost returned is a \ccc{boost::optional} value (i.e. it can be absent). An {\em absent} cost could be the result of a computational limitation (such as overflow), or can be intentionally returned to prevent the edge from being collapsed.
|
||||
|
||||
A model of this concept can simply return the cost stored in the
|
||||
passed cache object, if any, or perform the actual computation.
|
||||
The cost returned is a \ccc{boost::optional} value (i.e. it can be absent).
|
||||
An {\em absent} cost indicates that the edge should not be collapsed.
|
||||
This could be the result of a computational limitation (such as overflow),
|
||||
or can be intentionally returned to prevent the edge from being collapsed.
|
||||
|
||||
\ccRefines
|
||||
\ccc{DefaultConstructible}\\
|
||||
\ccc{CopyConstructible}
|
||||
|
||||
\ccTypes
|
||||
\ccNestedType{ECM}{The type of the surface to simplify.
|
||||
Must be a model of the \ccc{EdgeCollapsableMesh} concept.}{}
|
||||
\ccGlue
|
||||
\ccNestedType{Params}{The type of the model-specific parameters needed. Can be \ccc{void}.}{}
|
||||
\ccNestedType{Profile}
|
||||
{The type of the edge profile cache. Must be a model of the \ccc{EdgeProfile} concept.}{}
|
||||
\ccGlue
|
||||
\ccNestedType{FT}{A field type representing the collapse cost}{}
|
||||
\ccGlue
|
||||
\ccTypedef{typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor;}
|
||||
{A {\sc Bgl} edge descriptor representing an edge of the surface.}
|
||||
\ccTypedef{typename CGAL::halfedge_graph_traits<ECM>::Point Point;}{The point type for the surface vertex.}
|
||||
\ccGlue
|
||||
\ccTypedef{boost::optional<FT> result_type;}{The type of the result (an optional cost value).}
|
||||
|
||||
|
|
@ -53,23 +51,12 @@ passed cache object, if any, or perform the actual computation.
|
|||
|
||||
\ccOperations
|
||||
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, Params const* params
|
||||
) const;
|
||||
}
|
||||
{Computes and returns the cost of collapsing \ccc{edge} using the model-specific \ccc{params}.\\
|
||||
\ccc{edge} is required to be in the \ccc{surface}.\\
|
||||
If \ccc{Cache} is a model of \ccc{CostCache} or \ccc{CostAndPlacementCache},
|
||||
which means that \ccc{cache} stores the cost, a model of this \ccc{GetCost} concept
|
||||
can simply return the cached cost (but is not required to do so).\\
|
||||
\ccc{params} can be a \ccStyle{NULL} pointer.
|
||||
\ccMethod{result_type operator()( Profile const& edge_profile, optional<Point> const& placement ) const;}
|
||||
{Computes and returns the cost of collapsing the edge (represented by its profile),
|
||||
using the calculated placement.\\
|
||||
}
|
||||
|
||||
\ccHasModels
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cached_cost<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Edge_length_cost<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_cost<ECM>}.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,31 +24,22 @@
|
|||
|
||||
The concept \ccRefName\ describes the requirements for the {\em policy
|
||||
function object} which gets the {\em collapse placement} of an edge,
|
||||
that is, the position of the vertex that replaces the edge after the
|
||||
collapse.
|
||||
that is, the new position of the vertex that remains after a
|
||||
halfedge-collapse.
|
||||
|
||||
The placement returned is a \ccc{boost::optional} value (i.e., it can
|
||||
be absent). An absent placement could be the result of a
|
||||
computational limitation (such as overflow), or can be intentionally
|
||||
returned to prevent the edge from being collapsed.
|
||||
|
||||
A model of this concept can simply return the placement stored in the
|
||||
passed cache object, if any, or perform the actual computation.
|
||||
be absent). An absent result indicates that the remainin vertex
|
||||
must be kept in place, not moved to a new position.
|
||||
|
||||
\ccRefines
|
||||
\ccc{DefaultConstructible}\\
|
||||
\ccc{CopyConstructible}
|
||||
|
||||
\ccTypes
|
||||
\ccNestedType{ECM}{The type of the surface to simplify.
|
||||
Must be a model of the \ccc{EdgeCollapsableMesh} concept.}{}
|
||||
\ccGlue
|
||||
\ccNestedType{Params}{The type of the model-specific parameters needed. Can be \ccc{void}.}{}
|
||||
\ccNestedType{Profile}
|
||||
{The type of the edge profile cache. Must be a model of the \ccc{EdgeProfile} concept.}{}
|
||||
\ccGlue
|
||||
\ccTypedef{typename CGAL::halfedge_graph_traits<ECM>::Point Point;}{The point type for the surface vertex.}
|
||||
\ccGlue
|
||||
\ccTypedef{typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor;}
|
||||
{A {\sc Bgl} edge descriptor representing an edge of the surface.}
|
||||
\ccGlue
|
||||
\ccTypedef{boost::optional<Point> result_type;}{The type of the result (an optional point).}
|
||||
|
||||
|
|
@ -59,26 +50,13 @@ passed cache object, if any, or perform the actual computation.
|
|||
|
||||
\ccOperations
|
||||
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, Params const* params
|
||||
) const;
|
||||
}
|
||||
\ccMethod{ result_type operator()( Profile const& edge_profile ) const; }
|
||||
{Computes and returns the placement, that is, the position of the vertex
|
||||
which replaces the collapsing \ccc{edge}, using the model-specific \ccc{params}.\\
|
||||
\ccc{edge} is required to be in the \ccc{surface}.\\
|
||||
If \ccc{Cache} is a model of \ccc{CostAndPlacementCache}, which means that
|
||||
\ccc{cache} stores the placement, a model can simply return that
|
||||
(but is not required to do so).\\
|
||||
\ccc{params} can be a \ccc{NULL} pointer.
|
||||
}
|
||||
which replaces the collapsing edge (represented by its profile). }
|
||||
|
||||
\ccHasModels
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cached_cost<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Edge_length_cost<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_cost<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Edge_length_placement<ECM>}.
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_placement<ECM>}.
|
||||
|
||||
\end{ccRefConcept}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,21 +37,15 @@ It must be a model of the \ccc{EdgeCollapsableMesh} concept.
|
|||
|
||||
\ccCreation
|
||||
\ccCreationVariable{gc} %% choose variable name
|
||||
\ccConstructor{LindstromTurk_cost<ECM>();}{Default constructor}
|
||||
\ccConstructor{LindstromTurk_cost<ECM>( LindstromTurk_params const& aParams );}
|
||||
{Initializes the policy with the given parameters}
|
||||
|
||||
\ccHeading{Methods}
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, LindstromTurk_Params const* params
|
||||
) const;
|
||||
}
|
||||
{Returns the cost of collapsing \ccc{edge}.}
|
||||
\ccMethod{result_type operator()( Profile const& profile, optional<Point> const& placement ) const;}
|
||||
{Returns the cost of collapsing the edge (represented by its profile) considering
|
||||
the new \ccc{placement} computed for it.}
|
||||
|
||||
\ccSeeAlso
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_cache<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_and_placement_cache<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_placement<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_params}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@ cost strategy (Section~\ref{SurfaceMeshSimplification:LindstromTurkStrategy})
|
|||
{Initializes an instance which stores the given weights.}
|
||||
|
||||
\ccSeeAlso
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_cache<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_and_placement_cache<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_cost<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_placement<ECM>}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
\ccDefinition
|
||||
|
||||
The class \ccRefName\ provides a model for the \ccc{GetPlacement} concept.
|
||||
It computes the collapse cost following the Lindstrom-Turk strategy
|
||||
It computes the placement, that is, the new position for the remaining vertex after
|
||||
a halfedge-collapse, following the Lindstrom-Turk strategy
|
||||
(Section~\ref{SurfaceMeshSimplification:LindstromTurkStrategy}).
|
||||
|
||||
The class \ccRefName\ has one template argument: the type of surface being simplified.
|
||||
|
|
@ -37,20 +38,15 @@ It must be a model of the \ccc{EdgeCollapsableMesh} concept.
|
|||
|
||||
\ccCreation
|
||||
\ccCreationVariable{gp} %% choose variable name
|
||||
\ccConstructor{LindstromTurk_placement<ECM>();}{Default constructor}
|
||||
\ccConstructor{LindstromTurk_placement<ECM>( LindstromTurk_params const& aParams );}
|
||||
{Initializes the policy with the given parameters}
|
||||
|
||||
\ccHeading{Methods}
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, LindstromTurk_params const* params
|
||||
) const;
|
||||
}
|
||||
{Returns the position of the vertex that replaces the collapsed \ccc{edge}.}
|
||||
\ccMethod{result_type operator()( Profile const& edge_profile ) const;}
|
||||
{Returns the new position for the remaining vertex after collapsing the edge
|
||||
(represented by its profile).}
|
||||
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_cache<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_and_placement_cache<ECM>}\\
|
||||
\ccSeeAlso
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_cost<ECM>}\\
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_params}\\
|
||||
\end{ccRefClass}
|
||||
|
|
|
|||
|
|
@ -40,17 +40,11 @@ It be a model of the \ccc{EdgeCollapsableMesh} concept.
|
|||
\ccConstructor{Midpoint_placement<ECM>();}{Default constructor}
|
||||
|
||||
\ccHeading{Methods}
|
||||
\ccMethod{template<class Cache>
|
||||
result_type operator()( edge_descriptor const& edge
|
||||
, ECM& surface
|
||||
, Cache const& cache
|
||||
, Params const* params
|
||||
) const;
|
||||
\ccMethod{result_type operator()( Profile const& edge_profile ) const;
|
||||
}
|
||||
{Returns the {\em placement} (vertex position) as the midpoint between
|
||||
the points of the source and target vertices of \ccc{edge}. All arguments
|
||||
except \ccc{edge} and \ccc{surface} are ignored.
|
||||
}
|
||||
the points of the source and target vertices
|
||||
(that is, \ccc{profile.p0()} and \ccc{profile.p1()})}
|
||||
|
||||
\end{ccRefClass}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ The concept \ccRefName\ describes the requirements for the predicate which indic
|
|||
\ccGlue
|
||||
\ccNestedType{size_type}{An integer type representing the number of edges}{}
|
||||
\ccGlue
|
||||
\ccTypedef{typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor;}
|
||||
{A {\sc Bgl} edge descriptor representing an edge of the surface.}
|
||||
\ccNestedType{Profile}
|
||||
{The type of the edge profile cache. Must be a model of the \ccc{EdgeProfile} concept.}{}
|
||||
|
||||
\ccCreation
|
||||
\ccCreationVariable{should_stop} %% choose variable name
|
||||
|
|
@ -40,19 +40,19 @@ The concept \ccRefName\ describes the requirements for the predicate which indic
|
|||
\ccOperations
|
||||
|
||||
\ccMethod
|
||||
{bool operator()( FT current_cost
|
||||
, edge_descriptor edge
|
||||
{bool operator()( FT const& current_cost
|
||||
, Profile const& profile
|
||||
, size_type initial_count
|
||||
, size_type current_count
|
||||
) const ;
|
||||
}
|
||||
{
|
||||
This predicate is called each time an \ccc{edge} is selected for processing,
|
||||
This predicate is called each time an edge is selected for processing,
|
||||
before it is collapsed.\\
|
||||
\ccc{current_cost} is the cost of the selected edge.\\
|
||||
\ccc{initial_count} and \ccc{current_count} is the number of initial and current edges.\\
|
||||
\\
|
||||
If the return value is \ccc{true} the simplification terminates before processing \ccc{edge},
|
||||
If the return value is \ccc{true} the simplification terminates before processing the edge,
|
||||
otherwise it continues normally.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,43 +64,43 @@ All named parameters have default values and the order of the named parameters
|
|||
is irrelevant so you only need to compose those for which the default
|
||||
is inappropriate.
|
||||
|
||||
\subsubsection*{vertex\_point\_map(VertexPointMap vpm)}
|
||||
\subsubsection*{vertex\_index\_map(VertexIndexMap vpm)}
|
||||
|
||||
Provides lvalue access to the point of a vertex of the surface.
|
||||
\ccc{VertexPointMap} must be an
|
||||
\ccAnchor{http://www.boost.org/libs/property_map/LvaluePropertyMap.html}{LValuePropertyMap}
|
||||
Maps each vertex in the surface into an unsigned integer number
|
||||
in the range \ccc{[0,num_vertices(surface))}.
|
||||
|
||||
\ccc{VertexIndexMap} must be a
|
||||
\ccAnchor{http://www.boost.org/libs/property_map/ReadablePropertyMap.html}{ReadablePropertyMap}
|
||||
whose \ccc{key_type} is
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh>::vertex_descriptor}
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh const>::vertex_descriptor}
|
||||
and whose \ccc{value_type} is
|
||||
\ccc{boost::halfedge_graph_traits<EdgeCollapsableMesh>::Point}
|
||||
|
||||
\textbf{Default}: the property map obtained by calling \ccc{get(vertex_point,surface)}.
|
||||
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh>::size_type},
|
||||
|
||||
\textbf{Default}: the property map obtained by calling \ccc{get(vertex_index,surface)},
|
||||
which requires the surface vertices to have an \ccc{id()} member properly initialized to the
|
||||
required value.\\
|
||||
If the verices don't have such id(), you must pass a map explicitely, such as
|
||||
the property map obtained by calling \ccc{get(vertex_external_index,surface)},
|
||||
which constructs an internal map which non-intrusively associates a proper id with each vertex.
|
||||
|
||||
\subsubsection*{edge\_index\_map(EdgeIndexMap eim)}
|
||||
|
||||
Maps each {\em directed} edge in the surface into an integer number
|
||||
Maps each {\em directed} edge in the surface into an unsigned integer number
|
||||
in the range \ccc{[0,num_edges(surface))}.
|
||||
|
||||
\ccc{EdgeIndexMap} must be a either a
|
||||
\ccc{EdgeIndexMap} must be a
|
||||
\ccAnchor{http://www.boost.org/libs/property_map/ReadablePropertyMap.html}{ReadablePropertyMap}
|
||||
whose \ccc{key_type} is
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh const>::edge_descriptor}
|
||||
and whose \ccc{value_type} is
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh>::size_type},
|
||||
or the same as \ccc{EdgeCollapsableMesh}, in which case
|
||||
\ccc{eim} is in fact the surface to be simplified.
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh>::size_type}
|
||||
|
||||
If \ccc{eim} is a valid property map, it is
|
||||
passed as the argument, but if it is the surface, a
|
||||
temporary property map is passed instead.
|
||||
Such temporary map externally relates each edge
|
||||
in the surface (\ccc{eim}) to its index,
|
||||
without requiring any user intervention or any special
|
||||
provision in the surface edge.
|
||||
|
||||
\textbf{Default}: the property map obtained by calling \ccc{get(edge_index,surface)}.
|
||||
\textbf{Default}: the property map obtained by calling \ccc{get(edge_index,surface)},
|
||||
which requires the surface edges to have an \ccc{id()} member properly initialized to the
|
||||
require value.\\
|
||||
If the edges don't have such id(), you must pass a map explicitely, such as
|
||||
the property map obtained by calling \ccc{get(edge_external_index,surface)},
|
||||
which constructs an internal map which non-intrusively associates a proper id with each edge.
|
||||
|
||||
\subsubsection*{edge\_is\_border\_map(EdgeIsBorderMap ebm)}
|
||||
|
||||
|
|
@ -115,49 +115,13 @@ and whose \ccc{value_type} is \ccc{bool}.
|
|||
|
||||
\textbf{Default}: the property map obtained by calling \ccc{get(edge_is_border,surface)}.
|
||||
|
||||
|
||||
\subsubsection*{vertex\_is\_fixed\_map(VertexIsFixedMap vfm)}
|
||||
|
||||
|
||||
Maps each vertex in the surface into a boolean value
|
||||
which indicates if the vertex is fixed and cannot be modified
|
||||
by the \ccc{edge_collapse} function.\\
|
||||
\ccc{VertexIsFixedMap} must be a
|
||||
\ccAnchor{http://www.boost.org/libs/property_map/ReadablePropertyMap.html}{ReadablePropertyMap}
|
||||
whose \ccc{key_type} is
|
||||
\ccc{boost::graph_traits<EdgeCollapsableMesh const>::vertex_descriptor}
|
||||
and whose \ccc{value_type} is \ccc{bool}.
|
||||
|
||||
\textbf{Default}:
|
||||
\ccc{Vertex_is_fixed_property_map_always_false<EdgeCollapsableMesh>()}.
|
||||
|
||||
|
||||
\subsubsection*{set\_cache(SetCache sc)}
|
||||
|
||||
The policy which indicates the caching level used
|
||||
by the \ccc{edge_collapse} function.\\
|
||||
The type of \ccc{sc} must be a model of the \ccc{SetCache} concept.
|
||||
|
||||
\textbf{Default}:
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_cache<EdgeCollapsableMesh>()}
|
||||
|
||||
|
||||
\subsubsection*{get\_cost(GetCost gc)}
|
||||
|
||||
|
||||
The policy which returns the collapse cost for an edge.\\
|
||||
The type of \ccc{gc} must be a model of the \ccc{GetCost} concept.
|
||||
|
||||
\textbf{Default}:
|
||||
\ccc{CGAL::Surface_mesh_simplification::Cached_cost<EdgeCollapsableMesh>}.
|
||||
|
||||
|
||||
\subsubsection*{get\_cost\_params(GetCost::Params const* gp)}
|
||||
|
||||
The model-specific parameters to \ccc{get_cost}.
|
||||
|
||||
\textbf{Default}: \ccc{NULL}.
|
||||
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_cost<EdgeCollapsableMesh>}.
|
||||
|
||||
\subsubsection*{get\_placement(GetPlacement gp)}
|
||||
|
||||
|
|
@ -168,16 +132,6 @@ The type of \ccc{gp} must be a model of the \ccc{GetPlacement} concept.
|
|||
\textbf{Default}:
|
||||
\ccc{CGAL::Surface_mesh_simplification::LindstromTurk_placement<EdgeCollapsableMesh>}
|
||||
|
||||
|
||||
|
||||
\subsubsection*{get\_placement\_params(GetPlacement::Params const* gpp)}
|
||||
|
||||
The model-specific parameters to \ccc{get_placement}.
|
||||
|
||||
\textbf{Default}: A pointer to a local default constructed instance of \ccc{CGAL::LindstromTurk_params}.
|
||||
|
||||
|
||||
|
||||
\subsubsection*{visitor(EdgeCollapseSimplificationVisitor const* v)}
|
||||
|
||||
The visitor that is called by the \ccc{edge_collapse} function
|
||||
|
|
@ -197,16 +151,9 @@ examples in the user manual.
|
|||
The simplification process continues until the \ccc{should_stop} policy returns \ccc{true}
|
||||
or the surface cannot be simplified any further due to topological constraints.
|
||||
|
||||
\ccc{vertex_is_fixed_map} is used to indicate that some edges should not be
|
||||
collapsed: edges incident upon fixed vertices are not collapsed.
|
||||
|
||||
\ccc{set_cache}, along with \ccc{get_cost} and \ccc{get_placement},
|
||||
are the policies which control the {\em cost-strategy}, that is,
|
||||
the order in which edges are collapsed and the replacement vertex is positioned.\\
|
||||
\ccc{get_cost_params} and \ccc{get_placement_params} are the runtime
|
||||
parameters used by the these policies. They can be null pointers
|
||||
if the policies do not need them. This strategy is the driving factor that determines the accuracy of the
|
||||
simplified surface with respect to the original.
|
||||
\ccc{get_cost} and \ccc{get_placement} are the policies which control
|
||||
the {\em cost-strategy}, that is, the order in which edges are collapsed
|
||||
and the remaining vertex is re-positioned.
|
||||
|
||||
\ccc{visitor} is an optional object (can be null) which can be used
|
||||
to keep track of the simplification process.
|
||||
|
|
|
|||
|
|
@ -26,42 +26,26 @@ by iterative edge-collapsing.
|
|||
|
||||
\ccHeading{Concepts}
|
||||
\ccRefConceptPage{EdgeCollapsableMesh} \\
|
||||
\ccRefConceptPage{EdgeProfile} \\
|
||||
\ccRefConceptPage{StopPredicate} \\
|
||||
\ccRefConceptPage{NoCache} \\
|
||||
\ccRefConceptPage{CostCache} \\
|
||||
\ccRefConceptPage{CostAndPlacementCache} \\
|
||||
\ccRefConceptPage{SetCache} \\
|
||||
\ccRefConceptPage{GetCost} \\
|
||||
\ccRefConceptPage{GetPlacement} \\
|
||||
\ccRefConceptPage{EdgeCollapseSimplificationVisitor}
|
||||
|
||||
|
||||
\ccHeading{Functions}
|
||||
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::edge_collapse}\\
|
||||
|
||||
|
||||
\ccHeading{Classes}
|
||||
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Edge_profile<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Count_stop_predicate<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Count_ratio_stop_predicate<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::No_cache}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cost_cache<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cost_and_placement_cache<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Set_no_cache}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Set_cost_cache<ECM,GetCost>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Set_cost_and_placement_cache<ECM,GetCost,GetPlacement>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cached_cost<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Cached_placement<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Edge_length_cost<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::Midpoint_placement<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_cache<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_set_cost_and_placement_cache<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_cost<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_placement<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Surface_mesh_simplification::LindstromTurk_params}\\
|
||||
\ccRefIdfierPage{CGAL::Vertex_is_fixed_property_map_always_false<ECM>}\\
|
||||
\ccRefIdfierPage{CGAL::Vertex_is_fixed_property_map_stored<ECM>}\\
|
||||
|
||||
% +------------------------------------------------------------------------+
|
||||
%%RefPage: end of main body, begin of footer
|
||||
|
|
|
|||
|
|
@ -35,9 +35,13 @@ int main( int argc, char** argv )
|
|||
|
||||
// This the actual call to the simplification algorithm.
|
||||
// The surface and stop conditions are mandatory arguments.
|
||||
// The third argument is needed because the edges on this
|
||||
// surface lack an "id()" field.
|
||||
int r = SMS::edge_collapse(surface, stop, CGAL::edge_index_map(boost::get(CGAL::edge_external_index,surface)) );
|
||||
// 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))
|
||||
,CGAL::edge_index_map (boost::get(CGAL::edge_external_index ,surface))
|
||||
);
|
||||
|
||||
// === CONCRETE USAGE EXAMPLE ENDS HERE ===
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ using boost::addressof ;
|
|||
|
||||
using namespace boost::tuples ;
|
||||
|
||||
|
||||
template<class Handle>
|
||||
inline bool handle_assigned( Handle h ) { Handle null ; return h != null ; }
|
||||
|
||||
|
|
@ -74,31 +73,6 @@ bool handle_exists ( Iterator begin, Iterator end, Handle h )
|
|||
return false ;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U> struct ChooseNotVoidType ;
|
||||
template<class T> struct ChooseNotVoidType<T ,void> { typedef T type ; } ;
|
||||
template<class U> struct ChooseNotVoidType<void,U > { typedef U type ; } ;
|
||||
template<> struct ChooseNotVoidType<void,void> { typedef void type ; } ;
|
||||
|
||||
template<class GetCost, class SetCache>
|
||||
struct ExtractCostParamsType
|
||||
{
|
||||
typedef typename ChooseNotVoidType< typename GetCost ::Params
|
||||
, typename SetCache::CostParams
|
||||
>
|
||||
::type type ;
|
||||
} ;
|
||||
|
||||
template<class GetPlacement, class SetCache>
|
||||
struct ExtractPlacementParamsType
|
||||
{
|
||||
typedef typename ChooseNotVoidType< typename GetPlacement::Params
|
||||
, typename SetCache ::PlacementParams
|
||||
>
|
||||
::type type ;
|
||||
} ;
|
||||
|
||||
|
||||
} // namespace Surface_mesh_simplification
|
||||
|
||||
template<class XYZ>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <boost/graph/adjacency_list.hpp>
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -39,13 +40,11 @@ namespace Surface_mesh_simplification
|
|||
//
|
||||
template<class ECM_
|
||||
,class ShouldStop_
|
||||
,class VertexPointMap_
|
||||
,class VertexIndexMap_
|
||||
,class EdgeIndexMap_
|
||||
,class EdgeIsBorderMap_
|
||||
,class GetCost_
|
||||
,class GetPlacement_
|
||||
,class CostParams_
|
||||
,class PlacementParams_
|
||||
,class VisitorT_
|
||||
>
|
||||
class EdgeCollapse
|
||||
|
|
@ -54,17 +53,17 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
typedef ShouldStop_ ShouldStop ;
|
||||
typedef VertexPointMap_ VertexPointMap ;
|
||||
typedef VertexIndexMap_ VertexIndexMap ;
|
||||
typedef EdgeIndexMap_ EdgeIndexMap ;
|
||||
typedef EdgeIsBorderMap_ EdgeIsBorderMap ;
|
||||
typedef GetCost_ GetCost ;
|
||||
typedef GetPlacement_ GetPlacement ;
|
||||
typedef CostParams_ CostParams ;
|
||||
typedef PlacementParams_ PlacementParams ;
|
||||
typedef VisitorT_ VisitorT ;
|
||||
|
||||
typedef EdgeCollapse Self ;
|
||||
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef boost::graph_traits <ECM> GraphTraits ;
|
||||
typedef boost::graph_traits <ECM const> ConstGraphTraits ;
|
||||
typedef halfedge_graph_traits<ECM> HalfedgeGraphTraits ;
|
||||
|
|
@ -117,7 +116,7 @@ public:
|
|||
// NOTE: A cost is an optional<> value.
|
||||
// Absent optionals are ordered first; that is, "none < T" and "T > none" for any defined T != none.
|
||||
// In consequence, edges with undefined costs will be promoted to the top of the priority queue and poped out first.
|
||||
return mAlgorithm->get_cost(a) < mAlgorithm->get_cost(b);
|
||||
return mAlgorithm->get_data(a).cost() < mAlgorithm->get_data(b).cost();
|
||||
}
|
||||
|
||||
Self const* mAlgorithm ;
|
||||
|
|
@ -176,13 +175,11 @@ public:
|
|||
|
||||
EdgeCollapse( ECM& aSurface
|
||||
, ShouldStop const& aShouldStop
|
||||
, VertexPointMap const& aVertex_point_map
|
||||
, VertexIndexMap const& aVertex_index_map
|
||||
, EdgeIndexMap const& aEdge_index_map
|
||||
, EdgeIsBorderMap const& aEdge_is_border_map
|
||||
, GetCost const& aGetCost
|
||||
, GetPlacement const& aGetPlacement
|
||||
, CostParams const* aCostParams // Can be NULL
|
||||
, PlacementParams const* aPlacementParams // Can be NULL
|
||||
, VisitorT* aVisitor // Can be NULL
|
||||
) ;
|
||||
|
||||
|
|
@ -192,12 +189,17 @@ private:
|
|||
|
||||
void Collect();
|
||||
void Loop();
|
||||
bool Is_collapsable( edge_descriptor const& aEdge ) ;
|
||||
bool Is_collapsable( Profile const& aProfile ) ;
|
||||
bool Is_tetrahedron( edge_descriptor const& h1 ) ;
|
||||
bool Is_open_triangle( edge_descriptor const& h1 ) ;
|
||||
void Collapse( edge_descriptor const& aEdge ) ;
|
||||
void Collapse( Profile const& aProfile ) ;
|
||||
void Update_neighbors( vertex_descriptor const& aKeptV ) ;
|
||||
|
||||
Profile create_profile ( edge_descriptor const& aEdge )
|
||||
{
|
||||
return Profile(aEdge,mSurface,Vertex_index_map,Edge_index_map,Edge_is_border_map);
|
||||
}
|
||||
|
||||
size_type get_directed_edge_id ( const_edge_descriptor const& aEdge ) const { return Edge_index_map[aEdge]; }
|
||||
size_type get_undirected_edge_id ( const_edge_descriptor const& aEdge ) const { return get_directed_edge_id(aEdge) / 2 ; }
|
||||
|
||||
|
|
@ -223,7 +225,10 @@ private:
|
|||
return mEdgeDataArray[get_undirected_edge_id(aEdge)];
|
||||
}
|
||||
|
||||
Point get_point ( const_vertex_descriptor const aV ) const { return get(Vertex_point_map,aV); }
|
||||
Point const& get_point ( const_vertex_descriptor const& aV ) const
|
||||
{
|
||||
return get(vertex_point,mSurface,aV);
|
||||
}
|
||||
|
||||
tuple<const_vertex_descriptor,const_vertex_descriptor> get_vertices( const_edge_descriptor const& aEdge ) const
|
||||
{
|
||||
|
|
@ -253,14 +258,14 @@ private:
|
|||
return boost::str( boost::format("{E%1% %2%->%3%}") % aEdge->ID % vertex_to_string(p) % vertex_to_string(q) ) ;
|
||||
}
|
||||
|
||||
Cost_type get_cost ( edge_descriptor const& aEdge ) const
|
||||
Cost_type get_cost ( Profile const& aProfile ) const
|
||||
{
|
||||
return Get_cost(aEdge,mSurface,mCostParams, get_placement(aEdge) );
|
||||
return Get_cost(aProfile, get_placement(aProfile) );
|
||||
}
|
||||
|
||||
Placement_type get_placement( edge_descriptor const& aEdge ) const
|
||||
Placement_type get_placement( Profile const& aProfile ) const
|
||||
{
|
||||
return Get_placement(aEdge,mSurface,mPlacementParams);
|
||||
return Get_placement(aProfile);
|
||||
}
|
||||
|
||||
void insert_in_PQ( edge_descriptor const& aEdge, Edge_data& aData )
|
||||
|
|
@ -299,13 +304,11 @@ private:
|
|||
|
||||
ECM& mSurface ;
|
||||
ShouldStop const& Should_stop ;
|
||||
VertexPointMap const& Vertex_point_map ;
|
||||
VertexIndexMap const& Vertex_index_map ;
|
||||
EdgeIndexMap const& Edge_index_map ;
|
||||
EdgeIsBorderMap const& Edge_is_border_map ;
|
||||
GetCost const& Get_cost ;
|
||||
GetPlacement const& Get_placement ;
|
||||
CostParams const* mCostParams ; // Can be NULL
|
||||
PlacementParams const* mPlacementParams ; // Can be NULL
|
||||
VisitorT* Visitor ; // Can be NULL
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -23,28 +23,24 @@ CGAL_BEGIN_NAMESPACE
|
|||
namespace Surface_mesh_simplification
|
||||
{
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::EdgeCollapse( ECM& aSurface
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::EdgeCollapse( ECM& aSurface
|
||||
, ShouldStop const& aShould_stop
|
||||
, VertexPointMap const& aVertex_point_map
|
||||
, VertexIndexMap const& aVertex_index_map
|
||||
, EdgeIndexMap const& aEdge_index_map
|
||||
, EdgeIsBorderMap const& aEdge_is_border_map
|
||||
, GetCost const& aGet_cost
|
||||
, GetPlacement const& aGet_placement
|
||||
, CostParams const* aCostParams
|
||||
, PlacementParams const* aPlacementParams
|
||||
, VisitorT* aVisitor
|
||||
)
|
||||
:
|
||||
mSurface (aSurface)
|
||||
,Should_stop (aShould_stop)
|
||||
,Vertex_point_map (aVertex_point_map)
|
||||
,Vertex_index_map (aVertex_index_map)
|
||||
,Edge_index_map (aEdge_index_map)
|
||||
,Edge_is_border_map (aEdge_is_border_map)
|
||||
,Get_cost (aGet_cost)
|
||||
,Get_placement (aGet_placement)
|
||||
,mCostParams (aCostParams)
|
||||
,mPlacementParams (aPlacementParams)
|
||||
,Visitor (aVisitor)
|
||||
|
||||
{
|
||||
|
|
@ -63,8 +59,8 @@ EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::EdgeCollapse( ECM&
|
|||
#endif
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
int EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::run()
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
int EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::run()
|
||||
{
|
||||
if ( Visitor )
|
||||
Visitor->OnStarted(mSurface);
|
||||
|
|
@ -85,8 +81,8 @@ int EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::run()
|
|||
return r ;
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collect()
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Collect()
|
||||
{
|
||||
CGAL_ECMS_TRACE(0,"Collecting edges...");
|
||||
|
||||
|
|
@ -114,15 +110,12 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collect()
|
|||
CGAL_assertion( get_directed_edge_id(lEdge) == id ) ;
|
||||
CGAL_assertion( get_directed_edge_id(opposite_edge(lEdge,mSurface)) == id+1 ) ;
|
||||
|
||||
vertex_descriptor p,q ;
|
||||
tie(p,q) = get_vertices(lEdge);
|
||||
Profile const& lProfile = create_profile(lEdge);
|
||||
|
||||
CGAL_assertion(p!=q);
|
||||
|
||||
if ( !equal_points( get_point(p), get_point(q) ) )
|
||||
if ( !equal_points(lProfile.p0(),lProfile.p1()) )
|
||||
{
|
||||
Edge_data& lData = get_data(lEdge);
|
||||
lData.cost() = get_cost(lEdge) ;
|
||||
lData.cost() = get_cost(lProfile) ;
|
||||
insert_in_PQ(lEdge,lData);
|
||||
}
|
||||
|
||||
|
|
@ -137,8 +130,8 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collect()
|
|||
CGAL_ECMS_TRACE(0,"Initial edge count: " << mInitialEdgeCount ) ;
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Loop()
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Loop()
|
||||
{
|
||||
CGAL_ECMS_TRACE(0,"Collapsing edges...") ;
|
||||
|
||||
|
|
@ -157,7 +150,9 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Loop()
|
|||
|
||||
if ( lCost )
|
||||
{
|
||||
if ( Should_stop(*lCost,*lEdge,mInitialEdgeCount,mCurrentEdgeCount) )
|
||||
Profile const& lProfile = create_profile(*lEdge);
|
||||
|
||||
if ( Should_stop(*lCost,lProfile,mInitialEdgeCount,mCurrentEdgeCount) )
|
||||
{
|
||||
if ( Visitor )
|
||||
Visitor->OnStopConditionReached(mSurface);
|
||||
|
|
@ -169,9 +164,9 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Loop()
|
|||
break ;
|
||||
}
|
||||
|
||||
if ( Is_collapsable(*lEdge) )
|
||||
if ( Is_collapsable(lProfile) )
|
||||
{
|
||||
Collapse(*lEdge);
|
||||
Collapse(lProfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -189,8 +184,8 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Loop()
|
|||
}
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::is_border( const_vertex_descriptor const& aV ) const
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::is_border( const_vertex_descriptor const& aV ) const
|
||||
{
|
||||
bool rR = false ;
|
||||
|
||||
|
|
@ -216,41 +211,34 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::is_border( const_vertex_descr
|
|||
//
|
||||
// The link conidition is as follows: for every vertex 'k' adjacent to both 'p and 'q', "p,k,q" is a facet of the mesh.
|
||||
//
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descriptor const& aEdgePQ )
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Is_collapsable( Profile const& aProfile )
|
||||
{
|
||||
bool rR = true ;
|
||||
|
||||
vertex_descriptor p,q ; tie(p,q) = get_vertices(aEdgePQ);
|
||||
|
||||
CGAL_ECMS_TRACE(3,"Testing collapsabilty of p_q=V" << p->ID << "(%" << p->vertex_degree() << ")"
|
||||
<< "->V" << q->ID << "(%" << q->vertex_degree() << ")"
|
||||
CGAL_ECMS_TRACE(3,"Testing collapsabilty of p_q=V" << aProfile.v0()->id() << "(%" << aProfile.v0()->vertex_degree() << ")"
|
||||
<< "->V" << aProfile.v1()->id() << "(%" << aProfile.v1()->vertex_degree() << ")"
|
||||
);
|
||||
|
||||
CGAL_ECMS_TRACE(4, "is p_q border:" << is_border(aEdgePQ) );
|
||||
CGAL_ECMS_TRACE(4, "is q_q border:" << is_border(opposite_edge(aEdgePQ,mSurface)) ) ;
|
||||
CGAL_ECMS_TRACE(4, "is p_q border:" << aProfile.is_v0v1_a_border() );
|
||||
CGAL_ECMS_TRACE(4, "is q_q border:" << aProfile.is_v1v0_a_border() );
|
||||
|
||||
bool lIsBoundary = is_undirected_edge_a_border(aEdgePQ) ;
|
||||
bool lIsBoundary = aProfile.is_v0v1_a_border() || aProfile.is_v1v0_a_border() ;
|
||||
|
||||
out_edge_iterator eb1, ee1 ;
|
||||
out_edge_iterator eb2, ee2 ;
|
||||
|
||||
edge_descriptor lEdgeQP = opposite_edge(aEdgePQ,mSurface);
|
||||
CGAL_ECMS_TRACE(4," t=V" << aProfile.vt()->ID << "(%" << aProfile.vt()->vertex_degree() << ")" );
|
||||
CGAL_ECMS_TRACE(4," b=V" << aProfile.vb()->ID << "(%" << aProfile.vb()->vertex_degree() << ")" );
|
||||
|
||||
vertex_descriptor t = target(next_edge(aEdgePQ,mSurface),mSurface);
|
||||
vertex_descriptor b = target(next_edge(lEdgeQP,mSurface),mSurface);
|
||||
|
||||
CGAL_ECMS_TRACE(4," t=V" << t->ID << "(%" << t->vertex_degree() << ")" );
|
||||
CGAL_ECMS_TRACE(4," b=V" << b->ID << "(%" << b->vertex_degree() << ")" );
|
||||
|
||||
// The following loop checks the link condition for aEdgePQ.
|
||||
// The following loop checks the link condition for aProfile.v0v1().
|
||||
// Specifically, that every vertex 'k' adjacent to both 'p and 'q' is a face of the mesh.
|
||||
//
|
||||
for ( tie(eb1,ee1) = out_edges(p,mSurface) ; rR && eb1 != ee1 ; ++ eb1 )
|
||||
for ( tie(eb1,ee1) = out_edges(aProfile.v0(),mSurface) ; rR && eb1 != ee1 ; ++ eb1 )
|
||||
{
|
||||
edge_descriptor p_k = *eb1 ;
|
||||
|
||||
if ( p_k != aEdgePQ )
|
||||
if ( p_k != aProfile.v0v1() )
|
||||
{
|
||||
vertex_descriptor k = target(p_k,mSurface);
|
||||
|
||||
|
|
@ -258,7 +246,7 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descript
|
|||
{
|
||||
edge_descriptor k_l = *eb2 ;
|
||||
|
||||
if ( target(k_l,mSurface) == q )
|
||||
if ( target(k_l,mSurface) == aProfile.v1() )
|
||||
{
|
||||
// At this point we know p-q-k are connected and we need to determine if this triangle is a face of the mesh.
|
||||
//
|
||||
|
|
@ -271,18 +259,18 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descript
|
|||
// or k==b but q->b is a border (because in that case even though there exists triangles p->q->t (or q->p->b)
|
||||
// they are holes, not faces)
|
||||
//
|
||||
bool lIsFace = ( t == k && !is_border(aEdgePQ) )
|
||||
|| ( b == k && !is_border(lEdgeQP) ) ;
|
||||
bool lIsFace = ( aProfile.vl() == k && aProfile.left_face_exists () )
|
||||
|| ( aProfile.vr() == k && aProfile.right_face_exists() ) ;
|
||||
|
||||
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" << k->id() << " 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" << k->id() << " is in a face with p-q") ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -293,7 +281,7 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descript
|
|||
{
|
||||
if ( lIsBoundary )
|
||||
{
|
||||
if ( Is_open_triangle(aEdgePQ) )
|
||||
if ( Is_open_triangle(aProfile.v0v1()) )
|
||||
{
|
||||
rR = false ;
|
||||
CGAL_ECMS_TRACE(3," p-q belongs to an open triangle. NON-COLLAPSABLE edge." ) ;
|
||||
|
|
@ -301,12 +289,12 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descript
|
|||
}
|
||||
else
|
||||
{
|
||||
if ( is_border(p) && is_border(q) )
|
||||
if ( is_border(aProfile.v0()) && is_border(aProfile.v1()) )
|
||||
{
|
||||
rR = false ;
|
||||
CGAL_ECMS_TRACE(3," both p and q are boundary vertices but p-q is not. NON-COLLAPSABLE edge." ) ;
|
||||
}
|
||||
else if ( Is_tetrahedron(aEdgePQ) )
|
||||
else if ( Is_tetrahedron(aProfile.v0v1()) )
|
||||
{
|
||||
rR = false ;
|
||||
CGAL_ECMS_TRACE(3," p-q belongs to a tetrahedron. NON-COLLAPSABLE edge." ) ;
|
||||
|
|
@ -317,8 +305,8 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_collapsable( edge_descript
|
|||
return rR ;
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_tetrahedron( edge_descriptor const& h1 )
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Is_tetrahedron( edge_descriptor const& h1 )
|
||||
{
|
||||
//
|
||||
// Code copied from Polyhedron_3::is_tetrahedron()
|
||||
|
|
@ -369,8 +357,8 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_tetrahedron( edge_descript
|
|||
return true;
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_open_triangle( edge_descriptor const& h1 )
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Is_open_triangle( edge_descriptor const& h1 )
|
||||
{
|
||||
edge_descriptor h2 = next_edge(h1,mSurface);
|
||||
edge_descriptor h3 = next_edge(h2,mSurface);
|
||||
|
|
@ -379,87 +367,60 @@ bool EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Is_open_triangle( edge_descri
|
|||
}
|
||||
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collapse( edge_descriptor const& aEdgePQ )
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Collapse( Profile const& aProfile )
|
||||
{
|
||||
CGAL_ECMS_TRACE(1,"S" << mStep << ". Collapsig " << edge_to_string(aEdgePQ) ) ;
|
||||
|
||||
vertex_descriptor lP, lQ ; tie(lP,lQ) = get_vertices(aEdgePQ);
|
||||
|
||||
CGAL_assertion( lP != lQ );
|
||||
CGAL_ECMS_TRACE(1,"S" << mStep << ". Collapsig " << edge_to_string(aProfile.v0v1()) ) ;
|
||||
|
||||
vertex_descriptor rResult ;
|
||||
|
||||
// The external function Get_new_vertex_point() is allowed to return an absent point if there is no way to place the vertex
|
||||
// satisfying its constrians. In that case the vertex-pair is simply not removed.
|
||||
Placement_type lPlacement = get_placement(aEdgePQ);
|
||||
Placement_type lPlacement = get_placement(aProfile);
|
||||
|
||||
if ( Visitor )
|
||||
Visitor->OnCollapsing(aEdgePQ,mSurface,lPlacement);
|
||||
|
||||
CGAL_ECMS_TRACE(2,"New vertex point: " << xyz_to_string(*lPlacement) ) ;
|
||||
Visitor->OnCollapsing(aProfile.v0v1(),mSurface,lPlacement);
|
||||
|
||||
-- mCurrentEdgeCount ;
|
||||
|
||||
edge_descriptor lEdgeQP = opposite_edge(aEdgePQ,mSurface);
|
||||
|
||||
// The collapse of P-Q removes the top and bottom facets, if any.
|
||||
// Edges P-T and P-Q, which are in the top and bottom facets (if they exist), are used by the collapse operator to remove them.
|
||||
|
||||
// Edges P-T and P-Q are defined only if the top/bottom facets exists
|
||||
|
||||
edge_descriptor lEdgePT, lEdgeQB ;
|
||||
|
||||
if ( !is_border(aEdgePQ) ) // Exists top facet
|
||||
lEdgePT = primary_edge(opposite_edge(prev_edge(aEdgePQ,mSurface),mSurface));
|
||||
|
||||
if ( !is_border(lEdgeQP) ) // Exists bottom facet
|
||||
lEdgeQB = primary_edge(opposite_edge(prev_edge(lEdgeQP,mSurface),mSurface));
|
||||
|
||||
CGAL_ECMS_TRACE(3,"EdgePQ E" << aEdgePQ->ID
|
||||
<< "(V" << aEdgePQ->vertex()->ID << "->V" << aEdgePQ->opposite()->vertex()->ID
|
||||
<< ") EdgeQP E" << aEdgePQ->opposite()->ID
|
||||
) ;
|
||||
|
||||
|
||||
// If the top/bottom facets exists, they are removed and the edges P-T and Q-B along with them.
|
||||
// If the top/bottom facets exists, they are removed and the edges v0vt and Q-B along with them.
|
||||
// In that case their corresponding pairs must be pop off the queue
|
||||
|
||||
if ( handle_assigned(lEdgePT) )
|
||||
if ( aProfile.left_face_exists() )
|
||||
{
|
||||
CGAL_ECMS_TRACE(3,"EdgePT E" << lEdgePT->ID
|
||||
<< "(V" << lEdgePT->vertex()->ID << "->V" << lEdgePT->opposite()->vertex()->ID
|
||||
<< ") EdgeTP E" << lEdgePT->opposite()->ID
|
||||
edge_descriptor lV0VL = primary_edge(aProfile.vlv0());
|
||||
|
||||
CGAL_ECMS_TRACE(3,"V0VL E" << lV0VL->id()
|
||||
<< "(V" << lV0VL->vertex()->id() << "->V" << lV0VL->opposite()->vertex()->id() << ")
|
||||
) ;
|
||||
|
||||
Edge_data& lDataPT = get_data(lEdgePT) ;
|
||||
if ( lDataPT.is_in_PQ() )
|
||||
Edge_data& lData = get_data(lV0VL) ;
|
||||
if ( lData.is_in_PQ() )
|
||||
{
|
||||
CGAL_ECMS_TRACE(2,"Removing E" << lEdgePT->ID << " from PQ" ) ;
|
||||
remove_from_PQ(lEdgePT,lDataPT) ;
|
||||
CGAL_ECMS_TRACE(2,"Removing E" << lV0VL->id() << " from PQ" ) ;
|
||||
remove_from_PQ(lV0VL,lData) ;
|
||||
-- mCurrentEdgeCount ;
|
||||
}
|
||||
}
|
||||
|
||||
if ( handle_assigned(lEdgeQB) )
|
||||
if ( aProfile.right_face_exists() )
|
||||
{
|
||||
CGAL_ECMS_TRACE(3,"EdgeQB E" << lEdgeQB->ID
|
||||
<< "(V" << lEdgeQB->vertex()->ID << "->V" << lEdgeQB->opposite()->vertex()->ID
|
||||
<< ") EdgeBQ E" << lEdgeQB->opposite()->ID
|
||||
edge_descriptor lVRV1 = primary_edge(aProfile.vrv1());
|
||||
|
||||
CGAL_ECMS_TRACE(3,"V1VRE" << lVRV1->id()
|
||||
<< "(V" << lVRV1->vertex()->id() << "->V" << lVRV1->opposite()->vertex()->id() << ")"
|
||||
) ;
|
||||
|
||||
Edge_data& lDataQB = get_data(lEdgeQB) ;
|
||||
if ( lDataQB.is_in_PQ() )
|
||||
Edge_data& lData = get_data(lVRV1) ;
|
||||
if ( lData.is_in_PQ() )
|
||||
{
|
||||
CGAL_ECMS_TRACE(2,"Removing E" << lEdgeQB->ID << " from PQ") ;
|
||||
remove_from_PQ(lEdgeQB,lDataQB) ;
|
||||
CGAL_ECMS_TRACE(2,"Removing E" << lVRV1->ID << " from PQ") ;
|
||||
remove_from_PQ(lVRV1,lData) ;
|
||||
-- mCurrentEdgeCount ;
|
||||
}
|
||||
}
|
||||
|
||||
CGAL_ECMS_TRACE(1,"Removing:\n P-Q: E" << aEdgePQ->ID << "(V" << lP->ID << "->V" << lQ->ID << ")" );
|
||||
CGAL_ECMS_TRACE_IF(handle_assigned(lEdgePT),1," P-T: E" << lEdgePT->ID << "(V" << lP->ID << "->V" << target(lEdgePT,mSurface)->ID << ")" ) ;
|
||||
CGAL_ECMS_TRACE_IF(handle_assigned(lEdgeQB),1," Q-B: E" << lEdgeQB->ID << "(V" << lQ->ID << "->V" << target(lEdgeQB,mSurface)->ID << ")" ) ;
|
||||
CGAL_ECMS_TRACE(1,"Removing:\n v0v1: E" << aProfile.v0v1()->ID << "(V" << lP->ID << "->V" << lQ->ID << ")" );
|
||||
|
||||
|
||||
// Perform the actuall collapse.
|
||||
|
|
@ -467,7 +428,7 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collapse( edge_descriptor con
|
|||
// It's REQUIRED to remove ONLY 1 vertex (P or Q) and edges PQ,PT and QB (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 = collapse_triangulation_edge(aEdgePQ,mSurface);
|
||||
rResult = collapse_triangulation_edge(aProfile.v0v1(),mSurface);
|
||||
|
||||
CGAL_ECMS_TRACE(1,"V" << rResult->ID << " kept." ) ;
|
||||
|
||||
|
|
@ -478,15 +439,18 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Collapse( edge_descriptor con
|
|||
#endif
|
||||
|
||||
if ( lPlacement )
|
||||
{
|
||||
CGAL_ECMS_TRACE(2,"New vertex point: " << xyz_to_string(*lPlacement) ) ;
|
||||
put(vertex_point,mSurface,rResult,*lPlacement) ;
|
||||
}
|
||||
|
||||
Update_neighbors(rResult) ;
|
||||
|
||||
CGAL_ECMS_DEBUG_CODE ( ++mStep ; )
|
||||
}
|
||||
|
||||
template<class M,class SP,class VPM, class EIM,class EBM, class CF,class PF,class CP, class PP,class V>
|
||||
void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Update_neighbors( vertex_descriptor const& aKeptV )
|
||||
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
|
||||
void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Update_neighbors( vertex_descriptor const& aKeptV )
|
||||
{
|
||||
CGAL_ECMS_TRACE(3,"Updating cost of neighboring edges..." ) ;
|
||||
|
||||
|
|
@ -531,7 +495,9 @@ void EdgeCollapse<M,SP,VPM,EIM,EBM,CF,PF,CP,PP,V>::Update_neighbors( vertex_desc
|
|||
|
||||
Edge_data& lData = get_data(lEdge);
|
||||
|
||||
lData.cost() = get_cost(lEdge) ;
|
||||
Profile const& lProfile = create_profile(lEdge);
|
||||
|
||||
lData.cost() = get_cost(lProfile) ;
|
||||
|
||||
CGAL_ECMS_TRACE(3, edge_to_string(lEdge) << " updated in the PQ") ;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_RATIO_STOP_PREDICATE_H 1
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -43,6 +44,8 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor ;
|
||||
typedef typename boost::graph_traits<ECM>::edges_size_type size_type ;
|
||||
|
||||
|
|
@ -55,7 +58,7 @@ public :
|
|||
Count_ratio_stop_predicate( double aRatio ) : mRatio(aRatio) {}
|
||||
|
||||
bool operator()( FT const& // aCurrentCost
|
||||
, edge_descriptor const& //aEdge
|
||||
, Profile const& //aEdgeProfile
|
||||
, size_type aInitialCount
|
||||
, size_type aCurrentCount
|
||||
) const
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H 1
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -43,6 +44,8 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
private :
|
||||
|
||||
typedef typename halfedge_graph_traits<ECM>::Point Point ;
|
||||
|
|
@ -60,7 +63,7 @@ public :
|
|||
Count_stop_predicate( size_type aThres ) : mThres(aThres) {}
|
||||
|
||||
bool operator()( FT const& // aCurrentCost
|
||||
, edge_descriptor const& //aEdge
|
||||
, Profile const& //aEdgeProfile
|
||||
, size_type aInitialCount
|
||||
, size_type aCurrentCount
|
||||
) const
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_params.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
|
@ -44,6 +45,8 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef boost::graph_traits<ECM> GraphTraits ;
|
||||
|
||||
typedef typename GraphTraits::vertex_descriptor vertex_descriptor ;
|
||||
|
|
@ -65,40 +68,37 @@ public:
|
|||
|
||||
typedef MatrixC33<Kernel> Matrix ;
|
||||
|
||||
typedef typename Profile::Triangle Triangle ;
|
||||
typedef typename Profile::vertex_descriptor_vector vertex_descriptor_vector ;
|
||||
|
||||
typedef typename Profile::Triangle_vector ::const_iterator const_triangle_iterator ;
|
||||
typedef typename Profile::edge_descriptor_vector::const_iterator const_border_edge_iterator ;
|
||||
|
||||
public:
|
||||
|
||||
LindstromTurkCore( Params const& aParams
|
||||
, edge_descriptor const& aP_Q
|
||||
, ECM& aSurface
|
||||
) ;
|
||||
LindstromTurkCore( Params const& aParams, Profile const& aProfile ) ;
|
||||
|
||||
Optional_point compute_placement() ;
|
||||
Optional_FT compute_cost( Optional_point const& p ) ;
|
||||
|
||||
private :
|
||||
|
||||
struct Triangle
|
||||
struct Triangle_data
|
||||
{
|
||||
Triangle() {}
|
||||
|
||||
Triangle( Vector const& aNormalV, FT const& aNormalL ) : NormalV(aNormalV), NormalL(aNormalL) {}
|
||||
Triangle_data( Vector const& aNormalV, FT const& aNormalL ) : NormalV(aNormalV), NormalL(aNormalL) {}
|
||||
|
||||
Vector NormalV ;
|
||||
FT NormalL ;
|
||||
} ;
|
||||
|
||||
typedef std::vector<Triangle> Triangles ;
|
||||
typedef std::vector<vertex_descriptor> Link ;
|
||||
typedef std::vector<edge_descriptor> edge_descriptor_vector ;
|
||||
|
||||
struct BoundaryEdge
|
||||
struct Boundary_data
|
||||
{
|
||||
BoundaryEdge ( Point s_, Point t_, Vector const& v_, Vector const& n_ ) : s(s_), t(t_), v(v_), n(n_) {}
|
||||
Boundary_data ( Point s_, Point t_, Vector const& v_, Vector const& n_ ) : s(s_), t(t_), v(v_), n(n_) {}
|
||||
|
||||
Point s, t ;
|
||||
Vector v, n ;
|
||||
} ;
|
||||
typedef std::vector<BoundaryEdge> BoundaryEdges ;
|
||||
typedef std::vector<Triangle_data> Triangle_data_vector ;
|
||||
typedef std::vector<Boundary_data> Boundary_data_vector ;
|
||||
|
||||
class Constrians
|
||||
{
|
||||
|
|
@ -123,27 +123,21 @@ private :
|
|||
|
||||
private :
|
||||
|
||||
void Add_boundary_preservation_constrians( BoundaryEdges const& aBdry ) ;
|
||||
void Add_volume_preservation_constrians( Triangles const& aTriangles );
|
||||
void Add_boundary_and_volume_optimization_constrians( BoundaryEdges const& aBdry, Triangles const& aTriangles ) ;
|
||||
void Add_shape_optimization_constrians( Link const& aLink ) ;
|
||||
void Extract_triangle_data();
|
||||
void Extract_boundary_data() ;
|
||||
|
||||
FT Compute_boundary_cost( Vector const& v, BoundaryEdges const& aBdry ) ;
|
||||
FT Compute_volume_cost ( Vector const& v, Triangles const& aTriangles ) ;
|
||||
FT Compute_shape_cost ( Point const& p, Link const& aLink ) ;
|
||||
void Add_boundary_preservation_constrians( Boundary_data_vector const& aBdry ) ;
|
||||
void Add_volume_preservation_constrians( Triangle_data_vector const& aTriangles );
|
||||
void Add_boundary_and_volume_optimization_constrians( Boundary_data_vector const& aBdry, Triangle_data_vector const& aTriangles ) ;
|
||||
void Add_shape_optimization_constrians( vertex_descriptor_vector const& aLink ) ;
|
||||
|
||||
bool is_border ( edge_descriptor const& edge ) const
|
||||
{
|
||||
return get(edge_is_border,mSurface,edge) ;
|
||||
}
|
||||
bool is_undirected_edge_a_border ( edge_descriptor const& edge ) const
|
||||
{
|
||||
return is_border(edge) || is_border(opposite_edge(edge,mSurface)) ;
|
||||
}
|
||||
FT Compute_boundary_cost( Vector const& v, Boundary_data_vector const& aBdry ) ;
|
||||
FT Compute_volume_cost ( Vector const& v, Triangle_data_vector const& aTriangles ) ;
|
||||
FT Compute_shape_cost ( Point const& p, vertex_descriptor_vector const& aLink ) ;
|
||||
|
||||
Point const& get_point ( vertex_descriptor const& v ) const
|
||||
{
|
||||
return get(vertex_point,mSurface,v);
|
||||
return get(vertex_point,surface(),v);
|
||||
}
|
||||
|
||||
static Vector Point_cross_product ( Point const& a, Point const& b )
|
||||
|
|
@ -172,38 +166,18 @@ private :
|
|||
);
|
||||
}
|
||||
|
||||
Triangle Get_triangle ( vertex_descriptor const& v0
|
||||
, vertex_descriptor const& v1
|
||||
, vertex_descriptor const& v2
|
||||
) ;
|
||||
|
||||
void Extract_triangle( vertex_descriptor const& v0
|
||||
, vertex_descriptor const& v1
|
||||
, vertex_descriptor const& v2
|
||||
, edge_descriptor const& e02
|
||||
) ;
|
||||
|
||||
void Extract_triangles_and_link();
|
||||
|
||||
void Extract_boundary_edge ( edge_descriptor edge) ;
|
||||
void Extract_boundary_edges( vertex_descriptor const& v, edge_descriptor_vector& rCollected ) ;
|
||||
void Extract_boundary_edges() ;
|
||||
ECM& surface() const { return mProfile.surface() ; }
|
||||
|
||||
private:
|
||||
|
||||
Params const& mParams ;
|
||||
edge_descriptor const& mP_Q ;
|
||||
ECM& mSurface ;
|
||||
|
||||
vertex_descriptor mP ;
|
||||
vertex_descriptor mQ ;
|
||||
edge_descriptor mQ_P ;
|
||||
Profile const& mProfile ;
|
||||
|
||||
private:
|
||||
|
||||
Triangles mTriangles;
|
||||
Link mLink;
|
||||
BoundaryEdges mBdry ;
|
||||
Triangle_data_vector mTriangle_data ;
|
||||
Boundary_data_vector mBdry_data ;
|
||||
|
||||
Constrians mConstrians ;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,38 +31,65 @@ namespace Surface_mesh_simplification
|
|||
{
|
||||
|
||||
template<class ECM>
|
||||
LindstromTurkCore<ECM>::LindstromTurkCore( Params const& aParams
|
||||
, edge_descriptor const& aP_Q
|
||||
, ECM& aSurface
|
||||
)
|
||||
LindstromTurkCore<ECM>::LindstromTurkCore( Params const& aParams, Profile const& aProfile )
|
||||
:
|
||||
mParams(aParams)
|
||||
,mP_Q(aP_Q)
|
||||
,mSurface(aSurface)
|
||||
|
||||
,mP ( source (aP_Q,aSurface) )
|
||||
,mQ ( target (aP_Q,aSurface) )
|
||||
,mQ_P( opposite_edge(aP_Q,aSurface) )
|
||||
,mProfile(aProfile)
|
||||
{
|
||||
Extract_triangle_data();
|
||||
Extract_boundary_data();
|
||||
}
|
||||
|
||||
mTriangles.clear();
|
||||
mLink .clear();
|
||||
mTriangles.reserve(16);
|
||||
mLink .reserve(16);
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_boundary_data()
|
||||
{
|
||||
for ( const_border_edge_iterator it = mProfile.border_edges().begin(), eit = mProfile.border_edges().end() ; it != eit ; ++ it )
|
||||
{
|
||||
edge_descriptor border_edge = *it ;
|
||||
|
||||
// Volume preservation and optimization constrians are based on the normals to the triangles in the star of the collapsing egde
|
||||
// Triangle shape optimization constrians are based on the link of the collapsing edge (the cycle of vertices around the edge)
|
||||
Extract_triangles_and_link();
|
||||
edge_descriptor face_edge = opposite_edge(border_edge,surface()) ;
|
||||
|
||||
#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE
|
||||
std::ostringstream ss ;
|
||||
for( typename Link::const_iterator it = mLink.begin(), eit = mLink.end() ; it != eit ; ++it )
|
||||
ss << "v" << (*it)->ID << " " ;
|
||||
std::string s = ss.str();
|
||||
CGAL_ECMS_LT_TRACE(3,"Link: " << s );
|
||||
#endif
|
||||
vertex_descriptor sv = source(face_edge,surface());
|
||||
vertex_descriptor tv = target(face_edge,surface());
|
||||
|
||||
Extract_boundary_edges();
|
||||
Point const& sp = get_point(sv);
|
||||
Point const& tp = get_point(tv);
|
||||
|
||||
Vector v = tp - sp ;
|
||||
Vector n = Point_cross_product(tp,sp) ;
|
||||
|
||||
CGAL_ECMS_LT_TRACE(3,"Boundary edge. S:" << xyz_to_string(sp) << " T:" << xyz_to_string(tp)
|
||||
<< " V:" << xyz_to_string(v) << " N:" << xyz_to_string(n)
|
||||
) ;
|
||||
|
||||
mBdry_data.push_back( Boundary_data(sp,tp,v,n) ) ;
|
||||
}
|
||||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_triangle_data()
|
||||
{
|
||||
for ( const_triangle_iterator it = mProfile.triangles().begin(), eit = mProfile.triangles().end() ; it != eit ; ++ it )
|
||||
{
|
||||
Triangle const& tri = *it ;
|
||||
|
||||
Point const& p0 = get_point(tri.v0);
|
||||
Point const& p1 = get_point(tri.v1);
|
||||
Point const& p2 = get_point(tri.v2);
|
||||
|
||||
Vector v01 = p1 - p0 ;
|
||||
Vector v02 = p2 - p0 ;
|
||||
|
||||
Vector lNormalV = cross_product(v01,v02);
|
||||
|
||||
FT lNormalL = Point_cross_product(p0,p1) * (p2-ORIGIN);
|
||||
|
||||
CGAL_ECMS_LT_TRACE(3,"Extracting triangle v" << lTri.v0->id() << "->v" << lTri.v1->id() << "->v" << lTri.v2->id()
|
||||
<< " N:" << xyz_to_string(lNormalV) << " L:" << lNormalL
|
||||
);
|
||||
|
||||
mTriangle_data.push_back(Triangle_data(lNormalV,lNormalL));
|
||||
}
|
||||
}
|
||||
|
||||
template<class ECM>
|
||||
|
|
@ -71,7 +98,7 @@ typename LindstromTurkCore<ECM>::Optional_point LindstromTurkCore<ECM>::compute_
|
|||
Optional_point rPlacementP ;
|
||||
Optional_vector lPlacementV ;
|
||||
|
||||
CGAL_ECMS_LT_TRACE(2,"Computing LT data for E" << mP_Q->ID << " (V" << mP->ID << "->V" << mQ->ID << ")" );
|
||||
CGAL_ECMS_LT_TRACE(2,"Computing LT data for E" << mProfile.v0v1()->id() << " (V" << mProfile.v0()->id() << "->V" << mProfile.v1()->id() << ")" );
|
||||
|
||||
//
|
||||
// Each vertex constrian is an equation of the form: Ai * v = bi
|
||||
|
|
@ -96,17 +123,17 @@ typename LindstromTurkCore<ECM>::Optional_point LindstromTurkCore<ECM>::compute_
|
|||
//
|
||||
// A constrian (Ai,bi) must be alpha-compatible with the previously added constrians (see Paper); if it's not, is discarded.
|
||||
//
|
||||
if ( mBdry.size() > 0 )
|
||||
Add_boundary_preservation_constrians(mBdry);
|
||||
if ( mBdry_data.size() > 0 )
|
||||
Add_boundary_preservation_constrians(mBdry_data);
|
||||
|
||||
if ( mConstrians.n < 3 )
|
||||
Add_volume_preservation_constrians(mTriangles);
|
||||
Add_volume_preservation_constrians(mTriangle_data);
|
||||
|
||||
if ( mConstrians.n < 3 )
|
||||
Add_boundary_and_volume_optimization_constrians(mBdry,mTriangles);
|
||||
Add_boundary_and_volume_optimization_constrians(mBdry_data,mTriangle_data);
|
||||
|
||||
if ( mConstrians.n < 3 )
|
||||
Add_shape_optimization_constrians(mLink);
|
||||
Add_shape_optimization_constrians(mProfile.link());
|
||||
|
||||
// It might happen that there were not enough alpha-compatible constrians.
|
||||
// In that case there is simply no good vertex placement
|
||||
|
|
@ -141,18 +168,15 @@ typename LindstromTurkCore<ECM>::Optional_FT LindstromTurkCore<ECM>::compute_cos
|
|||
|
||||
if ( aP )
|
||||
{
|
||||
Point const& lP = get_point(mP) ;
|
||||
Point const& lQ = get_point(mQ) ;
|
||||
|
||||
Vector lV = (*aP) - ORIGIN ;
|
||||
|
||||
FT lSquaredLength = squared_distance(lP,lQ);
|
||||
FT lSquaredLength = squared_distance(mProfile.p0(),mProfile.p1());
|
||||
|
||||
CGAL_ECMS_LT_TRACE(1,"Squared edge length: " << lSquaredLength ) ;
|
||||
|
||||
FT lBdryCost = Compute_boundary_cost(lV ,mBdry);
|
||||
FT lVolumeCost = Compute_volume_cost (lV ,mTriangles);
|
||||
FT lShapeCost = Compute_shape_cost (*aP,mLink);
|
||||
FT lBdryCost = Compute_boundary_cost(lV ,mBdry_data);
|
||||
FT lVolumeCost = Compute_volume_cost (lV ,mTriangle_data);
|
||||
FT lShapeCost = Compute_shape_cost (*aP,mProfile.link());
|
||||
|
||||
FT lTotalCost = FT(mParams.VolumeWeight) * lVolumeCost
|
||||
+ FT(mParams.BoundaryWeight) * lBdryCost * lSquaredLength
|
||||
|
|
@ -172,186 +196,8 @@ typename LindstromTurkCore<ECM>::Optional_FT LindstromTurkCore<ECM>::compute_cos
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Caches the "local boundary", that is, the sequence of 3 border edges: o->p, p->q, q->e
|
||||
//
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_boundary_edge( edge_descriptor edge )
|
||||
{
|
||||
edge_descriptor face_edge = is_border(edge) ? opposite_edge(edge,mSurface) : edge ;
|
||||
|
||||
vertex_descriptor sv = source(face_edge,mSurface);
|
||||
vertex_descriptor tv = target(face_edge,mSurface);
|
||||
|
||||
Point const& sp = get_point(sv);
|
||||
Point const& tp = get_point(tv);
|
||||
|
||||
Vector v = tp - sp ;
|
||||
Vector n = Point_cross_product(tp,sp) ;
|
||||
|
||||
CGAL_ECMS_LT_TRACE(3,"Boundary edge. S:" << xyz_to_string(sp) << " T:" << xyz_to_string(tp)
|
||||
<< " V:" << xyz_to_string(v) << " N:" << xyz_to_string(n)
|
||||
) ;
|
||||
|
||||
mBdry.push_back( BoundaryEdge(sp,tp,v,n) ) ;
|
||||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_boundary_edges( vertex_descriptor const& v
|
||||
, edge_descriptor_vector& rCollected
|
||||
)
|
||||
{
|
||||
in_edge_iterator eb, ee ;
|
||||
for ( tie(eb,ee) = in_edges(v,mSurface) ; eb != ee ; ++ eb )
|
||||
{
|
||||
edge_descriptor edge = *eb ;
|
||||
|
||||
if ( is_undirected_edge_a_border(edge) && std::find(rCollected.begin(),rCollected.end(),edge) == rCollected.end() )
|
||||
{
|
||||
Extract_boundary_edge(edge);
|
||||
rCollected.push_back(edge);
|
||||
rCollected.push_back(opposite_edge(edge,mSurface));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_boundary_edges()
|
||||
{
|
||||
edge_descriptor_vector lCollected ;
|
||||
Extract_boundary_edges(mP,lCollected);
|
||||
Extract_boundary_edges(mQ,lCollected);
|
||||
}
|
||||
|
||||
//
|
||||
// Calculates the normal of the triangle (v0,v1,v2) (both vector and its length as (v0xv1).v2)
|
||||
//
|
||||
template<class ECM>
|
||||
typename LindstromTurkCore<ECM>::Triangle LindstromTurkCore<ECM>::Get_triangle( vertex_descriptor const& v0
|
||||
, vertex_descriptor const& v1
|
||||
, vertex_descriptor const& v2
|
||||
)
|
||||
{
|
||||
Point const& p0 = get_point(v0);
|
||||
Point const& p1 = get_point(v1);
|
||||
Point const& p2 = get_point(v2);
|
||||
|
||||
Vector v01 = p1 - p0 ;
|
||||
Vector v02 = p2 - p0 ;
|
||||
|
||||
Vector lNormalV = cross_product(v01,v02);
|
||||
|
||||
FT lNormalL = Point_cross_product(p0,p1) * (p2-ORIGIN);
|
||||
|
||||
CGAL_ECMS_LT_TRACE(3,"Extracting triangle v" << v0->ID << "->v" << v1->ID << "->v" << v2->ID
|
||||
<< " N:" << xyz_to_string(lNormalV) << " L:" << lNormalL
|
||||
);
|
||||
|
||||
return Triangle(lNormalV,lNormalL);
|
||||
}
|
||||
|
||||
//
|
||||
// If (v0,v1,v2) is a finite triangular facet of the mesh, that is, NONE of these vertices are boundary vertices,
|
||||
// the triangle (properly oriented) is added to rTriangles.
|
||||
// The triangle is encoded as its normal, calculated using the actual facet orientation [(v0,v1,v2) or (v0,v2,v1)]
|
||||
//
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_triangle( vertex_descriptor const& v0
|
||||
, vertex_descriptor const& v1
|
||||
, vertex_descriptor const& v2
|
||||
, edge_descriptor const& e02
|
||||
)
|
||||
{
|
||||
// The 3 vertices are obtained by circulating ccw around v0, that is, e02 = next_ccw(e01).
|
||||
// Since these vertices are NOT obtained by circulating the face, the actual triangle orientation is unspecified.
|
||||
|
||||
// The triangle is oriented v0->v2->v1 if the next edge that follows e02 (which is the edge v0->v2) is v2->v1.
|
||||
if ( target(next_edge(e02,mSurface),mSurface) == v1 )
|
||||
{
|
||||
// The triangle is oriented v0->v2->v1.
|
||||
// In this case e02 is an edge of the facet.
|
||||
// If this facet edge is a border edge then this triangle is not in the mesh .
|
||||
if ( !is_border(e02) )
|
||||
mTriangles.push_back(Get_triangle(v0,v2,v1) ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The triangle is oriented v0->v1->v2.
|
||||
// In this case, e20 and not e02, is an edge of the facet.
|
||||
// If this facet edge is a border edge then this triangle is not in the mesh .
|
||||
if ( !is_border(opposite_edge(e02,mSurface)) )
|
||||
mTriangles.push_back(Get_triangle(v0,v1,v2) ) ;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Extract all triangles (its normals) and vertices (the link) around the collpasing edge p_q
|
||||
//
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Extract_triangles_and_link()
|
||||
{
|
||||
//
|
||||
// Extract around mP, CCW
|
||||
//
|
||||
vertex_descriptor v0 = mP;
|
||||
vertex_descriptor v1 = mQ;
|
||||
|
||||
edge_descriptor e02 = mP_Q;
|
||||
|
||||
do
|
||||
{
|
||||
e02 = next_edge_ccw(e02,mSurface);
|
||||
|
||||
vertex_descriptor v2 = target(e02,mSurface);
|
||||
|
||||
if ( v2 != mQ )
|
||||
{
|
||||
CGAL_expensive_assertion ( std::find(mLink.begin(),mLink.end(),v2) == mLink.end() ) ;
|
||||
mLink.push_back(v2) ;
|
||||
}
|
||||
|
||||
Extract_triangle(v0,v1,v2,e02);
|
||||
|
||||
v1 = v2 ;
|
||||
}
|
||||
while ( e02 != mP_Q ) ;
|
||||
|
||||
//
|
||||
// Extract around mQ, CCW
|
||||
//
|
||||
|
||||
v0 = mQ;
|
||||
|
||||
e02 = next_edge_ccw(mQ_P,mSurface);
|
||||
|
||||
v1 = target(e02,mSurface);
|
||||
|
||||
// This could have been added to the link while circulating around mP
|
||||
if ( v1 != mP && std::find(mLink.begin(),mLink.end(),v1) == mLink.end() )
|
||||
mLink.push_back(v1) ;
|
||||
|
||||
e02 = next_edge_ccw(e02,mSurface);
|
||||
|
||||
do
|
||||
{
|
||||
vertex_descriptor v2 = target(e02,mSurface);
|
||||
|
||||
// Any of the vertices found around mP can be reached again around mQ, but we can't duplicate them here.
|
||||
if ( v2 != mP && std::find(mLink.begin(),mLink.end(),v2) == mLink.end() )
|
||||
mLink.push_back(v2) ;
|
||||
|
||||
Extract_triangle(v0,v1,v2,e02);
|
||||
|
||||
v1 = v2 ;
|
||||
|
||||
e02 = next_edge_ccw(e02,mSurface);
|
||||
|
||||
}
|
||||
while ( e02 != mQ_P ) ;
|
||||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Add_boundary_preservation_constrians( BoundaryEdges const& aBdry )
|
||||
void LindstromTurkCore<ECM>::Add_boundary_preservation_constrians( Boundary_data_vector const& aBdry )
|
||||
{
|
||||
|
||||
if ( aBdry.size() > 0 )
|
||||
|
|
@ -359,7 +205,7 @@ void LindstromTurkCore<ECM>::Add_boundary_preservation_constrians( BoundaryEdges
|
|||
Vector e1 = NULL_VECTOR ;
|
||||
Vector e2 = NULL_VECTOR ;
|
||||
|
||||
for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
{
|
||||
e1 = e1 + it->v ;
|
||||
e2 = e2 + it->n ;
|
||||
|
|
@ -376,14 +222,14 @@ void LindstromTurkCore<ECM>::Add_boundary_preservation_constrians( BoundaryEdges
|
|||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Add_volume_preservation_constrians( Triangles const& aTriangles )
|
||||
void LindstromTurkCore<ECM>::Add_volume_preservation_constrians( Triangle_data_vector const& aTriangles )
|
||||
{
|
||||
CGAL_ECMS_LT_TRACE(2,"Adding volume preservation constrians. " << aTriangles.size() << " triangles.");
|
||||
|
||||
Vector lSumV = NULL_VECTOR ;
|
||||
FT lSumL(0) ;
|
||||
|
||||
for( typename Triangles::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
{
|
||||
lSumV = lSumV + it->NormalV ;
|
||||
lSumL = lSumL + it->NormalL ;
|
||||
|
|
@ -394,7 +240,9 @@ void LindstromTurkCore<ECM>::Add_volume_preservation_constrians( Triangles const
|
|||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( BoundaryEdges const& aBdry, Triangles const& aTriangles )
|
||||
void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( Boundary_data_vector const& aBdry
|
||||
, Triangle_data_vector const& aTriangles
|
||||
)
|
||||
{
|
||||
CGAL_ECMS_LT_TRACE(2,"Adding boundary and volume optimization constrians. ");
|
||||
|
||||
|
|
@ -404,9 +252,9 @@ void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( Bo
|
|||
//
|
||||
// Volume optimization
|
||||
//
|
||||
for( typename Triangles::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
{
|
||||
Triangle const& lTri = *it ;
|
||||
Triangle_data const& lTri = *it ;
|
||||
|
||||
H += direct_product(lTri.NormalV,lTri.NormalV) ;
|
||||
|
||||
|
|
@ -424,7 +272,7 @@ void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( Bo
|
|||
Matrix Hb = NULL_MATRIX ;
|
||||
Vector cb = NULL_VECTOR ;
|
||||
|
||||
for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
{
|
||||
Matrix H = LT_product(it->v);
|
||||
Vector c = cross_product(it->v,it->n);
|
||||
|
|
@ -438,7 +286,7 @@ void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( Bo
|
|||
//
|
||||
// Weighted average
|
||||
//
|
||||
FT lScaledBoundaryWeight = FT(9) * mParams.BoundaryWeight * squared_distance ( get_point(mP), get_point(mQ) ) ;
|
||||
FT lScaledBoundaryWeight = FT(9) * mParams.BoundaryWeight * squared_distance(mProfile.p0(),mProfile.p1()) ;
|
||||
|
||||
H *= mParams.VolumeWeight ;
|
||||
c = c * mParams.VolumeWeight ;
|
||||
|
|
@ -454,7 +302,7 @@ void LindstromTurkCore<ECM>::Add_boundary_and_volume_optimization_constrians( Bo
|
|||
}
|
||||
|
||||
template<class ECM>
|
||||
void LindstromTurkCore<ECM>::Add_shape_optimization_constrians( Link const& aLink )
|
||||
void LindstromTurkCore<ECM>::Add_shape_optimization_constrians( vertex_descriptor_vector const& aLink )
|
||||
{
|
||||
FT s(aLink.size());
|
||||
|
||||
|
|
@ -465,7 +313,7 @@ void LindstromTurkCore<ECM>::Add_shape_optimization_constrians( Link const& aLin
|
|||
|
||||
Vector c = NULL_VECTOR ;
|
||||
|
||||
for( typename Link::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it )
|
||||
for( typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it )
|
||||
c = c + (ORIGIN - get_point(*it)) ;
|
||||
|
||||
CGAL_ECMS_LT_TRACE(2,"Adding shape optimization constrians: Shape vector: " << xyz_to_string(c) );
|
||||
|
|
@ -475,10 +323,10 @@ void LindstromTurkCore<ECM>::Add_shape_optimization_constrians( Link const& aLin
|
|||
|
||||
template<class ECM>
|
||||
typename LindstromTurkCore<ECM>::FT
|
||||
LindstromTurkCore<ECM>::Compute_boundary_cost( Vector const& v, BoundaryEdges const& aBdry )
|
||||
LindstromTurkCore<ECM>::Compute_boundary_cost( Vector const& v, Boundary_data_vector const& aBdry )
|
||||
{
|
||||
FT rCost(0);
|
||||
for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it )
|
||||
{
|
||||
Vector u = (it->t - ORIGIN ) - v ;
|
||||
Vector c = cross_product(it->v,u);
|
||||
|
|
@ -489,13 +337,13 @@ LindstromTurkCore<ECM>::Compute_boundary_cost( Vector const& v, BoundaryEdges co
|
|||
|
||||
template<class ECM>
|
||||
typename LindstromTurkCore<ECM>::FT
|
||||
LindstromTurkCore<ECM>::Compute_volume_cost( Vector const& v, Triangles const& aTriangles )
|
||||
LindstromTurkCore<ECM>::Compute_volume_cost( Vector const& v, Triangle_data_vector const& aTriangles )
|
||||
{
|
||||
FT rCost(0);
|
||||
|
||||
for( typename Triangles::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it )
|
||||
{
|
||||
Triangle const& lTri = *it ;
|
||||
Triangle_data const& lTri = *it ;
|
||||
|
||||
FT lF = lTri.NormalV * v - lTri.NormalL ;
|
||||
|
||||
|
|
@ -508,11 +356,11 @@ LindstromTurkCore<ECM>::Compute_volume_cost( Vector const& v, Triangles const& a
|
|||
|
||||
template<class ECM>
|
||||
typename LindstromTurkCore<ECM>::FT
|
||||
LindstromTurkCore<ECM>::Compute_shape_cost( Point const& p, Link const& aLink )
|
||||
LindstromTurkCore<ECM>::Compute_shape_cost( Point const& p, vertex_descriptor_vector const& aLink )
|
||||
{
|
||||
FT rCost(0);
|
||||
|
||||
for( typename Link::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it )
|
||||
for( typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it )
|
||||
rCost += squared_distance(p,get_point(*it)) ;
|
||||
|
||||
return rCost ;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_EDGE_LENGHT_COST_H
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -36,50 +37,23 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
private :
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::vertex_descriptor vertex_descriptor ;
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef typename halfedge_graph_traits<ECM>::Point Point ;
|
||||
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel ;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor ;
|
||||
|
||||
typedef typename Kernel::FT FT ;
|
||||
|
||||
typedef optional<FT> result_type ;
|
||||
|
||||
typedef void Params ;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Edge_length_cost() {}
|
||||
|
||||
result_type operator()( edge_descriptor const& aEdge
|
||||
, ECM& aSurface
|
||||
, Params const* //aParams
|
||||
, optional<Point> const& //aPlacement
|
||||
) const
|
||||
result_type operator()( Profile const& aProfile, optional<Point> const& /*aPlacement*/ ) const
|
||||
{
|
||||
vertex_descriptor vs,vt ; tie(vs,vt) = get_vertices(aEdge,aSurface);
|
||||
|
||||
Point const& ps = get(vertex_point,aSurface,vs);
|
||||
Point const& pt = get(vertex_point,aSurface,vt);
|
||||
|
||||
return result_type(squared_distance(ps,pt));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
tuple<vertex_descriptor,vertex_descriptor> get_vertices ( edge_descriptor const& aEdge, ECM& aSurface ) const
|
||||
{
|
||||
vertex_descriptor p = source(aEdge,aSurface);
|
||||
vertex_descriptor q = target(aEdge,aSurface);
|
||||
return make_tuple(p,q);
|
||||
return result_type(squared_distance(aProfile.p0(),aProfile.p1()));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::vertex_descriptor vertex_descriptor ;
|
||||
typedef typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor ;
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef typename halfedge_graph_traits<ECM>::Point Point ;
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel ;
|
||||
|
|
@ -42,24 +41,18 @@ public:
|
|||
|
||||
typedef optional<FT> result_type ;
|
||||
|
||||
typedef LindstromTurk_params Params ;
|
||||
|
||||
public:
|
||||
|
||||
LindstromTurk_cost() {}
|
||||
LindstromTurk_cost( LindstromTurk_params const& aParams = LindstromTurk_params() ) : mParams(aParams) {}
|
||||
|
||||
result_type operator()( edge_descriptor const& aEdge
|
||||
, ECM& aSurface
|
||||
, Params const* aParams
|
||||
, optional<Point> const& aPlacement
|
||||
) const
|
||||
result_type operator()( Profile const& aProfile, optional<Point> const& aPlacement ) const
|
||||
{
|
||||
CGAL_assertion(aParams);
|
||||
CGAL_assertion( handle_assigned(aEdge) );
|
||||
|
||||
return LindstromTurkCore<ECM>(*aParams,aEdge,aSurface).compute_cost(aPlacement) ;
|
||||
return LindstromTurkCore<ECM>(mParams,aProfile).compute_cost(aPlacement) ;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LindstromTurk_params mParams ;
|
||||
};
|
||||
|
||||
} // namespace Surface_mesh_simplification
|
||||
|
|
|
|||
|
|
@ -33,26 +33,25 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor ;
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef typename halfedge_graph_traits<ECM>::Point Point ;
|
||||
|
||||
typedef optional<Point> result_type ;
|
||||
|
||||
typedef LindstromTurk_params Params ;
|
||||
|
||||
public:
|
||||
|
||||
result_type operator()( edge_descriptor const& aEdge
|
||||
, ECM& aSurface
|
||||
, Params const* aParams
|
||||
) const
|
||||
{
|
||||
CGAL_assertion(aParams);
|
||||
CGAL_assertion( handle_assigned(aEdge) );
|
||||
LindstromTurk_placement( LindstromTurk_params const& aParams = LindstromTurk_params() ) : mParams(aParams) {}
|
||||
|
||||
return LindstromTurkCore<ECM>(*aParams,aEdge,aSurface).compute_placement() ;
|
||||
result_type operator()( Profile const& aProfile) const
|
||||
{
|
||||
return LindstromTurkCore<ECM>(mParams,aProfile).compute_placement() ;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LindstromTurk_params mParams ;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_MIDPOINT_PLACEMENT_H 1
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Detail/Edge_profile.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -32,42 +33,21 @@ public:
|
|||
|
||||
typedef ECM_ ECM ;
|
||||
|
||||
typedef typename boost::graph_traits<ECM>::edge_descriptor edge_descriptor ;
|
||||
typedef typename boost::graph_traits<ECM>::vertex_descriptor vertex_descriptor ;
|
||||
typedef Edge_profile<ECM> Profile ;
|
||||
|
||||
typedef typename halfedge_graph_traits<ECM>::Point Point ;
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel ;
|
||||
typedef typename Kernel::FT FT ;
|
||||
|
||||
typedef optional<Point> result_type ;
|
||||
|
||||
typedef void Params ;
|
||||
|
||||
public:
|
||||
|
||||
Midpoint_placement() {}
|
||||
|
||||
result_type operator()( edge_descriptor const& aEdge
|
||||
, ECM& aSurface
|
||||
, Params const* //aParams
|
||||
) const
|
||||
result_type operator()( Profile const& aProfile ) const
|
||||
{
|
||||
vertex_descriptor vs,vt ; tie(vs,vt) = get_vertices(aEdge,aSurface);
|
||||
|
||||
Point const& ps = get(vertex_point,aSurface,vs);
|
||||
Point const& pt = get(vertex_point,aSurface,vt);
|
||||
|
||||
return result_type(midpoint(ps,pt));
|
||||
return result_type(midpoint(aProfile.p0(),aProfile.p1()));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
tuple<vertex_descriptor,vertex_descriptor> get_vertices ( edge_descriptor const& aEdge, ECM& aSurface ) const
|
||||
{
|
||||
vertex_descriptor p = source(aEdge,aSurface);
|
||||
vertex_descriptor q = target(aEdge,aSurface);
|
||||
return make_tuple(p,q);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Surface_mesh_simplification
|
||||
|
|
|
|||
|
|
@ -29,76 +29,37 @@ CGAL_BEGIN_NAMESPACE
|
|||
namespace Surface_mesh_simplification
|
||||
{
|
||||
|
||||
|
||||
//
|
||||
// Edge-collapse method:
|
||||
//
|
||||
// Simplifies a triangulated surface mesh by iteratively selecting and collapsing edges.
|
||||
//
|
||||
// Not all edges are selected for removal; those which cannot be removed are labled "fixed"
|
||||
// and there are two kinds of fixed pairs: Intrisically fixed and explicitely fixed.
|
||||
// Intrinsically fixed edges are those which, if removed, would result in a topologically incosistent mesh.
|
||||
// (the algorithm automatically detects intrinsically fixed edges).
|
||||
// Explicitely fixed edges appear when the two vertices incident on the edge have been marked by the user as fixed,
|
||||
// via the "VertexIsFixedMap" property map.
|
||||
//
|
||||
// For each non-fixed edge in the mesh, a "collapse data" record is constructed by calling the user-supplied function
|
||||
// "SetCollapseData".
|
||||
// The edge is then associated with its collapse data via the "EdgeExtraPtrMap" property map.
|
||||
//
|
||||
// The user-supplied function "GetCost" is called, for each non-fixed edge.
|
||||
// This function returns a value which defines the collapsing cost of the edge. Edges with a lower cost are collapsed first.
|
||||
//
|
||||
// When a non-fixed edge is selected for removal, a user-supplied function "GetNewVertexPoint" is called.
|
||||
// This function returns a Point_3 which defines the coordinates of the single vertex that replaces the collapsed edge.
|
||||
//
|
||||
// The simplification continues until there are no more non-fixed edges to collapse or the user-defined function "ShouldStop"
|
||||
// returns true.
|
||||
//
|
||||
// NOTE: The functions GetCost and GetNewVertexPoint return 'optional values'. This is to allow the function to reject an
|
||||
// edge becasue it's cost is too high or uncomputable or the new vertex point cannot be placed in any way that
|
||||
// satisfies the constriants required by method used in these functions.
|
||||
// Consequently, not all non-fixed edges are neccessarily removed.
|
||||
//
|
||||
// This global function returns the number of edges collapsed.
|
||||
//
|
||||
template<class ECM
|
||||
,class ShouldStop
|
||||
,class VertexPointMap
|
||||
,class VertexIndexMap
|
||||
,class EdgeIndexMap
|
||||
,class EdgeIsBorderMap
|
||||
,class GetCost
|
||||
,class GetPlacement
|
||||
,class CostParams
|
||||
,class PlacementParams
|
||||
,class Visitor
|
||||
>
|
||||
int edge_collapse ( ECM& aSurface
|
||||
, ShouldStop const& aShould_stop
|
||||
|
||||
// optional mesh information policies
|
||||
, VertexPointMap const& aVertex_point_map // defaults to get(Vertex_point,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)
|
||||
|
||||
// optional strategy policies - defaults to LindstomTurk
|
||||
, GetCost const& aGet_cost
|
||||
, GetPlacement const& aGet_placement
|
||||
, CostParams const* aCostParams // Can be NULL
|
||||
, PlacementParams const* aPlacementParams // Can be NULL
|
||||
|
||||
, Visitor* aVisitor // Can be NULL
|
||||
)
|
||||
{
|
||||
typedef EdgeCollapse< ECM
|
||||
, ShouldStop
|
||||
, VertexPointMap
|
||||
, VertexIndexMap
|
||||
, EdgeIndexMap
|
||||
, EdgeIsBorderMap
|
||||
, GetCost
|
||||
, GetPlacement
|
||||
, CostParams
|
||||
, PlacementParams
|
||||
, Visitor
|
||||
>
|
||||
Algorithm
|
||||
|
|
@ -106,13 +67,11 @@ int edge_collapse ( ECM& aSurface
|
|||
|
||||
Algorithm algorithm( aSurface
|
||||
, aShould_stop
|
||||
, aVertex_point_map
|
||||
, aVertex_index_map
|
||||
, aEdge_index_map
|
||||
, aEdge_is_border_map
|
||||
, aGet_cost
|
||||
, aGet_placement
|
||||
, aCostParams
|
||||
, aPlacementParams
|
||||
, aVisitor
|
||||
) ;
|
||||
|
||||
|
|
@ -160,13 +119,11 @@ int edge_collapse ( ECM& aSurface
|
|||
|
||||
return edge_collapse(aSurface
|
||||
,aShould_stop
|
||||
,choose_const_pmap(get_param(aParams,vertex_point),aSurface,vertex_point)
|
||||
,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,get_cost_policy), LindstromTurk_cost<ECM>())
|
||||
,choose_param (get_param(aParams,get_placement_policy), LindstromTurk_placement<ECM>())
|
||||
,choose_param (get_param(aParams,get_cost_policy_params), &lPolicyParams)
|
||||
,choose_param (get_param(aParams,get_placement_policy_params), &lPolicyParams)
|
||||
,choose_param (get_param(aParams,vis), ((Dummy_visitor*)0))
|
||||
) ;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue