Edge_profile added

This commit is contained in:
Fernando Cacciola 2006-11-17 17:16:44 +00:00
parent 81f0f74829
commit 77348ee54d
26 changed files with 375 additions and 828 deletions

View File

@ -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 ;

View File

@ -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 ;

View File

@ -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

View File

@ -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}

View File

@ -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>}.

View File

@ -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}

View File

@ -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}

View File

@ -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>}

View File

@ -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}

View File

@ -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}

View File

@ -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.
}

View File

@ -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.

View File

@ -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

View File

@ -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 ===

View File

@ -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>

View File

@ -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:

View File

@ -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") ;

View File

@ -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

View File

@ -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

View File

@ -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 ;
};

View File

@ -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 ;

View File

@ -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()));
}
};

View File

@ -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

View File

@ -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 ;
};

View File

@ -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

View File

@ -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))
) ;