Skip to content

Commit

Permalink
Merge pull request #1052 from kerautret/CaliperCH
Browse files Browse the repository at this point in the history
Rotating Caliper in Hull2DHelpers
  • Loading branch information
dcoeurjo committed Oct 17, 2015
2 parents 43ac0f8 + 457580f commit e60d843
Show file tree
Hide file tree
Showing 13 changed files with 889 additions and 272 deletions.
13 changes: 11 additions & 2 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@

# DGtal 0.9.1

## New Features / Critical Changes
- *Geometry Package*
- Hull2DHelpers: implementation of the rotating caliper algorithm to compute
the width (vertical/horizontal or Euclidean) of a convex hull.
(Bertrand Kerautret, [#1052](https://github.com/DGtal-team/DGtal/pull/1052))

# DGtal 0.9

## New Features / Critical Changes
Expand All @@ -11,9 +20,9 @@
[catch](https://github.com/philsquared/Catch). Catch allows to
design quick and efficient unit tests with nice trace
outputs. (David Coeurjolly,
[#1019](https://github.com/DGtal-team/DGtal/pull/1019)
[#1019](https://github.com/DGtal-team/DGtal/pull/1019))
- Documentation added for Catch. (David Coeurjolly,
[#1042](https://github.com/DGtal-team/DGtal/pull/1042)
[#1042](https://github.com/DGtal-team/DGtal/pull/1042))


- *Kernel*
Expand Down
19 changes: 19 additions & 0 deletions examples/geometry/tools/exampleConvexHull2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,29 @@ void convexHull()
//! [Hull2D-AndrewAlgo]
andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate );
//! [Hull2D-AndrewAlgo]
//![Hull2D-Caliper-computeBasic]
double th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness);
//![Hull2D-Caliper-computeBasic]

//![Hull2D-Caliper-computeAnti]
Z2i::Point antipodalP, antipodalQ, antipodalS;
th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness, antipodalP, antipodalQ, antipodalS);
//![Hull2D-Caliper-computeAnti]


trace.info() <<" ConvexHull HV thickness: " << th << std::endl;
//display
Board2D board;
drawPolygon( res.begin(), res.end(), board );
//![Hull2D-Caliper-display]
board.setPenColor(DGtal::Color::Red);
board.drawCircle( antipodalS[0], antipodalS[1], 0.2) ;
board.setPenColor(DGtal::Color::Blue);
board.drawCircle(antipodalP[0], antipodalP[1], 0.2);
board.drawCircle(antipodalQ[0], antipodalQ[1], 0.2);
board.drawLine(antipodalP[0], antipodalP[1], antipodalQ[0], antipodalQ[1]);
//![Hull2D-Caliper-display]

board.saveSVG( "ConvexHullCCW.svg" );
#ifdef WITH_CAIRO
board.saveCairo("ConvexHullCCW.png", Board2D::CairoPNG);
Expand Down
8 changes: 8 additions & 0 deletions src/DGtal/doc/global.bib
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
%% Images
@Misc{belongieRotation,
author = {Belongie, Serge},
title = {Rodrigues' Rotation Formula.},
Expand All @@ -13,6 +14,13 @@ @Misc{belongieRotation

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Geometry/tools
@article{Shamos1978,
title = {Computational geometry.},
url = {http://dl.acm.org/citation.cfm?id=908431},
urldate = {2015-10-12},
author = {Shamos, Michael Ian},
year = {1978}
}

@article{graham1972,
author = "Graham, R.L.",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 56 additions & 1 deletion src/DGtal/geometry/doc/moduleHull2D.dox
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace DGtal {
//----------------------------------------
/*!
@page moduleHull2D Convex hull and alpha-shape in the plane
@writers Tristan Roussillon
@writers Tristan Roussillon, Bertrand Kerautret)
[TOC]

In this part of the manual, we describe how to compute
Expand Down Expand Up @@ -177,6 +177,61 @@ the on-line feature, you may call the off-line procedure melkmanConvexHullAlgori

@warning The behavior is undefined if the input points do not form a simple polygonal line.


\subsection subsectmoduleHull2D14 Convex hull thickness

From a convex hull it can be useful to compute its associated
thickness. We propose the implementation of the well known rotating
caliper algorithm allowing to compute all the antipodal pairs in
linear time [Shamos , 1978: \cite Shamos1978].

Two definitions of thickness can be computed from an iterator on the
convex hull. The first one is the vertical/horizontal thickness
obtained by projection on the main x-y axis from antipodal pairs. The
second one is given from the normal projection on the edge of the same
antipodal pairs. The two definitions are illustrated on the following figures:


@image html exampleConvexHullHV.png "Example of the definitiion of horizontal/vertical thickness defined from the convex hull antipodal pair ((P,Q), S)."
@image latex MelkmanHowTo.png "Example of the definitiion of horizontal/vertical thickness defined from the convex hull antipodal pair ((P,Q), S)."

@image html exampleConvexHullEucl.png "Example of the definitiion of Euclidean thickness defined from the convex hull antipodal pair ((P,Q), S)."
@image latex MelkmanHowTo.png "Example of the definitiion of horizontal/vertical thickness defined from the convex hull antipodal pair ((P,Q), S)"


To compute the thickness of a convex hull you have simply to call the computeHullThickness procedure:

@snippet geometry/tools/exampleConvexHull2D.cpp Hull2D-Caliper-computeBasic


To recover the antipodal pairs for which the thickness is minimal you
can also use the same method with an antipodal pair:

@snippet geometry/tools/exampleConvexHull2D.cpp Hull2D-Caliper-computeAnti

And display the result:
@snippet geometry/tools/exampleConvexHull2D.cpp Hull2D-Caliper-display


By using the sequence of points of the first example, you will obtain a thickness of 12 with the following antipodal pair:


@image html ConvexHullCCWAntiPodal.png "Example of antipodal pair obtained from the computation of the horizontal/vertical thickness. The edge (P, Q) of the antipodal pair is represented in blue and its vertex R is given in red."
@image latex ConvexHullCCWAntiPodal.png "Example of antipodal pair obtained from the computation of the horizontal/vertical thickness. The edge (P, Q) of the antipodal pair is represented in blue and its vertex R is given in red."


@warning The convex hull should be oriented in counter clockwise else it will return wrong result.











\section sectmoduleHull2D2 Alpha-shape

The alpha-shape of a finite set of points has been introduced in
Expand Down
2 changes: 1 addition & 1 deletion src/DGtal/geometry/doc/packageGeometry.dox
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ of arbitrary dimension, by the means of separable and incremental distance trans

- Tools
- \ref moduleGeometricPredicates (Tristan Roussillon)
- \ref moduleHull2D (Tristan Roussillon)
- \ref moduleHull2D (Tristan Roussillon, Bertrand Kerautret)


@b Package @b Concepts @b Overview
Expand Down
164 changes: 163 additions & 1 deletion src/DGtal/geometry/tools/Hull2DHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
* @author Tristan Roussillon (\c [email protected] )
* Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France
*
* @date 2013/12/02
* @author Bertrand Kerautret (\c [email protected])
* LORIA (CNRS, UMR 7503), University of Lorraine, France
* @date 2015/12/10
*
* Header file for module Hull2DHelpers.cpp
*
Expand Down Expand Up @@ -71,6 +73,10 @@ namespace DGtal
namespace Hull2D
{


/// The 2 thickness definitions.
enum ThicknessDefinition {HorizontalVerticalThickness, EuclideanThickness};


/**
* @brief Procedure that updates the hull when
Expand Down Expand Up @@ -352,6 +358,162 @@ namespace DGtal
const Predicate& aPredicate );


/**
* @brief Procedure to compute the convex hull thickness given
* from different definitions (Horizontal/vertical or Euclidean
* distances). It takes as input the vertices of the hull given
* by the range [@a itbn, @a ite). The procedure applies the
* classic rotating caliper to recover all anti-podal pairs.
*
* Typical use:
* @code
* typedef PointVector<2,DGtal::int32_t> Point;
* typedef InHalfPlaneBySimple3x3Matrix<Point, DGtal::int32_t> Functor;
* DGtal::MelkmanConvexHull<Point, Functor> ch;
* ch.add(Point(0,0));
* ch.add(Point(11,1));
* ch.add(Point(12,3));
* ch.add(Point(8,3));
* ch.add(Point(4,5));
* ch.add(Point(2,6));
* ch.add(Point(1,4));
* double th = computeHullThickness(ch.begin(), ch.end(),
* DGtal::functions::Hull2D::EuclideanThickness);
* @endcode
* @param[in] itb begin iterator on the convex hull points.
* @param[in] ite end iterator on the convex hull points.
* @param[in] def definition of the thickness used in the estimation (i.e HorizontalVerticalThickness or EuclideanThickness)
*
* @note If the convex hull contains 0, 1 or 2 points the thickness of 0 is returned.
* @warning The convex hull should be oriented in counter clockwise else it will return wrong result.
**/
template <typename ForwardIterator >
double computeHullThickness(const ForwardIterator& itb,
const ForwardIterator& ite,
const ThicknessDefinition& def);


/**
* @brief Procedure to compute the convex hull thickness given
* from different definitions (Horizontal/vertical or Euclidean
* distances). It takes as input the vertices of the hull given
* by the range [@a itbn, @a ite). The procedure applies the
* classic rotating caliper to recover all anti-podal pairs.
*
* Typical use:
* @code
* typedef PointVector<2,DGtal::int32_t> Point;
* typedef InHalfPlaneBySimple3x3Matrix<Point, DGtal::int32_t> Functor;
* DGtal::MelkmanConvexHull<Point, Functor> ch;
* ch.add(Point(0,0));
* ch.add(Point(11,1));
* ch.add(Point(12,3));
* ch.add(Point(8,3));
* ch.add(Point(4,5));
* ch.add(Point(2,6));
* ch.add(Point(1,4));
* Point p, q, s;
* double th = computeHullThickness(ch.begin(), ch.end(),
* DGtal::functions::Hull2D::EuclideanThickness, p, q, s);
* @endcode
* @param[in] itb begin iterator on the convex hull points.
* @param[in] ite end iterator on the convex hull points.
* @param[in] def definition of the thickness used in the estimation (i.e HorizontalVerticalThickness or EuclideanThickness)
* @param[out] antipodalEdgeP one point of the antipodal edge associated to the minimal value of convex hull thickness.
* @param[out] antipodalEdgeQ one point of the antipodal edge associated to the minimal value of convex hull thickness.
* @param[out] antipodalVertexR the vertex of the antipodal pair associated to the minimal value of convex hull thickness.
* @note If the convex hull contains 0, 1 or 2 points the thickness of 0 is returned and the antipodal points are updated with the first points (if they exist).
* @warning The convex hull should be oriented in counter clockwise else it will return wrong result.
**/
template <typename ForwardIterator,
typename TInputPoint >
double computeHullThickness(const ForwardIterator& itb,
const ForwardIterator& ite,
const ThicknessDefinition& def,
TInputPoint& antipodalEdgeP,
TInputPoint& antipodalEdgeQ,
TInputPoint& antipodalVertexR);


/**
* Computes the angle between the line (@a a,@a b) and (@a c,@a d)
* @param[in] a one of point defining the first line.
* @param[in] b a second point defining the first line.
* @param[in] c a third point defining the second line.
* @param[in] d a third point defining the second line.
**/
template<typename TInputPoint>
inline
double getAngle(const TInputPoint& a, const TInputPoint& b,const TInputPoint& c,const TInputPoint& d);

/**
* Computes the thickness of an anti podal pair (represented by
* the segment [ @a p , @a q ] and vertex @a r) according to the given
* distance @def definition.
*
* If the distance definition is @HorizontalVerticalThickness, it
* returns the minimal distance between the vertical/horizontal
* projection of @r on ( @a p , @a q ).
*
* If the distance definition is @EuclideanThickness, it returns
* the distance between r and its projection on the line ( @a p ,@a q ).
*
* @param[in] p the first point of the edge anti podal pair.
* @param[in] q the second point of the edge anti podal pair.
* @param[in] r the vertex of the anti podal pair.
* @param[in] def definition of the thickness used in the estimation (i.e HorizontalVerticalThickness or EuclideanThickness).
*
**/
template<typename TInputPoint>
double getThicknessAntipodalPair(const TInputPoint& p, const TInputPoint& q,
const TInputPoint& r, const ThicknessDefinition& def);

/**
* Computes the horizontal distance a point @c according to the segment [ @a a , @a b ].
* (i.e the horizontal projection distance of @c on [ @a a , @a b ]).
* @note if the segment [@a a, @a b] is horizontal (i.e @a a [1]==@a b[1]) then an infinite value (std::numerics<double>::max()) is returned.
*
* @param[in] a one point of the segment.
* @param[in] b a second point of the segment.
* @param[in] c the point for which the horizontal distance is computed.
* @param[out] isInside indicates if the projected point is inside the segment or not.
**/
template< typename TInputPoint>
double
computeHProjDistance(const TInputPoint& a, const TInputPoint& b, const TInputPoint& c, bool& isInside );


/**
* Computes the vertical distance a point @c according to the segment [@a a, @a b].
* (i.e the vertical projection distance of @c on [@a a,@a b].
* @note if the segment [@a a, @a b] is vertical (i.e @a a [0]== @a b [0]) then an infinite value (std::numerics<double>::max()) is returned.
*
* @param[in] a one point of the segment.
* @param[in] b a second point of the segment.
* @param[in] c the point for which the vertical distance is computed.
* @param[out] isInside indicates if the projected point is inside the segment or not.
**/
template< typename TInputPoint>
double
computeVProjDistance(const TInputPoint& a, const TInputPoint& b, const TInputPoint& c, bool& isInside );


/**
* Computes the euclidean distance a point @a c according to the segment [@a a, @a b].
* (i.e the distance between @a c and its projected point on [@a a,@a b].
*
* @param[in] a one point of the segment.
* @param[in] b a second point of the segment.
* @param[in] c the point for which the vertical distance is computed.
* @param[out] isInside indicates if the projected point is inside the segment or not.
**/
template< typename TInputPoint>
double
computeEuclideanDistance(const TInputPoint& a, const TInputPoint& b, const TInputPoint& c, bool& isInside );



} // namespace convexHull2D

} // namespace functions
Expand Down
Loading

0 comments on commit e60d843

Please sign in to comment.