From 1a08945ee6d522899e65285f2361ac9fbf0d5f4b Mon Sep 17 00:00:00 2001
From: evenp <Philippe.Even@loria.fr>
Date: Thu, 10 Dec 2020 20:16:15 +0100
Subject: [PATCH] New comparisons with other detectors added in Expes

---
 Code/FBSD/BlurredSegment/bsdetector.cpp       |   2 +-
 Code/FBSD/BlurredSegment/nfafilter.cpp        |   9 +-
 .../ImageTools/digitalstraightsegment.cpp     |  20 +-
 Code/FBSD/ImageTools/digitalstraightsegment.h |  24 +-
 Expes/Testers/TestLines/.qmake.stash          |  23 +
 .../TestLines/BlurredSegment/biptlist.cpp     | 256 ++++++
 .../TestLines/BlurredSegment/biptlist.h       | 146 +++
 .../BlurredSegment/blurredsegment.cpp         | 328 +++++++
 .../TestLines/BlurredSegment/blurredsegment.h | 238 +++++
 .../BlurredSegment/blurredsegmentproto.cpp    | 294 +++++++
 .../BlurredSegment/blurredsegmentproto.h      | 139 +++
 .../TestLines/BlurredSegment/bsdetector.cpp   | 577 ++++++++++++
 .../TestLines/BlurredSegment/bsdetector.h     | 623 +++++++++++++
 .../TestLines/BlurredSegment/bsproto.cpp      | 319 +++++++
 .../TestLines/BlurredSegment/bsproto.h        | 165 ++++
 .../TestLines/BlurredSegment/bstracker.cpp    | 422 +++++++++
 .../TestLines/BlurredSegment/bstracker.h      | 200 +++++
 .../Testers/TestLines/BlurredSegment/changed  |  14 +
 .../TestLines/BlurredSegment/nfafilter.cpp    | 139 +++
 .../TestLines/BlurredSegment/nfafilter.h      |  94 ++
 .../TestLines/BlurredSegment/rechanged        |  12 +
 .../TestLines/ConvexHull/antipodal.cpp        | 335 +++++++
 .../Testers/TestLines/ConvexHull/antipodal.h  | 135 +++
 Expes/Testers/TestLines/ConvexHull/changed    |   6 +
 .../Testers/TestLines/ConvexHull/chvertex.cpp |  36 +
 Expes/Testers/TestLines/ConvexHull/chvertex.h |  92 ++
 .../TestLines/ConvexHull/convexhull.cpp       | 261 ++++++
 .../Testers/TestLines/ConvexHull/convexhull.h | 195 ++++
 Expes/Testers/TestLines/ConvexHull/rechanged  |   6 +
 .../DirectionalScanner/adaptivescannero1.cpp  | 262 ++++++
 .../DirectionalScanner/adaptivescannero1.h    | 138 +++
 .../DirectionalScanner/adaptivescannero2.cpp  | 256 ++++++
 .../DirectionalScanner/adaptivescannero2.h    | 140 +++
 .../DirectionalScanner/adaptivescannero7.cpp  | 256 ++++++
 .../DirectionalScanner/adaptivescannero7.h    | 139 +++
 .../DirectionalScanner/adaptivescannero8.cpp  | 262 ++++++
 .../DirectionalScanner/adaptivescannero8.h    | 138 +++
 .../TestLines/DirectionalScanner/changed      |  28 +
 .../DirectionalScanner/directionalscanner.cpp |  22 +
 .../DirectionalScanner/directionalscanner.h   | 157 ++++
 .../directionalscannero1.cpp                  | 337 +++++++
 .../DirectionalScanner/directionalscannero1.h | 131 +++
 .../directionalscannero2.cpp                  | 335 +++++++
 .../DirectionalScanner/directionalscannero2.h | 131 +++
 .../directionalscannero7.cpp                  | 335 +++++++
 .../DirectionalScanner/directionalscannero7.h | 131 +++
 .../directionalscannero8.cpp                  | 335 +++++++
 .../DirectionalScanner/directionalscannero8.h | 131 +++
 .../TestLines/DirectionalScanner/rechanged    |  28 +
 .../DirectionalScanner/scannerprovider.cpp    | 194 ++++
 .../DirectionalScanner/scannerprovider.h      |  93 ++
 .../DirectionalScanner/vhscannero1.cpp        | 194 ++++
 .../DirectionalScanner/vhscannero1.h          | 113 +++
 .../DirectionalScanner/vhscannero2.cpp        | 194 ++++
 .../DirectionalScanner/vhscannero2.h          | 113 +++
 .../DirectionalScanner/vhscannero7.cpp        | 194 ++++
 .../DirectionalScanner/vhscannero7.h          | 113 +++
 .../DirectionalScanner/vhscannero8.cpp        | 194 ++++
 .../DirectionalScanner/vhscannero8.h          | 113 +++
 Expes/Testers/TestLines/ImageTools/absrat.h   |  71 ++
 Expes/Testers/TestLines/ImageTools/changed    |  13 +
 .../ImageTools/digitalstraightline.cpp        | 460 ++++++++++
 .../ImageTools/digitalstraightline.h          | 255 ++++++
 .../ImageTools/digitalstraightsegment.cpp     | 277 ++++++
 .../ImageTools/digitalstraightsegment.h       | 181 ++++
 Expes/Testers/TestLines/ImageTools/edist.cpp  |  22 +
 Expes/Testers/TestLines/ImageTools/edist.h    | 154 ++++
 Expes/Testers/TestLines/ImageTools/pt2i.cpp   | 832 ++++++++++++++++++
 Expes/Testers/TestLines/ImageTools/pt2i.h     | 195 ++++
 Expes/Testers/TestLines/ImageTools/rechanged  |  13 +
 Expes/Testers/TestLines/ImageTools/vmap.cpp   | 769 ++++++++++++++++
 Expes/Testers/TestLines/ImageTools/vmap.h     | 393 +++++++++
 Expes/Testers/TestLines/ImageTools/vr2i.cpp   |  70 ++
 Expes/Testers/TestLines/ImageTools/vr2i.h     | 156 ++++
 Expes/Testers/TestLines/Images/couloir.gif    | Bin 0 -> 113589 bytes
 Expes/Testers/TestLines/TestLines.pro         |  74 ++
 Expes/Testers/TestLines/main.cpp              | 305 +++++++
 Expes/YorkUrbanDB/Scripts/precstat.sh         |  17 +
 Expes/YorkUrbanDB/Scripts/precstats.sh        | 112 +++
 Expes/YorkUrbanDB/Scripts/ytimes.c            | 159 ++++
 Expes/YorkUrbanDB/data/moyennes/mprec.c       | 136 +++
 Ipol/paper/Algos/algoAuto.tex                 |   2 +-
 Ipol/paper/Algos/algoInitial.tex              |  12 +-
 Ipol/paper/Algos/algoMulti.tex                |   2 +-
 Ipol/paper/Algos/algoSingle.tex               |   7 +-
 Ipol/paper/algos.tex                          |  32 +-
 Methode/evals.tex                             |  30 +-
 87 files changed, 15030 insertions(+), 36 deletions(-)
 create mode 100644 Expes/Testers/TestLines/.qmake.stash
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/biptlist.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/biptlist.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/blurredsegment.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/blurredsegment.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bsdetector.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bsdetector.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bsproto.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bsproto.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bstracker.cpp
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/bstracker.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/changed
 create mode 100755 Expes/Testers/TestLines/BlurredSegment/nfafilter.cpp
 create mode 100755 Expes/Testers/TestLines/BlurredSegment/nfafilter.h
 create mode 100644 Expes/Testers/TestLines/BlurredSegment/rechanged
 create mode 100644 Expes/Testers/TestLines/ConvexHull/antipodal.cpp
 create mode 100644 Expes/Testers/TestLines/ConvexHull/antipodal.h
 create mode 100644 Expes/Testers/TestLines/ConvexHull/changed
 create mode 100644 Expes/Testers/TestLines/ConvexHull/chvertex.cpp
 create mode 100644 Expes/Testers/TestLines/ConvexHull/chvertex.h
 create mode 100644 Expes/Testers/TestLines/ConvexHull/convexhull.cpp
 create mode 100644 Expes/Testers/TestLines/ConvexHull/convexhull.h
 create mode 100644 Expes/Testers/TestLines/ConvexHull/rechanged
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/changed
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscanner.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscanner.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/rechanged
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/scannerprovider.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/scannerprovider.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero1.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero1.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero2.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero2.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero7.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero7.h
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero8.cpp
 create mode 100644 Expes/Testers/TestLines/DirectionalScanner/vhscannero8.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/absrat.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/changed
 create mode 100644 Expes/Testers/TestLines/ImageTools/digitalstraightline.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/digitalstraightline.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/digitalstraightsegment.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/digitalstraightsegment.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/edist.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/edist.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/pt2i.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/pt2i.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/rechanged
 create mode 100644 Expes/Testers/TestLines/ImageTools/vmap.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/vmap.h
 create mode 100644 Expes/Testers/TestLines/ImageTools/vr2i.cpp
 create mode 100644 Expes/Testers/TestLines/ImageTools/vr2i.h
 create mode 100644 Expes/Testers/TestLines/Images/couloir.gif
 create mode 100644 Expes/Testers/TestLines/TestLines.pro
 create mode 100644 Expes/Testers/TestLines/main.cpp
 create mode 100644 Expes/YorkUrbanDB/Scripts/precstat.sh
 create mode 100644 Expes/YorkUrbanDB/Scripts/precstats.sh
 create mode 100644 Expes/YorkUrbanDB/Scripts/ytimes.c
 create mode 100644 Expes/YorkUrbanDB/data/moyennes/mprec.c

diff --git a/Code/FBSD/BlurredSegment/bsdetector.cpp b/Code/FBSD/BlurredSegment/bsdetector.cpp
index 545c181..6b6a4b0 100755
--- a/Code/FBSD/BlurredSegment/bsdetector.cpp
+++ b/Code/FBSD/BlurredSegment/bsdetector.cpp
@@ -48,7 +48,7 @@ BSDetector::BSDetector ()
   bst1 = new BSTracker ();
   bst2 = new BSTracker ();
 
-  nfaOn = false;
+  nfaOn = true;
   nfaf = NULL;
   nfaf = (nfaOn ? new NFAFilter () : NULL);
 
diff --git a/Code/FBSD/BlurredSegment/nfafilter.cpp b/Code/FBSD/BlurredSegment/nfafilter.cpp
index 8a676d4..e525eb5 100755
--- a/Code/FBSD/BlurredSegment/nfafilter.cpp
+++ b/Code/FBSD/BlurredSegment/nfafilter.cpp
@@ -82,7 +82,7 @@ bool NFAFilter::filter (const BlurredSegment *bs, int start, int end)
 
   // Gets point with small gradient
   int gmin = max_grad2;
-  int pmin = -1;
+//  int pmin = -1;
   std::vector<Pt2i> pts = bs->getAllPoints ();
   for (int i = start; i < end; i++)
   {
@@ -90,14 +90,15 @@ bool NFAFilter::filter (const BlurredSegment *bs, int start, int end)
     if (gn < gmin)
     {
       gmin = gn;
-      pmin = i;
+//      pmin = i;
     }
   }
 
   // Gets NFA and accept or split the segment
   double nfa = nfaValue (cum_histo[(int) (sqrt (gmin))], length);
-  if (nfa < NFA_EPSILON) return true;
-  return (filter (bs, start, pmin) && filter (bs, pmin + 1, end));
+  return (nfa < NFA_EPSILON);
+//  if (nfa < NFA_EPSILON) return true;
+//  return (filter (bs, start, pmin) && filter (bs, pmin + 1, end));
 }
 
 
diff --git a/Code/FBSD/ImageTools/digitalstraightsegment.cpp b/Code/FBSD/ImageTools/digitalstraightsegment.cpp
index 581250b..c2b509f 100755
--- a/Code/FBSD/ImageTools/digitalstraightsegment.cpp
+++ b/Code/FBSD/ImageTools/digitalstraightsegment.cpp
@@ -222,17 +222,25 @@ DigitalStraightSegment *DigitalStraightSegment::dilation (
 }
 
 
-DigitalStraightSegment *DigitalStraightSegment::dilation (int radius) const
+DigitalStraightSegment *DigitalStraightSegment::dilation (int ar_width) const
 {
-  return (new DigitalStraightSegment (a, b, c - radius,
-                                      nu + 2 * radius, min, max));
+  return (new DigitalStraightSegment (a, b, c - ar_width,
+                                      nu + 2 * ar_width, min, max));
 }
 
 
-void DigitalStraightSegment::dilate (int radius)
+void DigitalStraightSegment::dilate (int ar_width)
 {
-  nu += 2 * radius;
-  c -= radius;
+  nu += 2 * ar_width;
+  c -= ar_width;
+}
+
+
+void DigitalStraightSegment::setNaive ()
+{
+  int p = period ();
+  c += (nu - p) / 2;
+  nu = p;
 }
 
 
diff --git a/Code/FBSD/ImageTools/digitalstraightsegment.h b/Code/FBSD/ImageTools/digitalstraightsegment.h
index 5c774a4..891b6a2 100755
--- a/Code/FBSD/ImageTools/digitalstraightsegment.h
+++ b/Code/FBSD/ImageTools/digitalstraightsegment.h
@@ -24,7 +24,10 @@ public:
   DigitalStraightSegment ();
 
   /**
-   * \brief Creates a null-thick segment joining two points.
+   * \brief Creates a null-thick segment passing through two points.
+   * Caution: the segment ends on given min-max bounds !
+   * To create a segment ending on the two points, use constructor with
+   * two points and width instead.
    * @param p1 First point on the line.
    * @param p2 Second point on the line.
    * @param type Digital line type : DSL_THIN, DSL_NAIVE or DSL_STANDARD.
@@ -53,7 +56,7 @@ public:
    * \brief Creates a digital straight segment from end points and width.
    * @param p1 First end point of the segment.
    * @param p2 Second end point of the segment.
-   * @param width Width value.
+   * @param width Width value: 1 for a naive line.
    */
   DigitalStraightSegment (Pt2i p1, Pt2i p2, int width);
 
@@ -107,16 +110,21 @@ public:
   DigitalStraightSegment *dilation (int num, int den) const;
 
   /**
-   * \brief Returns a dilated segment of given radius.
-   * @param radius Dilation radius.
+   * \brief Returns a dilated segment of given arithmetical width on each side.
+   * @param radius Dilation arithmetical width.
    */
-  DigitalStraightSegment *dilation (int radius) const;
+  DigitalStraightSegment *dilation (int ar_width) const;
 
   /**
-   * \brief Dilates the segment of given radius.
-   * @param radius Dilation radius.
+   * \brief Dilates the segment of given arithmetical width on each side.
+   * @param radius Dilation arithmetical width.
    */
-  void dilate (int radius);
+  void dilate (int ar_width);
+
+  /**
+   * \brief Erodes the segment to its naive center line.
+   */
+  void setNaive ();
 
   /**
    * \brief Inquires if given point belongs to a dilation of the segment.
diff --git a/Expes/Testers/TestLines/.qmake.stash b/Expes/Testers/TestLines/.qmake.stash
new file mode 100644
index 0000000..d6e97ef
--- /dev/null
+++ b/Expes/Testers/TestLines/.qmake.stash
@@ -0,0 +1,23 @@
+QMAKE_CXX.QT_COMPILER_STDCXX = 201402L
+QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 9
+QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 3
+QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
+QMAKE_CXX.COMPILER_MACROS = \
+    QT_COMPILER_STDCXX \
+    QMAKE_GCC_MAJOR_VERSION \
+    QMAKE_GCC_MINOR_VERSION \
+    QMAKE_GCC_PATCH_VERSION
+QMAKE_CXX.INCDIRS = \
+    /usr/include/c++/9 \
+    /usr/include/x86_64-linux-gnu/c++/9 \
+    /usr/include/c++/9/backward \
+    /usr/lib/gcc/x86_64-linux-gnu/9/include \
+    /usr/local/include \
+    /usr/include/x86_64-linux-gnu \
+    /usr/include
+QMAKE_CXX.LIBDIRS = \
+    /usr/lib/gcc/x86_64-linux-gnu/9 \
+    /usr/lib/x86_64-linux-gnu \
+    /usr/lib \
+    /lib/x86_64-linux-gnu \
+    /lib
diff --git a/Expes/Testers/TestLines/BlurredSegment/biptlist.cpp b/Expes/Testers/TestLines/BlurredSegment/biptlist.cpp
new file mode 100644
index 0000000..e416c26
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/biptlist.cpp
@@ -0,0 +1,256 @@
+#include "biptlist.h"
+
+
+BiPtList::BiPtList (Pt2i pt)
+{
+  pts.push_back (pt);
+  start = 0;
+  cpt = 1;
+}
+
+
+BiPtList::~BiPtList ()
+{
+}
+
+
+void BiPtList::addFront (Pt2i pt)
+{
+  pts.push_front (pt);
+  start++;
+  cpt++;
+}
+
+
+void BiPtList::addBack (Pt2i pt)
+{
+  pts.push_back (pt);
+  cpt++;
+}
+
+
+void BiPtList::removeFront (int n)
+{
+  if (n >= frontSize ()) n = frontSize () - 1; // We keep at least one point
+  for (int i = 0; i < n; i++) pts.pop_front ();
+  cpt -= n;
+  start -= n;
+  if (start < 0) start = 0; // Theoretically impossible
+}
+
+
+void BiPtList::removeBack (int n)
+{
+  if (n >= backSize ()) n = backSize () - 1;  // We keep at least one point
+  for (int i = 0; i < n; i++) pts.pop_back ();
+  cpt -= n;
+  if (start >= cpt) start = cpt - 1;  // Theoretically impossible
+}
+
+
+void BiPtList::findExtrema (int &xmin, int &ymin, int &xmax, int &ymax) const
+{
+  std::deque<Pt2i>::const_iterator it = pts.begin ();
+  xmin = it->x ();
+  ymin = it->y ();
+  xmax = it->x ();
+  ymax = it->y ();
+  while (it != pts.end ())
+  {
+    if (xmin > it->x ()) xmin = it->x ();
+    if (xmax < it->x ()) xmax = it->x ();
+    if (ymin > it->y ()) ymin = it->y ();
+    if (ymax < it->y ()) ymax = it->y ();
+    it++;
+  }
+}
+
+
+std::vector<Pt2i> BiPtList::frontToBackPoints () const
+{
+  std::vector<Pt2i> res;
+  for (std::deque<Pt2i>::const_iterator it = pts.begin ();
+       it != pts.end (); it++)
+    res.push_back (*it);
+  return (res);
+}
+
+
+std::vector<Pt2i> *BiPtList::emptyVector () const
+{
+  return (new std::vector<Pt2i> ());
+}
+
+
+std::vector<Pt2i> *BiPtList::frontPoints () const
+{
+  // Entered from extremity to center : relevant ?
+  std::vector<Pt2i> *res = new std::vector<Pt2i> ();
+  std::deque<Pt2i>::const_iterator it = pts.begin ();
+  for (int i = 0; i < start; i++) res->push_back (*it++);
+  return res;
+}
+
+
+std::vector<Pt2i> *BiPtList::backPoints () const
+{
+  std::vector<Pt2i> *res = new std::vector<Pt2i> ();
+  std::deque<Pt2i>::const_iterator it = pts.begin ();
+  it += start + 1;
+  for (int i = 0; i < cpt - start - 1; i++) res->push_back (*it++);
+  return res;
+}
+
+
+EDist BiPtList::heightToEnds (const Pt2i &pt) const
+{
+  EDist xh = xHeightToEnds (pt);
+  EDist yh = yHeightToEnds (pt);
+  return (xh.lessThan (yh) ? xh : yh);
+}
+
+
+EDist BiPtList::xHeightToEnds (const Pt2i &pt) const
+{
+  int xp = pt.x (), yp = pt.y ();
+  int p1x = pts.front().x (), p1y = pts.front().y ();
+  int p2x = pts.back().x (), p2y = pts.back().y ();
+  int ax, ay, bx, by, cx, cy;
+
+  if (xp < p1x)
+  {
+    if (xp < p2x)
+    {
+      ax = xp;
+      ay = yp;
+      if (p1x < p2x)
+      {
+        bx = p1x;
+        by = p1y;
+        cx = p2x;
+        cy = p2y;
+      }
+      else
+      {
+        bx = p2x;
+        by = p2y;
+        cx = p1x;
+        cy = p1y;
+      }
+    }
+    else
+    {
+      ax = p2x;
+      ay = p2y;
+      bx = xp;
+      by = yp;
+      cx = p1x;
+      cy = p1y;
+    }
+  }
+  else
+  { 
+    if (xp < p2x) 
+    { 
+      ax = p1x; 
+      ay = p1y; 
+      bx = xp; 
+      by = yp; 
+      cx = p2x; 
+      cy = p2y; 
+    } 
+    else
+    { 
+      cx = xp; 
+      cy = yp; 
+      if (p1x < p2x) 
+      { 
+        ax = p1x; 
+        ay = p1y; 
+        bx = p2x; 
+        by = p2y; 
+      } 
+      else 
+      { 
+        ax = p2x; 
+        ay = p2y; 
+        bx = p1x; 
+        by = p1y; 
+      } 
+    } 
+  } 
+  return (EDist ((bx - ax) * (cy - ay) - (by - ay) * (cx - ax), cx - ax));
+}
+
+
+EDist BiPtList::yHeightToEnds (const Pt2i &pt) const
+{
+  int xp = pt.x (), yp = pt.y ();
+  int p1x = pts.front().x (), p1y = pts.front().y ();
+  int p2x = pts.back().x (), p2y = pts.back().y ();
+  int ax, ay, bx, by, cx, cy;
+
+  if (yp < p1y)
+  {
+    if (yp < p2y)
+    {
+      ax = xp;
+      ay = yp;
+      if (p1y < p2y)
+      {
+        bx = p1x;
+        by = p1y;
+        cx = p2x;
+        cy = p2y;
+      }
+      else
+      {
+        bx = p2x;
+        by = p2y;
+        cx = p1x;
+        cy = p1y;
+      }
+    }
+    else
+    {
+      ax = p2x;
+      ay = p2y;
+      bx = xp;
+      by = yp;
+      cx = p1x;
+      cy = p1y;
+    }
+  }
+  else
+  {
+    if (yp < p2y)
+    {
+      ax = p1x;
+      ay = p1y;
+      bx = xp;
+      by = yp;
+      cx = p2x;
+      cy = p2y;
+    }
+    else
+    {
+      cx = xp;
+      cy = yp;
+      if (p1y < p2y)
+      {
+        ax = p1x;
+        ay = p1y;
+        bx = p2x;
+        by = p2y;
+      }
+      else
+      {
+        ax = p2x;
+        ay = p2y;
+        bx = p1x;
+        by = p1y;
+      }
+    }
+  }
+  return (EDist ((bx - ax) * (cy - ay) - (by - ay) * (cx - ax), cy - ay));
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/biptlist.h b/Expes/Testers/TestLines/BlurredSegment/biptlist.h
new file mode 100644
index 0000000..417d8b8
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/biptlist.h
@@ -0,0 +1,146 @@
+#ifndef BIPT_LIST_H
+#define BIPT_LIST_H
+
+#include "pt2i.h"
+#include "edist.h"
+#include <deque>
+
+
+/** 
+ * @class BiPtList biptlist.h
+ * \brief Bi-directional list of points.
+ */
+class BiPtList
+{
+public:
+
+  /**
+   * \brief Creates a extendable bi-directional list with one point.
+   * @param pt Initial point of the list.
+   */
+  BiPtList (Pt2i pt);
+
+  /**
+   * \brief Deletes the bi-directional list.
+   */
+  ~BiPtList ();
+
+  /**
+   * \brief Returns the count of point in the bi-directional list.
+   */
+  inline int size () const { return (cpt); }
+
+  /**
+   * \brief Returns the count of point on back part of bi-directional list.
+   */
+  inline int backSize () const { return (cpt - start - 1); }
+
+  /**
+   * \brief Returns the count of point on front part of bi-directional list.
+   */
+  inline int frontSize () const { return (start); }
+
+  /**
+   * \brief Returns the initial point of the bi-directional list.
+   */
+  inline Pt2i initialPoint () const { return (pts[start]); }
+
+  /**
+   * \brief Returns the back end point of the bi-directional list.
+   */
+  inline Pt2i backPoint () const { return (pts.back ()); }
+
+  /**
+   * \brief Returns the front end point of the bi-directional list.
+   */
+  inline Pt2i frontPoint () const { return (pts.front ()); }
+
+  /**
+   * \brief Returns a point Manhattan height to the line between end points.
+   * Manhattan height is the lowest value of horizontal or vertical height.
+   * @param pt Tested point.
+   */
+  EDist heightToEnds (const Pt2i &pt) const;
+
+  /**
+   * \brief Adds a point on front side.
+   * @param pt Point to add.
+   */
+  void addFront (Pt2i pt);
+
+  /**
+   * \brief Adds a point on back side.
+   * @param pt Point to add.
+   */
+  void addBack (Pt2i pt);
+
+  /**
+   * \brief Removes points on front side.
+   * @param n The amount of points to remove.
+   */
+  void removeFront (int n);
+
+  /**
+   * \brief Removes points on back side.
+   * @param n The amount of points to remove.
+   */
+  void removeBack (int n);
+
+  /**
+   * \brief Sets given parameters with point min and max coordinates.
+   * @param xmin Minimum X value to set.
+   * @param ymin Minimum Y value to set.
+   * @param xmax Maximum X value to set.
+   * @param ymax Maximum Y value to set.
+   */
+  void findExtrema (int &xmin, int &ymin, int &xmax, int &ymax) const;
+
+  /**
+   * \brief Returns front to back points in a vector.
+   */
+  std::vector<Pt2i> frontToBackPoints () const;
+
+  /**
+   * \brief Returns a pointer to a empty vector of points.
+   */
+  std::vector<Pt2i> *emptyVector () const;
+
+  /**
+   * \brief Returns a pointer to a vector containing front points.
+   * Front points are entered from segment edge to the initial point excluded.
+   */
+  std::vector<Pt2i> *frontPoints () const;
+
+  /**
+   * \brief Returns a pointer to a vector containing back points.
+   * Back points are entered from initial point excluded to segment edge.
+   */
+  std::vector<Pt2i> *backPoints () const;
+
+
+private:
+
+  /** List of points. */
+  std::deque<Pt2i> pts;
+  /** Index of the initial point. */
+  int start;
+  /** Length of the point list. */
+  int cpt;
+
+
+  /**
+   * \brief Returns a point X-height to the line between list end points.
+   * X-height is the horizontal distance.
+   * @param pt Tested point.
+   */
+  EDist xHeightToEnds (const Pt2i &pt) const;
+
+  /**
+   * \brief Returns a point Y-height to the line between list end points.
+   * Y-height is the vertical distance.
+   * @param pt Tested point.
+   */
+  EDist yHeightToEnds (const Pt2i &pt) const;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/blurredsegment.cpp b/Expes/Testers/TestLines/BlurredSegment/blurredsegment.cpp
new file mode 100644
index 0000000..81e8e20
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/blurredsegment.cpp
@@ -0,0 +1,328 @@
+#include "blurredsegment.h"
+
+
+BlurredSegment::BlurredSegment ()
+{
+  plist = NULL;
+  dss = NULL;
+  scan = NULL;
+}
+
+
+BlurredSegment::BlurredSegment (BiPtList *ptlist, DigitalStraightSegment *seg,
+                                const Pt2i &aps, const Pt2i &ape,
+                                const Pt2i &apv)
+{
+  plist = ptlist;
+  dss = seg;
+  scan = NULL;
+  laps.set (aps);
+  lape.set (ape);
+  lapv.set (apv);
+}
+
+
+BlurredSegment::~BlurredSegment ()
+{
+  if (plist != NULL) delete plist;
+  if (dss != NULL) delete dss;
+  if (scan != NULL) delete scan;
+}
+
+
+void BlurredSegment::setScan (const Pt2i &pt1, const Pt2i &pt2)
+{
+  scan = new DigitalStraightLine (pt1, pt2, DigitalStraightLine::DSL_NAIVE);
+}
+
+
+void BlurredSegment::setScan (const Pt2i &center, const Vr2i &dir)
+{
+  Pt2i p2 (center.x () + dir.x (), center.y () + dir.y ());
+  scan = new DigitalStraightLine (center, p2, DigitalStraightLine::DSL_NAIVE);
+}
+
+
+EDist BlurredSegment::minimalWidth () const
+{
+  return (EDist (dss->width (), dss->period ()));
+}
+
+
+std::vector<Pt2i> BlurredSegment::getAllPoints () const
+{
+  return (plist->frontToBackPoints ());
+}
+
+
+std::vector<Pt2i> *BlurredSegment::getAllRight () const
+{
+  return (plist->backPoints ());
+}
+
+
+std::vector<Pt2i> *BlurredSegment::getAllLeft () const
+{
+  return (plist->frontPoints ());
+}
+
+
+DigitalStraightSegment *BlurredSegment::holdSegment ()
+{
+  DigitalStraightSegment *tmp = dss;
+  dss = NULL;
+  return tmp;
+}
+
+
+int BlurredSegment::size () const
+{
+  return (plist->size ());
+}
+
+
+int BlurredSegment::extent () const
+{
+  int l = 0;
+  if (scan != NULL)
+  {
+    l = scan->pavingIndex (plist->backPoint ())
+        + scan->pavingIndex (plist->frontPoint ());
+  }
+  else
+  {
+    Pt2i pr = plist->backPoint ();
+    Pt2i pl = plist->frontPoint ();
+    Pt2i c ((pr.x () + pl.x ()) / 2, (pr.y () + pl.y ()) / 2);
+    Pt2i d (c.x () + pl.y () - pr.y (), c.y () + pr.x () - pl.x ());
+    DigitalStraightLine line (c, d, DigitalStraightLine::DSL_NAIVE);
+    l = line.pavingIndex (plist->backPoint ())
+        + line.pavingIndex (plist->frontPoint ());
+  }
+  return (l < 0 ? 1 - l : 1 + l);
+}
+
+
+std::vector<Pt2i> BlurredSegment::getStartPt () const
+{
+  std::vector<Pt2i> res;
+  res.push_back (plist->initialPoint ());
+  return res;
+}
+
+
+const Pt2i BlurredSegment::getLastRight () const
+{
+  return (plist->backPoint ());
+}
+
+
+const Pt2i BlurredSegment::getLastLeft () const
+{
+  return (plist->frontPoint ());
+}
+
+
+int BlurredSegment::getSquarredLength () const
+{
+  Pt2i rp = plist->backPoint ();
+  Pt2i lp = plist->frontPoint ();
+  return ((rp.x () - lp.x ()) * (rp.x () - lp.x ())
+          + (rp.y () - lp.y ()) * (rp.y () - lp.y ()));
+}
+
+
+const Pt2i BlurredSegment::getMiddle () const
+{
+  Pt2i rp = plist->backPoint ();
+  Pt2i lp = plist->frontPoint ();
+  return (Pt2i ((rp.x () + lp.x ()) / 2, (rp.y () + lp.y ()) / 2));
+}
+
+
+Vr2i BlurredSegment::getSupportVector ()
+{
+  return (dss->supportVector ());
+}
+
+
+Vr2i BlurredSegment::boundingBoxSize () const
+{
+  int xmin, ymin, xmax, ymax;
+  plist->findExtrema (xmin, ymin, xmax, ymax);
+  return (Vr2i (xmax - xmin, ymax - ymin));
+}
+
+
+std::vector <std::vector <Pt2i> > BlurredSegment::connectedComponents () const
+{
+  std::vector <std::vector <Pt2i> > ccs;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    std::vector <Pt2i> cc;
+    bool started = false;
+    std::vector <Pt2i>::const_iterator it = pts.begin ();
+    Pt2i pix (*it++);
+    while (it != pts.end ())
+    {
+      if (it->isConnectedTo (pix))
+      {
+        if (! started)
+        {
+          cc.push_back (pix);
+          started = true;
+        }
+        cc.push_back (*it);
+      }
+      else
+      {
+        if (started)
+        {
+          ccs.push_back (cc);
+          cc.clear ();
+          started = false;;
+        }
+      }
+      pix.set (*it++);
+    }
+  }
+  return ccs;
+}
+
+
+int BlurredSegment::countOfConnectedPoints () const
+{
+  int count = 0;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    bool started = false;
+    std::vector <Pt2i>::const_iterator it = pts.begin ();
+    Pt2i pix (*it++);
+    while (it != pts.end ())
+    {
+      if (it->isConnectedTo (pix))
+      {
+        if (started) count ++;
+        else
+        {
+          count += 2;
+          started = true;
+        }
+      }
+      else
+      {
+        if (started) started = false;;
+      }
+      pix.set (*it++);
+    }
+  }
+  return count;
+}
+
+
+int BlurredSegment::countOfConnectedComponents () const
+{
+  int count = 0;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    bool started = false;
+    std::vector <Pt2i>::const_iterator it = pts.begin ();
+    Pt2i pix (*it++);
+    while (it != pts.end ())
+    {
+      if (it->isConnectedTo (pix))
+      {
+        if (! started)
+        {
+          count ++;
+          started = true;
+        }
+      }
+      else
+      {
+        if (started) started = false;;
+      }
+      pix.set (*it++);
+    }
+  }
+  return count;
+}
+
+
+int BlurredSegment::countOfConnectedPoints (int min) const
+{
+  int count = 0;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    int cpt = 1;
+    std::vector <Pt2i>::const_iterator it = pts.begin ();
+    Pt2i pix (*it++);
+    while (it != pts.end ())
+    {
+      if (it->isConnectedTo (pix))
+      {
+        if (++cpt == min) count += min;
+        else if (cpt > min) count ++;
+      }
+      else cpt = 1;
+      pix.set (*it++);
+    }
+  }
+  return count;
+}
+
+
+int BlurredSegment::countOfConnectedComponents (int min) const
+{
+  int count = 0;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    int cpt = 1;
+    std::vector <Pt2i>::const_iterator it = pts.begin ();
+    Pt2i pix (*it++);
+    while (it != pts.end ())
+    {
+      if (it->isConnectedTo (pix))
+      {
+        if (++cpt == min) count ++;
+      }
+      else cpt = 1;;
+      pix.set (*it++);
+    }
+  }
+  return count;
+}
+
+
+std::vector <std::vector <Pt2i> >
+BlurredSegment::getConnectedComponents () const
+{
+  std::vector <std::vector <Pt2i> > res;
+  std::vector <Pt2i> pts = getAllPoints ();
+  if (pts.size () > 1)
+  {
+    std::vector <Pt2i>::const_iterator bit = pts.begin ();
+    std::vector <Pt2i>::const_iterator eit = pts.end ();
+    while (bit != eit)
+    {
+      std::vector <Pt2i> lres;
+      Pt2i pix = *bit++;
+      bool compose = true;
+      do
+      {
+        lres.push_back (pix);
+        compose = bit->isConnectedTo (pix);
+        if (compose) pix.set (*bit++);
+      }
+      while (compose && bit != eit);
+      if (compose) lres.push_back (pix);
+      res.push_back (lres);
+    }
+  }
+  return res;
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/blurredsegment.h b/Expes/Testers/TestLines/BlurredSegment/blurredsegment.h
new file mode 100644
index 0000000..d7a7e07
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/blurredsegment.h
@@ -0,0 +1,238 @@
+#ifndef BLURRED_SEGMENT_H
+#define BLURRED_SEGMENT_H
+
+#include "convexhull.h"
+#include "digitalstraightsegment.h"
+#include "biptlist.h"
+
+
+/** 
+ * @class BlurredSegment blurredsegment.h
+ * \brief A set of 2D points lying inside a digital straight line.
+ */
+class BlurredSegment
+{
+public:
+
+  /**
+   * \brief Creates an empty blurred segment.
+   */
+  BlurredSegment ();
+
+  /**
+   * \brief Creates a blurred segment from a list of points.
+   * @param ptlist List of points of the blurred segment to build.
+   * @param seg Bounding digital straight segment.
+   * @param aps Start point of the antipodal edge.
+   * @param ape End point of the antipodal edge.
+   * @param apv Antipodal vertex.
+   */
+  BlurredSegment (BiPtList *ptlist, DigitalStraightSegment *seg,
+                  const Pt2i &aps, const Pt2i &ape, const Pt2i &apv);
+
+  /**
+   * \brief Deletes the blurred segment.
+   */
+  virtual ~BlurredSegment ();
+
+  /**
+   * \brief Sets the scan line used for detection.
+   * @param pt1 Scan start point.
+   * @param pt2 Scan end point.
+   */
+  virtual void setScan (const Pt2i &pt1, const Pt2i &pt2);
+
+  /**
+   * \brief Sets the scan line used for detection.
+   * @param center Scan center point.
+   * @param dir Scan line direction.
+   */
+  virtual void setScan (const Pt2i &center, const Vr2i &dir);
+
+  /**
+   * \brief Returns the minimal vertical or horizontal width.
+   */
+  virtual EDist minimalWidth () const;
+
+  /**
+   * \brief Returns if the segment has non null thickness (not aligned points).
+   */
+  inline bool isThick () const { return (dss->width () > 1); }
+
+  /**
+   * \brief Returns the optimal digital straight segment.
+   */
+  inline DigitalStraightSegment *getSegment () { return dss; }
+
+  /**
+   * \brief Returns a pointer to a copy of the optimal DSS.
+   */
+  DigitalStraightSegment *holdSegment ();
+
+  /**
+   * \brief Returns the count of points of the blurred segment.
+   */
+  int size () const;
+
+  /**
+   * \brief Returns the scan distance between end points.
+   */
+  int extent () const;
+
+  /**
+   * \brief Returns the start point of the blurred segment.
+   */
+  inline const Pt2i getCenter () const { return plist->initialPoint (); }
+
+  /**
+   * \brief Returns the colinear points at the left of the start point.
+   */
+  inline const std::vector<Pt2i> *getLeftLine () const {
+    return plist->emptyVector (); }
+
+  /**
+   * \brief Returns the colinear points at the right of the start point.
+   */
+  inline const std::vector<Pt2i> *getRightLine () const {
+    return plist->emptyVector (); }
+
+  /**
+   * \brief Returns the left points added to the blurred segment start point.
+   */
+  inline const std::vector<Pt2i> *getLeftPoints () const {
+    return plist->frontPoints (); }
+
+  /**
+   * \brief Returns the right points added to the blurred segment start point.
+   */
+  inline const std::vector<Pt2i> *getRightPoints () const {
+    return plist->backPoints (); }
+
+  /**
+   * \brief Returns the set of all the points on the blurred segment.
+   * Points are ordered from the left end point up to the right end point.
+   */
+  std::vector<Pt2i> getAllPoints () const;
+
+  /**
+   * \brief Returns the set of points on the left part of the blurred segment.
+   * Points are ordered from the furthest to the nearest to the start point.
+   */
+  std::vector<Pt2i> *getAllLeft () const;
+
+  /**
+   * \brief Returns the set of points on the left part of the blurred segment.
+   * Points are ordered from the nearest to the furthest to the start point.
+   */
+  std::vector<Pt2i> *getAllRight () const;
+
+  /**
+   * \brief Returns a vector containing the start point of the blurred segment.
+   */
+  std::vector<Pt2i> getStartPt () const;
+
+  /**
+   * \brief Returns the last accepted point on the right side. 
+   */
+  const Pt2i getLastRight () const;
+
+  /**
+   * \brief Returns the last accepted point on the left side. 
+   */
+  const Pt2i getLastLeft () const;
+
+  /**
+   * \brief Returns the squarred length of the blurred segment.
+   * Returns the squarred distance between end points.
+   */
+  int getSquarredLength () const;
+
+  /**
+   * \brief Returns the middle point of the blurred segment.
+   * Returns the middle point between end points.
+   */
+  const Pt2i getMiddle () const;
+
+  /**
+   * \brief Returns the start point of the last antipodal edge. 
+   */
+  inline const Pt2i antipodalEdgeStart () const { return laps; }
+
+  /**
+   * \brief Returns the end point of the last antipodal edge. 
+   */
+  inline const Pt2i antipodalEdgeEnd () const { return lape; }
+
+  /**
+   * \brief Returns the last antipodal vertex. 
+   */
+  inline const Pt2i antipodalVertex () const { return lapv; }
+
+  /**
+   * \brief Returns the support vector of the blurred segment.
+   */
+  virtual Vr2i getSupportVector ();
+
+  /**
+   * \brief Returns the size of the segment bounding box in a vector 2D.
+   */
+  Vr2i boundingBoxSize () const;
+
+  /**
+   * \brief Returns the connected components of the blurred segment.
+   */
+  std::vector <std::vector <Pt2i> > connectedComponents () const;
+
+  /**
+   * \brief Returns the count of connected points in the blurred segment.
+   */
+  int countOfConnectedPoints () const;
+
+  /**
+   * \brief Returns the count of connected components in the blurred segment.
+   */
+  int countOfConnectedComponents () const;
+
+  /**
+   * \brief Returns the count of connected points of given minimal size.
+   * @param min Minimal size of the connected components.
+   */
+  int countOfConnectedPoints (int min) const;
+
+  /**
+   * \brief Returns the count of connected components of given minimal size.
+   * @param min Minimal size of the connected components.
+   */
+  int countOfConnectedComponents (int min) const;
+
+  /**
+   * \brief Returns the connected components of the blurred segment.
+   */
+  std::vector <std::vector <Pt2i> > getConnectedComponents () const;
+
+  /**
+   * \brief Checks if given point is one of the three antipodal points.
+   * @param pt Given point.
+   */
+  inline bool isAntipodal (Pt2i pt) const {
+    return (pt.equals (laps) || pt.equals (lape) || pt.equals (lapv)); }
+
+
+protected:
+
+  /** Bi-directional list of points: the effective blurred segment. */
+  BiPtList *plist;
+  /** Bounding straight segment. */
+  DigitalStraightSegment *dss;
+  /** Central scan line used for detection (if defined). */
+  DigitalStraightLine *scan;
+
+  /** Start point of the last known antipodal edge. */
+  Pt2i laps;
+  /** End point of the last known antipodal edge. */
+  Pt2i lape;
+  /** Last known antipodal vertex. */
+  Pt2i lapv;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.cpp b/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.cpp
new file mode 100644
index 0000000..c11e553
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.cpp
@@ -0,0 +1,294 @@
+#include "blurredsegmentproto.h"
+
+
+BlurredSegmentProto::BlurredSegmentProto (int maxWidth, Pt2i pix)
+{
+  this->maxWidth.set (maxWidth);
+  plist = new BiPtList (pix);
+  leftOK = false;
+  rightOK = false;
+  bsFlat = false;
+  bsOK = false;
+  convexhull = NULL;
+  chChanged = false;
+  dss = NULL;
+}
+
+
+BlurredSegmentProto::BlurredSegmentProto (int maxWidth, Pt2i center,
+                  const vector<Pt2i> &leftPts, const vector<Pt2i> &rightPts)
+{
+  this->maxWidth.set (maxWidth);
+  plist = new BiPtList (center);
+  leftOK = false;
+  rightOK = false;
+  bsFlat = false;
+  bsOK = false;
+  convexhull = NULL;
+  chChanged = false;
+  dss = NULL;
+
+  vector<Pt2i>::const_iterator itr = rightPts.begin ();
+  vector<Pt2i>::const_iterator itl = leftPts.begin ();
+  bool scanningRight = true;
+  bool scanningLeft = true;
+  while (scanningRight || scanningLeft)
+  {
+    if (scanningRight)
+    {
+      if (itr == rightPts.end ()) scanningRight = false;
+      else
+        if (! addRight (*itr++)) scanningRight = false;
+    }
+    if (scanningLeft)
+    {
+      if (itl == leftPts.end ()) scanningLeft = false;
+      else
+        if (! addLeft (*itl++)) scanningLeft = false;
+    }
+  }
+}
+
+
+BlurredSegmentProto::~BlurredSegmentProto ()
+{
+  if (convexhull != NULL) delete convexhull;
+}
+
+
+EDist BlurredSegmentProto::strictThickness () const
+{
+  return (convexhull != NULL ? convexhull->thickness () : EDist (0, 1));
+}
+
+
+EDist BlurredSegmentProto::digitalThickness () const
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    DigitalStraightLine l (s, e, v);
+    return (EDist (l.width (), l.period ()));
+  }
+  return (EDist (1, 1));
+}
+
+
+DigitalStraightLine *BlurredSegmentProto::getLine () const
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    return (new DigitalStraightLine (s, e, v));
+  }
+  if (bsFlat || leftOK || rightOK)
+    return (new DigitalStraightLine (getLastLeft (), getLastRight (),
+                                     DigitalStraightLine::DSL_THIN));
+  return (NULL); // No line if only one point
+}
+
+
+bool BlurredSegmentProto::addLeft (Pt2i pix)
+{
+  if (bsOK)     // convexhull defined
+  {
+    bool res = addPoint (pix, true);
+    return (res);
+  }
+
+  else if (bsFlat)    // leftOK && rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () != 0)
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else if (leftOK)    // thus ! rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else if (rightOK)
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else   // only the central point is ok
+  {
+    plist->addFront (pix);
+    leftOK = true;
+  }
+
+  chChanged = true;
+  return true;
+}
+
+
+bool BlurredSegmentProto::addRight (Pt2i pix)
+{
+  if (bsOK)     // bs != NULL
+  {
+    bool res = addPoint (pix, false);
+    return (res);
+  }
+
+  else if (bsFlat)    // leftOK && rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () != 0)
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else if (rightOK)    // thus ! leftOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else if (leftOK)
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.numerator () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else   // only the central point is ok
+  {
+    plist->addBack (pix);
+    rightOK = true;
+  }
+
+  chChanged = true;
+  return true;
+}
+
+
+bool BlurredSegmentProto::addPoint (Pt2i p, bool onleft)
+{
+  bool inserted = convexhull->addPointDS (p, onleft);
+  if ((strictThickness ()).greaterThan (maxWidth))
+  {
+    if (inserted) convexhull->restore ();
+    return false;
+  }
+ 
+  if (onleft) plist->addFront (p);
+  else plist->addBack (p);
+  chChanged = true;
+  return true;
+}
+
+
+void BlurredSegmentProto::removeLeft (int n)
+{
+  if (bsOK) plist->removeFront (n);
+}
+
+
+void BlurredSegmentProto::removeRight (int n)
+{
+  if (bsOK) plist->removeBack (n);
+}
+ 
+
+Vr2i BlurredSegmentProto::getSupportVector ()
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    return (s.vectorTo (e));
+  }
+  if (bsFlat || leftOK || rightOK)
+    return (getLastLeft().vectorTo (getLastRight ()));
+  return (Vr2i (1, 0));    // hardly better with only one point !
+}
+
+
+BlurredSegment *BlurredSegmentProto::endOfBirth ()
+{
+  DigitalStraightSegment *seg = NULL;
+  if (bsOK)
+  {
+    int xmin, ymin, xmax, ymax;
+    plist->findExtrema (xmin, ymin, xmax, ymax);
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    seg = new DigitalStraightSegment (s, e, v, xmin, ymin, xmax, ymax);
+  }
+  else if (bsFlat || rightOK || leftOK)
+  {
+    Pt2i llast = plist->frontPoint ();
+    Pt2i rlast = plist->backPoint ();
+    if (llast.equals (rlast)) // Strange, should not be flat, rightok or leftok
+    {
+      plist = NULL;
+      return (NULL);
+    }
+    int xmin = llast.x ();
+    if (rlast.x () < llast.x ()) xmin = rlast.x ();
+    int ymin = llast.y ();
+    if (rlast.y () < llast.y ()) ymin = rlast.y ();
+    int xmax = llast.x ();
+    if (rlast.x () > llast.x ()) xmax = rlast.x ();
+    int ymax = llast.y ();
+    if (rlast.y () > llast.y ()) ymax = rlast.y ();
+    seg = new DigitalStraightSegment (llast, rlast,
+                                      DigitalStraightLine::DSL_THIN,
+                                      xmin, ymin, xmax, ymax);
+  }
+  else return (NULL);
+  Pt2i aps (-1, -1), ape (-1, -1), apv (-1, -1);
+  if (convexhull != NULL)
+    convexhull->antipodalEdgeAndVertex (aps, ape, apv);
+  BlurredSegment *bbs = new BlurredSegment (plist, seg, aps, ape, apv);
+  plist = NULL;  // NECESSARY TO AVOID CONTENTS CLEARANCE !!!
+  return (bbs);
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.h b/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.h
new file mode 100644
index 0000000..1489b07
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/blurredsegmentproto.h
@@ -0,0 +1,139 @@
+#ifndef OLD_BLURRED_SEGMENT_PROTO_H
+#define OLD_BLURRED_SEGMENT_PROTO_H
+
+#include "blurredsegment.h"
+
+
+/** 
+ * @class BlurredSegmentProto blurredsegmentproto.h
+ * \brief A prototype of blurred segment, untill complete specification.
+ * It is mostly based on a evolving list of points, its convex hull and
+ * the successive states of the blurred segment construction.
+ */
+class [[deprecated("Use BSProto instead")]]
+BlurredSegmentProto : public BlurredSegment
+{
+public:
+
+  /**
+   * \brief Creates a blurred segment prototype.
+   * @param maxWidth Maximal width of the blurred segment to build
+   * @param pix Central point of the blurred segment to build
+   */
+  BlurredSegmentProto (int maxWidth, Pt2i pix);
+
+  /**
+   * \brief Creates a blurred segment prototype with lists of points.
+   * @param maxWidth Maximal width of the blurred segment to build.
+   * @param center Central point of the blurred segment to build.
+   * @param leftPts Points to add on left side
+   * @param rightPts Points to add on right side.
+   */
+  BlurredSegmentProto (int maxWidth, Pt2i center,
+                  const vector<Pt2i> &leftPts, const vector<Pt2i> &rightPts);
+
+  /**
+   * \brief Deletes the blurred segment prototype.
+   */
+  ~BlurredSegmentProto ();
+
+  /**
+   * \brief Checks if the blurred segment has at least two points.
+   */
+  inline bool isLineable () const {
+    return (bsOK || bsFlat || leftOK || rightOK); }
+
+  /**
+   * \brief Returns the built-in blurred segment strict thickness.
+   * The strict thickness is the distance between bounding lines, ie (nu-1)/p.
+   */
+  EDist strictThickness () const;
+
+  /**
+   * \brief Returns the built-in blurred segment digital thickness.
+   * The digital thickness is the width of the digital straight line, ie nu/p.
+   */
+  EDist digitalThickness () const;
+
+  /**
+   * \brief Returns the requested max width of the segment.
+   */
+  inline const EDist getMaxWidth () const { return maxWidth; }
+
+  /**
+   * \brief Sets the requested max width of the segment.
+   * @param maxwidth The new vaue for the requested max width.
+   */
+  inline void setMaxWidth (const EDist &val) { maxWidth.set (val); }
+
+  /**
+   * \brief Returns the underlying digital straight line.
+   */
+  DigitalStraightLine *getLine () const;
+
+  /**
+   * \brief Adds a new point on the left.
+   * @param pix point to be added.
+   * Returns true if the point is accepted.
+   */
+  bool addLeft (Pt2i pix);
+
+  /**
+   * \brief Adds a new point on the right.
+   * @param pix point to be added.
+   * Returns true if the point is accepted.
+   */
+  bool addRight (Pt2i pix);
+
+  /**
+   * \brief Remove last points on the left side.
+   * @param n Number of points to remove.
+   */
+  void removeLeft (int n);
+
+  /**
+   * \brief Remove last points on the right side.
+   * @param n Number of points to remove.
+   */
+  void removeRight (int n);
+
+  /**
+   * \brief Returns the support vector of the blurred segment.
+   */
+  Vr2i getSupportVector ();
+
+  /**
+   * \brief Returns a stable blurred segment from available information.
+   */
+  BlurredSegment *endOfBirth ();
+
+
+protected:
+
+  /** Maximal width of the blurred segment. */
+  EDist maxWidth;
+
+  /** Maintained convex hull of the blurred segment. */
+  ConvexHull *convexhull;
+
+  /** Indicates if the blurred segment is constructed. */
+  bool bsOK;
+  /** Indicates if the points are aligned. */
+  bool bsFlat;
+  /** Indicates if the left point is defined. */
+  bool leftOK;
+  /** Indicates if the right point is defined. */
+  bool rightOK;
+
+  /** Flag indicating if the convex hull changed since last DSS extraction. */
+  bool chChanged;
+
+
+  /**
+   * \brief Submits a new point to extend the blurred segment.
+   * @param p Submitted point.
+   * @param onleft Adding direction (true for LEFT, false for RIGHT).
+   */
+  bool addPoint (Pt2i p, bool onleft);
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/bsdetector.cpp b/Expes/Testers/TestLines/BlurredSegment/bsdetector.cpp
new file mode 100644
index 0000000..6b6a4b0
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bsdetector.cpp
@@ -0,0 +1,577 @@
+#include "bsdetector.h"
+
+
+const std::string BSDetector::VERSION = "1.3.0";
+
+const int BSDetector::STEP_FINAL = 0;
+const int BSDetector::STEP_INITIAL = 1;
+const int BSDetector::STEP_PRELIM = 2;
+
+const int BSDetector::RESULT_VOID = -2;
+const int BSDetector::RESULT_UNDETERMINED = -1;
+const int BSDetector::RESULT_OK = 0;
+const int BSDetector::RESULT_PRELIM_NO_DETECTION = 1;
+const int BSDetector::RESULT_PRELIM_TOO_FEW = 2;
+const int BSDetector::RESULT_INITIAL_NO_DETECTION = 11;
+const int BSDetector::RESULT_INITIAL_TOO_FEW = 12;
+const int BSDetector::RESULT_INITIAL_TOO_SPARSE = 13;
+const int BSDetector::RESULT_INITIAL_TOO_MANY_OUTLIERS = 14;
+const int BSDetector::RESULT_INITIAL_CLOSE_ORIENTATION = 15;
+const int BSDetector::RESULT_FINAL_NO_DETECTION = 21;
+const int BSDetector::RESULT_FINAL_TOO_FEW = 22;
+const int BSDetector::RESULT_FINAL_TOO_SPARSE = 23;
+const int BSDetector::RESULT_FINAL_TOO_SMALL = 24;
+const int BSDetector::RESULT_FINAL_TOO_MANY_OUTLIERS = 25;
+
+const int BSDetector::DEFAULT_FAST_TRACK_SCAN_WIDTH = 16;
+const int BSDetector::DEFAULT_ASSIGNED_THICKNESS = 3;
+const int BSDetector::DEFAULT_ACCEPTED_LACKS = 5;
+const int BSDetector::FAST_TRACK_MARGIN = 2;
+
+const int BSDetector::BS_MIN_SIZE = 3;
+const int BSDetector::DEFAULT_INITIAL_MIN_SIZE = 5;
+const int BSDetector::DEFAULT_FINAL_MIN_SIZE = 10;
+const int BSDetector::DEFAULT_FRAGMENT_MIN_SIZE = 5;
+const int BSDetector::DEFAULT_AUTO_SWEEPING_STEP = 15;
+const int BSDetector::PRELIM_MIN_HALF_WIDTH = 10;
+
+
+
+BSDetector::BSDetector ()
+{
+  gMap = NULL;
+  inThick = DEFAULT_ASSIGNED_THICKNESS;
+  prelimDetectionOn = false;
+  singleMultiOn = true;
+
+  bst0 = (prelimDetectionOn ? new BSTracker () : NULL);
+  bst1 = new BSTracker ();
+  bst2 = new BSTracker ();
+
+  nfaOn = true;
+  nfaf = NULL;
+  nfaf = (nfaOn ? new NFAFilter () : NULL);
+
+  acceptedLacks = DEFAULT_ACCEPTED_LACKS;
+  oppositeGradientDir = false;   // main edge detection
+  initialMinSize = DEFAULT_INITIAL_MIN_SIZE;
+  fragmentMinSize = DEFAULT_FRAGMENT_MIN_SIZE;
+  initialSparsityTestOn = true;
+  finalSizeTestOn = true;
+  finalMinSize = DEFAULT_FINAL_MIN_SIZE;
+  finalSparsityTestOn = false;
+  multiSelection = false;
+  autodet = false;
+  autoSweepingStep = DEFAULT_AUTO_SWEEPING_STEP;
+  maxtrials = 0;
+  nbtrials = 0;
+
+  bspre = NULL;
+  bsini = NULL;
+  bsf = NULL;
+  resultValue = RESULT_UNDETERMINED;
+}
+
+
+BSDetector::~BSDetector ()
+{
+  if (prelimDetectionOn) delete bst0;
+  delete bst1;
+  delete bst2;
+  
+  if (bsini != NULL) delete bsini;
+  if (bsf != NULL) delete bsf;
+  std::vector <BlurredSegment *>::iterator it = mbsf.begin ();
+  while (it != mbsf.end ()) delete (*it++);
+}
+
+
+void BSDetector::clearAll ()
+{
+  if (bsini != NULL)
+  {
+    delete bsini;
+    bsini = NULL;
+  }
+  if (bsf != NULL)
+  {
+    delete bsf;
+    bsf = NULL;
+  }
+  std::vector <BlurredSegment *>::iterator it = mbsf.begin ();
+  while (it != mbsf.end ()) delete (*it++);
+  mbsf.clear ();
+  vbsf.clear ();
+  rbsf.clear ();
+}
+
+
+void BSDetector::setGradientMap (VMap *data)
+{
+  gMap = data;
+  if (prelimDetectionOn) bst0->setGradientMap (data);
+  if (bst1) bst1->setGradientMap (data);
+  if (bst2) bst2->setGradientMap (data);
+  if (nfaf) nfaf->init (data);
+}
+
+
+void BSDetector::detectAll ()
+{
+  // Initializes the multi-detection structures
+  autodet = true;
+  freeMultiSelection ();
+  gMap->setMasking (true);
+  gMap->clearMask ();
+
+  // Runs the automatic detection sweep algorithm
+  bool isnext = true;
+  nbtrials = 0;
+  int width = gMap->getWidth ();
+  int height = gMap->getHeight ();
+  for (int x = width / 2; isnext && x > 0; x -= autoSweepingStep)
+    isnext = detectMulti (Pt2i (x, 0), Pt2i (x, height - 1));
+  for (int x = width / 2 + autoSweepingStep;
+       isnext && x < width - 1; x += autoSweepingStep)
+    isnext = detectMulti (Pt2i (x, 0), Pt2i (x, height - 1));
+  for (int y = height / 2; isnext && y > 0; y -= autoSweepingStep)
+    isnext = detectMulti (Pt2i (0, y), Pt2i (width - 1, y));
+  for (int y = height / 2 + autoSweepingStep;
+       isnext && y < height - 1; y += autoSweepingStep)
+    isnext = detectMulti (Pt2i (0, y), Pt2i (width - 1, y));
+
+  // Updates the selected segment for survey
+  if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
+
+  // Filters the detection output using NFA measure
+  if (nfaf) nfaf->filter (mbsf, vbsf, rbsf);
+  gMap->setMasking (false);
+}
+
+
+void BSDetector::detectAllWithBalancedXY ()
+{
+  // Initializes the multi-detection structures
+  autodet = true;
+  freeMultiSelection ();
+  gMap->setMasking (true);
+  gMap->clearMask ();
+
+  // Runs the automatic detection balanced sweep algorithm
+  bool isnext = true;
+  nbtrials = 0;
+  int width = gMap->getWidth ();
+  int height = gMap->getHeight ();
+  int xg = width / 2, yb = height / 2;
+  int xd = xg + autoSweepingStep, yh = yb + autoSweepingStep;
+  bool agauche = true, enbas = true, adroite = true, enhaut = true;
+  while (isnext && (agauche || enbas || adroite || enhaut))
+  {
+    if (agauche)
+    {
+      isnext = detectMulti (Pt2i (xg, 0), Pt2i (xg, height - 1));
+      xg -= autoSweepingStep;
+      if (xg <= 0) agauche = false;
+    }
+    if (isnext && enbas)
+    {
+      isnext = detectMulti (Pt2i (0, yb), Pt2i (width - 1, yb));
+      yb -= autoSweepingStep;
+      if (yb <= 0) enbas = false;
+    }
+    if (isnext && adroite)
+    {
+      isnext = detectMulti (Pt2i (xd, 0), Pt2i (xd, height - 1));
+      xd += autoSweepingStep;
+      if (xd >= width - 1) adroite = false;
+    }
+    if (isnext && enhaut)
+    {
+      isnext = detectMulti (Pt2i (0, yh), Pt2i (width - 1, yh));
+      yh += autoSweepingStep;
+      if (yh >= height - 1) enhaut = false;
+    }
+  }
+  // Updates the selected segment for survey
+  if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
+
+  // Filters the detection output using NFA measure
+  if (nfaf) nfaf->filter (mbsf, vbsf, rbsf);
+  gMap->setMasking (false);
+}
+
+
+void BSDetector::detectSelection (const Pt2i &p1, const Pt2i &p2)
+{
+  autodet = false;
+  freeMultiSelection ();
+
+  // Runs multi-detection if set
+  if (multiSelection)
+  {
+    gMap->setMasking (true);
+    gMap->clearMask ();
+    nbtrials = 0;
+    detectMulti (p1, p2);
+
+    // Updates the selected segment for survey
+    if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
+    gMap->setMasking (false);
+  }
+
+  // Runs single detection otherwise
+  else resultValue = detectSingle (p1, p2);
+}
+
+
+void BSDetector::redetect ()
+{
+  if (autodet) detectAll ();
+  else detectSelection (inip1, inip2);
+}
+
+
+void BSDetector::freeMultiSelection ()
+{
+  std::vector<BlurredSegment *>::iterator it = mbsf.begin ();
+  while (it != mbsf.end ()) delete (*it++);
+  mbsf.clear ();
+}
+
+
+bool BSDetector::detectMulti (const Pt2i &p1, const Pt2i &p2)
+{
+  // Finds and sorts local max of gradient magnitude along the input stroke
+  std::vector<Pt2i> pts;
+  p1.draw (pts, p2);
+  int *locmax = new int[pts.size ()];
+  int nlm = gMap->localMax (locmax, pts);
+
+  // Detects a blurred segment for each local max
+  bool isnext = true;
+  for (int i = 0; isnext && i < nlm; i++)
+  {
+    Pt2i ptstart = pts.at (locmax[i]);
+    if (gMap->isFree (ptstart))
+    {
+      // Handles opposite edge orientations
+      bool savedOppDir = oppositeGradientDir;
+      oppositeGradientDir = false;
+      int nbDets = (gMap->isOrientationConstraintOn () ? 2 : 1);
+      if (singleMultiOn) nbDets = 1;
+      while (isnext && nbDets != 0)
+      {
+        // Detects a blurred segment
+        if (detectSingle (p1, p2, true, ptstart) == RESULT_OK)
+        {
+          gMap->setMask (bsf->getAllPoints ());
+          mbsf.push_back (bsf);
+          bsf = NULL; // to avoid BS deletion
+
+          // Interrupts the detection when the selected segment is reached
+          if ((int) (mbsf.size ()) == maxtrials) isnext = false;
+        }
+        oppositeGradientDir = ! oppositeGradientDir;
+        nbDets --;
+        nbtrials ++;
+      }
+      oppositeGradientDir = savedOppDir;
+    }
+  }
+  return (isnext);
+}
+
+
+int BSDetector::detectSingle (const Pt2i &p1, const Pt2i &p2,
+                        bool centralp, const Pt2i &pc)
+{
+  // Entry check
+  //------------
+  if (p1.equals (p2)
+      || ((! centralp) && p1.chessboard (p2) < BSTracker::MIN_SCAN))
+    return RESULT_VOID;
+
+  // Clearance
+  //----------
+  if (prelimDetectionOn) bst0->clear ();
+  bst1->clear ();
+  bst2->clear ();
+  if (bspre != NULL) delete bspre;
+  bspre = NULL;
+  if (bsini != NULL) delete bsini;
+  bsini = NULL;
+  if (bsf != NULL) delete bsf;
+  bsf = NULL;
+
+  prep1.set (p1);
+  prep2.set (p2);
+  prewidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0);
+  prepc.set (pc);
+
+  // Preliminary based on highest gradient without orientation constraint
+  //---------------------------------------------------------------------
+  if (prelimDetectionOn)
+  {
+    bspre = bst0->fastTrack (prep1, prep2, inThick + FAST_TRACK_MARGIN,
+                             acceptedLacks, prewidth, prepc);
+    if (bspre == NULL || bspre->size () < initialMinSize)
+      return (bspre == NULL ? RESULT_PRELIM_NO_DETECTION
+                            : RESULT_PRELIM_TOO_FEW);
+
+    Vr2i v0 = bspre->getSupportVector ();
+    int l = v0.chessboard ();
+    if (l != 0)
+    {
+      Pt2i pcentral = bspre->getSegment()->centerOfIntersection (prep1, prep2);
+      int detw = 2 * (1 + bspre->minimalWidth().floor ());
+      if (detw < PRELIM_MIN_HALF_WIDTH) detw = PRELIM_MIN_HALF_WIDTH;
+      int dx = (int) ((v0.y () * detw) / l);
+      int dy = (int) (- (v0.x () * detw) / l);
+      inip1.set (pcentral.x () + dx, pcentral.y () + dy);
+      inip2.set (pcentral.x () - dx, pcentral.y () - dy);
+      iniwidth = 0;
+    }
+  }
+  else
+  {
+    inip1.set (p1);
+    inip2.set (p2);
+    iniwidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0);
+    inipc.set (pc);
+  }
+
+  // Initial detection based on highest gradient without orientation constraint
+  //---------------------------------------------------------------------------
+  bsini = bst1->fastTrack (inip1, inip2, inThick + FAST_TRACK_MARGIN,
+                           acceptedLacks, iniwidth, inipc);
+  if (bsini == NULL || bsini->size () < initialMinSize)
+    return (bsini == NULL ? RESULT_INITIAL_NO_DETECTION
+                          : RESULT_INITIAL_TOO_FEW);
+
+  // Sparsity test
+  //-------------
+  if (initialSparsityTestOn)
+  {
+    if (bsini->size () < bsini->extent () / 2)
+      return RESULT_INITIAL_TOO_SPARSE;
+  }
+
+  // Orientation test for automatic extractions
+  //-------------------------------------------
+  Vr2i bsinidir = bsini->getSupportVector();
+  if (bsinidir.orientedAs (inip1.vectorTo (inip2)))
+    return RESULT_INITIAL_CLOSE_ORIENTATION;
+  
+  // Gradient reference selection
+  //-----------------------------
+  Pt2i pCenter = bsini->getCenter ();
+  Vr2i gRef = gMap->getValue (pCenter);
+  if (oppositeGradientDir && gMap->isOrientationConstraintOn ())
+    gRef.invert ();
+
+  // Scan recentering and fitting
+  //-----------------------------
+  pCenter.set (bsini->getSegment()->centerOfIntersection (inip1, inip2));
+
+  // Finer detection based on gradient maxima with orientation constraint
+  //---------------------------------------------------------------------
+  bsf = bst2->fineTrack (pCenter, bsinidir, inThick, acceptedLacks, gRef);
+  if (bsf == NULL || bsf->size () < initialMinSize)
+    return (bsf == NULL ? RESULT_FINAL_NO_DETECTION : RESULT_FINAL_TOO_FEW);
+
+  // Size test
+  //------------
+  if (finalSizeTestOn)
+  {
+    // DigitalStraightSegment *dss = bsf->getSegment ();
+    if ((int) (bsf->getAllPoints().size ()) < finalMinSize)
+      return RESULT_FINAL_TOO_SMALL;
+  }
+
+  // Sparsity test
+  //--------------
+  if (finalSparsityTestOn)
+  {
+    if (bsf->size () < (bsf->extent () * 4) / 5)
+      return RESULT_FINAL_TOO_SPARSE;
+  }
+
+  return RESULT_OK;
+}
+
+
+BlurredSegment *BSDetector::getBlurredSegment (int step) const
+{
+  if (step == STEP_PRELIM) return (bspre);
+  else if (step == STEP_INITIAL) return (bsini);
+  else if (mbsf.empty ()) return (bsf);
+  else return (mbsf.back ());
+  return NULL;
+}
+
+
+int BSDetector::getDigitalStraightSegments (
+                        std::vector<DigitalStraightSegment *> &dss) const
+{
+  if (mbsf.empty ())
+  {
+    if (bsf == NULL) return 0;
+    DigitalStraightSegment *ds = bsf->getSegment ();
+    if (ds == NULL) return (0);
+    dss.push_back (ds);
+    return (1);
+  }
+  int nb = 0;
+  std::vector<BlurredSegment *>::const_iterator it = mbsf.begin ();
+  while (it != mbsf.end ())
+  {
+    BlurredSegment *bs = (*it++);
+    if (bs != NULL)
+    {
+      DigitalStraightSegment *ds = bs->getSegment ();
+      if (ds != NULL)
+      {
+        dss.push_back (ds);
+        nb ++;
+      }
+    }
+  }
+  return nb;
+}
+
+
+int BSDetector::copyDigitalStraightSegments (
+                             std::vector<DigitalStraightSegment> &dss) const
+{
+  if (mbsf.empty ())
+  {
+    if (bsf == NULL) return 0;
+    DigitalStraightSegment *ds = bsf->getSegment ();
+    if (ds == NULL) return 0;
+    dss.push_back (DigitalStraightSegment (ds));
+    return 1;
+  }
+  int nb = 0;
+  std::vector<BlurredSegment *>::const_iterator it = mbsf.begin ();
+  while (it != mbsf.end ())
+  {
+    BlurredSegment *bs = (*it++);
+    if (bs != NULL)
+    {
+      DigitalStraightSegment *ds = bs->getSegment ();
+      if (ds != NULL)
+      {
+        dss.push_back (DigitalStraightSegment (ds));
+        nb ++;
+      }
+    }
+  }
+  return nb;
+}
+
+
+void BSDetector::setPixelLackTolerence (int number)
+{
+  if (number >= 0) acceptedLacks = number;
+}
+
+
+void BSDetector::incMaxDetections (bool dir)
+{
+  maxtrials = maxtrials + (dir ? -1 : 1);
+  if (maxtrials < 0) maxtrials = (int) (mbsf.size ());
+}
+
+
+void BSDetector::getScanInput (int step,
+                               Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const
+{
+  if (step == STEP_PRELIM)
+  {
+    if (prelimDetectionOn)
+    {
+      p1.set (prep1);
+      p2.set (prep2);
+      swidth = prewidth;
+      pc.set (prepc);
+    }
+  }
+  else if (step == STEP_INITIAL)
+  {
+    p1.set (inip1);
+    p2.set (inip2);
+    swidth = iniwidth;
+    pc.set (inipc);
+  }
+}
+
+
+const std::vector <std::vector <Pt2i> > BSDetector::getFinalScans () const
+{
+  return (bst2->getScans ());
+}
+
+
+bool BSDetector::finalScansRecordOn () const
+{
+  return (bst2->scanRecordOn ());
+}
+
+
+void BSDetector::setFinalScansRecord (bool status)
+{
+  bst2->setScanRecord (status);
+  if (status) redetect ();
+}
+
+
+void BSDetector::switchNFA ()
+{
+  nfaOn = ! nfaOn;
+  if (nfaOn && nfaf == NULL)
+  {
+    nfaf = new NFAFilter ();
+    nfaf->init (gMap);
+  }
+}
+
+
+bool BSDetector::incFragmentSizeMinValue (bool inc)
+{
+  if ((! inc) && fragmentMinSize <= 1) return false;
+  fragmentMinSize += (inc ? 1 : -1);
+  return true;
+}
+
+
+void BSDetector::switchPreliminary ()
+{
+  if (prelimDetectionOn)
+  {
+    delete bst0;
+    prelimDetectionOn = false;
+  }
+  else
+  {
+    prelimDetectionOn = true;
+    bst0 = new BSTracker ();
+    bst0->setGradientMap (gMap);
+  }
+}
+
+
+bool BSDetector::switchOppositeGradient ()
+{
+  if (gMap != NULL && gMap->isOrientationConstraintOn ())
+  {
+    oppositeGradientDir = ! oppositeGradientDir;
+    return true;
+  }
+  return false;
+}
+
+
+std::string BSDetector::version ()
+{
+  return BSDetector::VERSION;
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/bsdetector.h b/Expes/Testers/TestLines/BlurredSegment/bsdetector.h
new file mode 100644
index 0000000..bc4010a
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bsdetector.h
@@ -0,0 +1,623 @@
+#ifndef BLURRED_SEGMENT_DETECTOR_H
+#define BLURRED_SEGMENT_DETECTOR_H
+
+#include "bstracker.h"
+#include "nfafilter.h"
+#include <string>
+
+
+/** 
+ * @class BSDetector bsdetector.h
+ * \brief Blurred segment detector in grey level images.
+ */
+class BSDetector
+{
+public:
+
+  /** Version number */
+  static const std::string VERSION;
+
+  /** Identifier for the final detection step. */
+  static const int STEP_FINAL;
+  /** Identifier for the initial detection step. */
+  static const int STEP_INITIAL;
+  /** Identifier for the preliminary detection step. */
+  static const int STEP_PRELIM;
+
+  /** Extraction result : void input. */
+  static const int RESULT_VOID;
+  /** Extraction result : successful extraction. */
+  static const int RESULT_UNDETERMINED;
+  /** Extraction result : successful extraction. */
+  static const int RESULT_OK;
+  /** Extraction result : no initial detection (bsini == NULL). */
+  static const int RESULT_PRELIM_NO_DETECTION;
+  /** Extraction result : too few points at initial detection. */
+  static const int RESULT_PRELIM_TOO_FEW;
+  /** Extraction result : no initial detection (bsini == NULL). */
+  static const int RESULT_INITIAL_NO_DETECTION;
+  /** Extraction result : too few points at initial detection. */
+  static const int RESULT_INITIAL_TOO_FEW;
+  /** Extraction result : unsuccessful density test at initial detection. */
+  static const int RESULT_INITIAL_TOO_SPARSE;
+  /** Extraction result : unsuccessful filter test at initial detection. */
+  static const int RESULT_INITIAL_TOO_MANY_OUTLIERS;
+  /** Extraction result : initial detection of a closely oriented segment. */
+  static const int RESULT_INITIAL_CLOSE_ORIENTATION;
+  /** Extraction result : no final detection (bsf == NULL). */
+  static const int RESULT_FINAL_NO_DETECTION;
+  /** Extraction result : too few points at final detection. */
+  static const int RESULT_FINAL_TOO_FEW;
+  /** Extraction result : unsuccessful connectivity test at final detection. */
+  static const int RESULT_FINAL_TOO_SPARSE;
+  /** Extraction result : unsuccessful spread test at final detection. */
+  static const int RESULT_FINAL_TOO_SMALL;
+  /** Extraction result : unsuccessful filter test at final detection. */
+  static const int RESULT_FINAL_TOO_MANY_OUTLIERS;
+
+  
+  /**
+   * \brief Creates a segment detector.
+   */
+  BSDetector ();
+
+  /**
+   * \brief Deletes the segment detector.
+   */
+  ~BSDetector ();
+
+  /**
+   * \brief Delete all detected structures.
+   */
+  void clearAll ();
+
+  /**
+   * \brief Returns the minimal vertical or horizontal width.
+   */
+  inline int result () const { return resultValue; }
+
+  /**
+   * \brief Sets the gradient map.
+   */
+  void setGradientMap (VMap *data);
+
+  /**
+   * \brief Detects all blurred segments in the picture.
+   * Parses X direction first, then Y direction.
+   */
+  void detectAll ();
+
+  /**
+   * \brief Detects all blurred segments in the picture.
+   * Parses simultaneously X and Y directions.
+   */
+  void detectAllWithBalancedXY ();
+
+  /**
+   * \brief Detects blurred segments between two input points.
+   * @param p1 First input point.
+   * @param p2 Second input point.
+   */
+  void detectSelection (const Pt2i &p1, const Pt2i &p2);
+
+  /**
+   * \brief Runs the last detection again.
+   */
+  void redetect ();
+
+  /**
+   * \brief Detects a blurred segment between two input points.
+   * Step 1: For each scan line, one candidate is selected
+   *         based on the gradient norm only (no direction test).
+   * Step 2: Outliers pruning based on parameter space pre-filtering.
+   * Step 3: For each scan line, local candidates are detected
+   *         on top of gradient ridges with closest direction.
+   *         The first candidates that prolongates the segment are retained.
+   * Step 4: Outliers pruning based on parameter space filtering.
+   * Note : Multi-detection along a stroke requires an initial start point.
+   * Returns the detection status (RESULT_OK if successfull).
+   * @param p1 First input point.
+   * @param p2 Second input point.
+   * @param centralp Set to true if the central point is provided.
+   * @param pc Initial central point.
+   */
+  int detectSingle (const Pt2i &p1, const Pt2i &p2,
+                    bool centralp = false, const Pt2i &pc = Pt2i ());
+
+  /**
+   * \brief Returns the detected blurred segment at given step.
+   * @param step Detection step.
+   */
+  BlurredSegment *getBlurredSegment (int step = STEP_FINAL) const;
+    
+  /**
+   * \brief Returns the list of detected blurred segments at final step.
+   */
+  inline const std::vector<BlurredSegment *> getBlurredSegments () const {
+    return (mbsf); }
+
+  /**
+   * \brief Returns the list of NFA-validated blurred segments at final step.
+   */
+  inline const std::vector<BlurredSegment *> getValidSegments () const {
+    return (vbsf); }
+
+  /**
+   * \brief Returns the list of NFA-rejected blurred segments at final step.
+   */
+  inline const std::vector<BlurredSegment *> getRejectedSegments () const {
+    return (rbsf); }
+
+  /**
+   * \brief Avoids the deletion of the last extracted blurred segment.
+   */
+  inline void preserveFormerBlurredSegment () { bsf = NULL; }
+
+  /**
+   * \brief Avoids the deletion of the last extracted blurred segments.
+   */
+  inline void preserveFormerBlurredSegments () { mbsf.clear (); }
+
+  /**
+   * \brief Adds digital straight segments to provided list.
+   * @param dss List of digital straight segments to be completed.
+   */
+  int getDigitalStraightSegments (
+        std::vector<DigitalStraightSegment *> &dss) const;
+
+  /**
+   * \brief Adds a copy of the digital straight segments to provided list.
+   * @param dss List of digital straight segments to be completed.
+   */
+  int copyDigitalStraightSegments (
+        std::vector<DigitalStraightSegment> &dss) const;
+
+  /**
+   * \brief Returns the assigned maximal thickness to detector.
+   */
+  inline int assignedThickness () const { return inThick; }
+
+  /**
+   * \brief Sets the assigned maximal thickness to detector.
+   * @param val New assigned thickness value.
+   */
+  inline void setAssignedThickness (int val) { if (val > 0) inThick = val; }
+
+  /**
+   * \brief Returns the output blurred segment minimal size.
+   */
+  inline int initialSizeMinValue () const { return initialMinSize; }
+
+  /**
+   * \brief Sets the output blurred segment minimal size.
+   * @param val New minimal size value for the output blurred segment.
+   */
+  inline void setInitialMinSize (int val) {
+    initialMinSize = (val >= BS_MIN_SIZE ? val : BS_MIN_SIZE); }
+
+  /**
+   * \brief Returns the threshold used for maximal gradient detection.
+   */
+  inline int getSensitivity () const {
+    return (gMap->getGradientThreshold ()); }
+
+  /**
+   * \brief Increments the threshold used for maximal gradient detection.
+   * @param inc Increment value.
+   */
+  inline void incSensitivity (int inc) {
+    return (gMap->incGradientThreshold (inc)); }
+
+  /**
+   * \brief Returns the gradient threshold used for local max filtering.
+   */
+  inline int getLocalMaxGradientResolution () const {
+    return (gMap->getLocalMaxGradientResolution ()); }
+
+  /**
+   * \brief Increments the gradient threshold used for local maximal filtering.
+   * @param inc Increment value.
+   */
+  inline void incLocalMaxGradientResolution (int inc) {
+    return (gMap->incLocalMaxGradientResolution (inc)); }
+
+  /**
+   * \brief Returns the stroke sweeping step value for automatic detections.
+   */
+  inline int getAutoSweepingStep () const { return autoSweepingStep; }
+
+  /**
+   * \brief Sets the stroke sweeping step value for automatic detections.
+   * @param number New value for the stroke sweeping.
+   */
+  inline void setAutoSweepingStep (int number) {
+    if (number > 0 && number < gMap->getWidth () / 8) autoSweepingStep = number; }
+
+  /**
+   * \brief Returns the pixel lack tolerence.
+   */
+  inline int getPixelLackTolerence () const { return acceptedLacks; }
+
+  /**
+   * \brief Sets the pixel lack tolerence.
+   * @param number New value for the pixel lack tolerance.
+   */
+  void setPixelLackTolerence (int number);
+
+  /**
+   * \brief Returns the preliminary detection modality status.
+   */
+  inline bool isPreliminary () { return (prelimDetectionOn); }
+
+  /**
+   * \brief Switches preliminary detection modality.
+   */
+  void switchPreliminary ();
+
+  /**
+   * \brief Returns whether opposite edge direction is set for single edge mode.
+   */
+  inline bool isOppositeGradientOn () const { return (oppositeGradientDir); }
+
+  /**
+   * \brief Inverts the edge direction for detection stage.
+   * Effective only in single edge detection mode.
+   * Returns whether the modification was actually set.
+   */
+  bool switchOppositeGradient ();
+
+  /**
+   * \brief Returns whether opposite edge direction is set in double edge mode.
+   */
+  inline bool isSingleEdgeModeOn () const {
+    return (gMap != NULL ? gMap->isOrientationConstraintOn () : true); }
+
+  /**
+   * \brief Switches between single and double edge detection.
+   */
+  inline void switchSingleOrDoubleEdge () {
+    if (gMap != NULL) gMap->switchOrientationConstraint (); }
+
+  /**
+   * \brief Returns whether a single edge mode is set for multidetections.
+   */
+  inline bool isSingleMultiOn () const { return (singleMultiOn); }
+
+  /**
+   * \brief Switches between single and double edge mode for multidetections.
+   */
+  inline void switchSingleOrDoubleMultiDetection () {
+    singleMultiOn = ! singleMultiOn; }
+
+  /**
+   * \brief Returns true if the multi-selection modality is set.
+   */
+  inline bool isMultiSelection () const { return multiSelection; }
+
+  /**
+   * \brief Switches on or off the multi-selection modality.
+   */
+  inline void switchMultiSelection () { multiSelection = ! multiSelection; }
+
+  /**
+   * \brief Returns the scan lines at final step.
+   */
+  const std::vector <std::vector <Pt2i> > getFinalScans () const;
+
+  /**
+   * \brief Returns whether the final scan record modality is set.
+   */
+  bool finalScansRecordOn () const;
+
+  /**
+   * \brief Sets the scan record modality at final step.
+   * @param status Sets on if true, off otherwise.
+   */
+  void setFinalScansRecord (bool status);
+
+  /**
+   * \brief Toggles the initial step bounding.
+   */
+  inline void switchInitialBounding () { bst1->switchScanExtent (); }
+
+  /**
+   * \brief Returns the maximal scan extent of the initial detection.
+   */
+  inline int initialDetectionMaxExtent () { return (bst1->maxScanExtent ()); }
+
+  /**
+   * \brief Returns the proximity threshold used for fast tracking.
+   */
+  inline int getFastTrackProximityThreshold () const {
+    return (bst1->getProximityThreshold ()); }
+
+  /**
+   * \brief Increments the proximity threshold used for fast tracking.
+   * @param inc Increment sign.
+   */
+  inline void incFastTrackProximityThreshold (bool inc) {
+    bst1->incProximityThreshold (inc); }
+    
+  /**
+   * \brief Returns the proximity test status.
+   */
+  inline bool fastTrackProximityConstraintOn () const {
+    return (bst1->proximityConstraintOn ()); }
+
+  /**
+   * \brief Switches the proximity test used for fast tracking.
+   */
+  inline void switchFastTrackProximityConstraint () {
+    bst1->switchProximityConstraint (); }
+
+  /**
+   * \brief Returns the assigned thickness control delay.
+   */
+  inline int getAssignedThicknessControlDelay () const {
+    return bst2->getAssignedThicknessControlDelay (); }
+
+  /**
+   * \brief Increments the assigned thickness control delay.
+   * @param val Increment value.
+   */
+  inline void incAssignedThicknessControlDelay (int val) {
+    bst2->incAssignedThicknessControlDelay (val); }
+
+  /**
+   * \brief Returns if NFA-based filter is activated.
+   */
+  inline bool isNFA () const { return (nfaOn); }
+
+  /**
+   * \brief Toggles the use of the NFA-based filter.
+   */
+  void switchNFA ();
+
+  /**
+   * \brief Returns the NFA length ratio parameter value.
+   */
+  inline double nfaLengthRatio () const {
+    return (nfaOn ? nfaf->lengthRatio () : 0.0); }
+
+  /**
+   * \brief Increments the NFA length ratio parameter value.
+   * @param inc Increment direction.
+   */
+  inline void incNfaLengthRatio (int inc) {
+    if (nfaOn) nfaf->incLengthRatio (inc); }
+
+  /**
+   * \brief Returns whether the density test at initial step is set.
+   */
+  inline bool isInitialSparsityTestOn () const {
+    return (initialSparsityTestOn); }
+
+  /**
+   * \brief Switches on or off the initial density test modality.
+   */
+  inline void switchInitialSparsityTest () {
+    initialSparsityTestOn = ! initialSparsityTestOn; }
+
+  /**
+   * \brief Returns whether the density test at final step is set.
+   */
+  inline bool isFinalSparsityTestOn () const { return (finalSparsityTestOn); }
+
+  /**
+   * \brief Switches on or off the final density test modality.
+   */
+  inline void switchFinalSparsityTest () {
+    finalSparsityTestOn = ! finalSparsityTestOn; }
+
+  /**
+   * \brief Returns whether the size test at final step is set.
+   */
+  inline bool isFinalSizeTestOn () const { return (finalSizeTestOn); }
+
+  /**
+   * \brief Switches on or off the final size test modality.
+   */
+  inline void switchFinalSizeTest () {
+    finalSizeTestOn = ! finalSizeTestOn; }
+
+  /**
+   * \brief Returns the minimal size of final blurred segments.
+   */
+  inline int finalSizeMinValue () const {
+    return (finalSizeTestOn ? finalMinSize : BS_MIN_SIZE); }
+
+  /**
+   * \brief Sets the minimal spread of final blurred segments.
+   * @param val New size value.
+   */
+  inline void setFinalSizeMinValue (int val) {
+    finalMinSize = (val < BS_MIN_SIZE ? BS_MIN_SIZE : val); }
+
+  /**
+   * \brief Returns the minimal size of the segment connected components.
+   */
+  inline int fragmentSizeMinValue () const { return fragmentMinSize; }
+
+  /**
+   * \brief Increments the minimal size of the connected components.
+   * @param inc Positive increment if true, negative otherwise.
+   */
+  bool incFragmentSizeMinValue (bool inc);
+
+  /*
+   * \brief Returns the count of trials in a multi-detection.
+   */
+  inline int countOfTrials () const { return (nbtrials); }
+
+  /**
+   * \brief Returns the maximum number of detections set for a multi-detection.
+   */
+  inline int getMaxDetections () const { return maxtrials; }
+
+  /**
+   * \brief Sets the maximum number of trials in a multi-detection.
+   * Just kept for IPOL demo compatibility.
+   * @param nb Number of trials (0 if illimited).
+   */
+  inline void setMaxTrials (int nb) { maxtrials = nb; resetMaxDetections (); }
+
+  /**
+   * \brief Increments the maximum number of detections in a multi-detection.
+   * @param dir Increments if true, otherwise decrements.
+   */
+  void incMaxDetections (bool dir);
+
+  /**
+   * \brief Sets the maximum number of detections in a multi-detection.
+   * @param nb Number of detections (0 if illimited).
+   */
+  inline void setMaxDetections (int nb) { maxtrials = nb; }
+
+  /**
+   * \brief Resets the maximum number of detections set for a multi-detection.
+   */
+  inline void resetMaxDetections () { maxtrials = 0; }
+
+  /**
+   * \brief Gets the last detection inputs.
+   * @param step Detection step.
+   * @param p1 Input stroke first point to fill in.
+   * @param p2 Input stroke end point to fill in.
+   * @param swidth Scan width if not set by P1 and p2, otherwise 0.
+   * @param pc Input central point to fill in.
+   */
+  void getScanInput (int step,
+                     Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const;
+
+  /**
+   * \brief Returns the version number.
+   */
+  std::string version ();
+
+
+private :
+
+  /** Default value for the scan width for fast tracks. */
+  static const int DEFAULT_FAST_TRACK_SCAN_WIDTH;
+  /** Default value for the assigned thickess to detection method. */
+  static const int DEFAULT_ASSIGNED_THICKNESS;
+  /** Default value for the accepted number of successive lacks. */
+  static const int DEFAULT_ACCEPTED_LACKS;
+  /** Additional assigned thickness margin for fast tracks. */
+  static const int FAST_TRACK_MARGIN;
+  /** Default minimal size of the initial blurred segment. */
+  static const int DEFAULT_INITIAL_MIN_SIZE;
+  /** Minimal size of a blurred segment. */
+  static const int BS_MIN_SIZE;
+  /** Default minimal size of the final blurred segment. */
+  static const int DEFAULT_FINAL_MIN_SIZE;
+  /** Default value for the minimal size of segment fragments. */
+  static const int DEFAULT_FRAGMENT_MIN_SIZE;
+  /** Default value of the stroke sweeping step for automatic detections. */
+  static const int DEFAULT_AUTO_SWEEPING_STEP;
+  /** Default value for the preliminary stroke half length. */
+  static const int PRELIM_MIN_HALF_WIDTH;
+
+
+  /** Processed gradient map. */
+  VMap *gMap;
+  /** Assigned maximal thickness for current detection. */
+  int inThick;
+  /** Accepted number of successive lacks (wrt restart points). */
+  int acceptedLacks;
+
+  /** Preliminary rough tracker. */
+  BSTracker *bst0;
+  /** Preliminary stage modality. */
+  bool prelimDetectionOn;
+  /** Last input start point. */
+  Pt2i prep1;
+  /** Last input end point. */
+  Pt2i prep2;
+  /** Last input central point. */
+  Pt2i prepc;
+  /** Preliminary fast scan width if not set by an input selection. */
+  int prewidth;
+  /** Preliminary detected blurred segment. */
+  BlurredSegment *bspre;
+
+  /** Initial rough tracker. */
+  BSTracker *bst1;
+  /** Last input start point for initial step. */
+  Pt2i inip1;
+  /** Last input end point for initial step. */
+  Pt2i inip2;
+  /** Last input central point for initial step. */
+  Pt2i inipc;
+  /** Initial fast scan width if not set by an input selection. */
+  int iniwidth;
+  /** Initially detected blurred segment (initial step result). */
+  BlurredSegment *bsini;
+
+  /** Fine tracker. */
+  BSTracker *bst2;
+  /** Detected blurred segment (final result). */
+  BlurredSegment *bsf;
+
+  /** Detected blurred segments in case of multi-detection (final results). */
+  std::vector<BlurredSegment *> mbsf;
+  /** NFA-validated blurred segments. */
+  std::vector<BlurredSegment *> vbsf;
+  /** NFA-rejected blurred segments. */
+  std::vector<BlurredSegment *> rbsf;
+  /** NFA-based filtering modality. */
+  bool nfaOn;
+  /** NFA-based filter. */
+  NFAFilter *nfaf;
+
+  /** Status of the detection of points with opposite gradient direction.
+   *  Opposite to gradient direction at start point.
+   *  Used to discriminate two close edges with opposite gradients.
+   */
+  bool oppositeGradientDir;
+  /** Minimal size of the initial segment. */
+  int initialMinSize;
+  /** Minimal size of the segment fragments. */
+  int fragmentMinSize;
+  /** Sparsity test modality after initial detection. */
+  bool initialSparsityTestOn;
+  /** Sparsity test modality after final detection. */
+  bool finalSparsityTestOn;
+  /** Size test modality after final detection. */
+  bool finalSizeTestOn;
+  /** Minimal size of the final segment. */
+  int finalMinSize;
+  /** Count of small BS eliminated by the spread test. */
+  int nbSmallBS;
+  /** Segment multi-selection modality status. */
+  bool multiSelection;
+  /** Single or double mode for multi-selections. */
+  bool singleMultiOn;
+  /** Count of trials in a multi-detection. */
+  int nbtrials;
+  /** Automatic detection modality. */
+  bool autodet;
+  /** Stroke sweeping step for the automatic extraction. */
+  int autoSweepingStep;
+  /** Result of the blurred segment extraction. */
+  int resultValue;
+
+  /** Maximum number of trials in a multi-detection (for survey). */
+  int maxtrials;    // DVPT
+
+
+  /**
+   * \brief Resets the multi-selection list.
+   */
+  void freeMultiSelection ();
+
+  /**
+   * \brief Detects all blurred segments between two input points.
+   *   Returns the continuation modality.
+   * @param p1 First input point.
+   * @param p2 Second input point.
+   */
+  bool detectMulti (const Pt2i &p1, const Pt2i &p2);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/bsproto.cpp b/Expes/Testers/TestLines/BlurredSegment/bsproto.cpp
new file mode 100644
index 0000000..04bc51c
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bsproto.cpp
@@ -0,0 +1,319 @@
+#include "bsproto.h"
+
+
+BSProto::BSProto (int maxWidth, Pt2i pix)
+{
+  this->maxWidth.set (maxWidth);
+  plist = new BiPtList (pix);
+  leftOK = false;
+  rightOK = false;
+  bsFlat = false;
+  bsOK = false;
+  convexhull = NULL;
+  chChanged = false;
+  dss = NULL;
+}
+
+
+BSProto::BSProto (int maxWidth, Pt2i center,
+                  const std::vector<Pt2i> &leftPts,
+                  const std::vector<Pt2i> &rightPts)
+{
+  this->maxWidth.set (maxWidth);
+  plist = new BiPtList (center);
+  leftOK = false;
+  rightOK = false;
+  bsFlat = false;
+  bsOK = false;
+  convexhull = NULL;
+  chChanged = false;
+  dss = NULL;
+
+  std::vector<Pt2i>::const_iterator itr = rightPts.begin ();
+  std::vector<Pt2i>::const_iterator itl = leftPts.begin ();
+  bool scanningRight = true;
+  bool scanningLeft = true;
+  while (scanningRight || scanningLeft)
+  {
+    if (scanningRight)
+    {
+      if (itr == rightPts.end ()) scanningRight = false;
+      else
+        if (! addRight (*itr++)) scanningRight = false;
+    }
+    if (scanningLeft)
+    {
+      if (itl == leftPts.end ()) scanningLeft = false;
+      else
+        if (! addLeft (*itl++)) scanningLeft = false;
+    }
+  }
+}
+
+
+BSProto::~BSProto ()
+{
+  if (convexhull != NULL) delete convexhull;
+}
+
+
+EDist BSProto::strictThickness () const
+{
+  return (convexhull != NULL ? convexhull->thickness () : EDist (0, 1));
+}
+
+
+EDist BSProto::digitalThickness () const
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    DigitalStraightLine l (s, e, v);
+    return (EDist (l.width (), l.period ()));
+  }
+  return (EDist (1, 1));
+}
+
+
+DigitalStraightLine *BSProto::getLine () const
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    return (new DigitalStraightLine (s, e, v));
+  }
+  if (bsFlat || leftOK || rightOK)
+    return (new DigitalStraightLine (getLastLeft (), getLastRight (),
+                                     DigitalStraightLine::DSL_THIN));
+  return (NULL); // No line if only one point
+}
+
+
+bool BSProto::addLeftSorted (Pt2i pix)
+{
+  if (pix.equals (plist->frontPoint ()))
+  { 
+    plist->addFront (pix);
+    chChanged = false;
+    return true;
+  }
+  return addLeft (pix);
+}
+
+
+bool BSProto::addRightSorted (Pt2i pix)
+{
+  if (pix.equals (plist->backPoint ()))
+  {
+    plist->addBack (pix);
+    chChanged = false;
+    return true;
+  }
+  return addRight (pix);
+}
+
+
+bool BSProto::addLeft (Pt2i pix)
+{
+  if (bsOK)     // convexhull defined
+  {
+    bool res = addPoint (pix, true);
+    return (res);
+  }
+
+  else if (bsFlat)    // leftOK && rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () != 0)
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else if (leftOK)    // thus ! rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else if (rightOK)
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (pix, plist->frontPoint (),
+                                        plist->backPoint ());
+      bsOK = true;
+    }
+    plist->addFront (pix);
+  }
+
+  else   // only the central point is ok
+  {
+    plist->addFront (pix);
+    leftOK = true;
+  }
+
+  chChanged = true;
+  return true;
+}
+
+
+bool BSProto::addRight (Pt2i pix)
+{
+  if (bsOK)     // bs != NULL
+  {
+    bool res = addPoint (pix, false);
+    return (res);
+  }
+
+  else if (bsFlat)    // leftOK && rightOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () != 0)
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else if (rightOK)    // thus ! leftOK
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else if (leftOK)
+  {
+    EDist height = plist->heightToEnds (pix);
+    if (height.greaterThan (maxWidth)) return false;
+    if (height.num () == 0) bsFlat = true;
+    else
+    {
+      convexhull = new ConvexHull (plist->frontPoint (),
+                                   plist->backPoint (), pix);
+      bsOK = true;
+    }
+    plist->addBack (pix);
+  }
+
+  else   // only the central point is ok
+  {
+    plist->addBack (pix);
+    rightOK = true;
+  }
+
+  chChanged = true;
+  return true;
+}
+
+
+bool BSProto::addPoint (Pt2i p, bool onleft)
+{
+  bool inserted = convexhull->addPointDS (p, onleft);
+  if ((strictThickness ()).greaterThan (maxWidth))
+  {
+    if (inserted) convexhull->restore ();
+    return false;
+  }
+ 
+  if (onleft) plist->addFront (p);
+  else plist->addBack (p);
+  chChanged = true;
+  return true;
+}
+
+
+void BSProto::removeLeft (int n)
+{
+  if (bsOK) plist->removeFront (n);
+}
+
+
+void BSProto::removeRight (int n)
+{
+  if (bsOK) plist->removeBack (n);
+}
+ 
+
+Vr2i BSProto::getSupportVector ()
+{
+  if (bsOK)
+  {
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    return (s.vectorTo (e));
+  }
+  if (bsFlat || leftOK || rightOK)
+    return (getLastLeft().vectorTo (getLastRight ()));
+  return (Vr2i (1, 0));    // hardly better with only one point !
+}
+
+
+BlurredSegment *BSProto::endOfBirth ()
+{
+  DigitalStraightSegment *seg = NULL;
+  if (bsOK)
+  {
+    int xmin, ymin, xmax, ymax;
+    plist->findExtrema (xmin, ymin, xmax, ymax);
+    Pt2i s, e, v;
+    convexhull->antipodalEdgeAndVertex (s, e, v);
+    seg = new DigitalStraightSegment (s, e, v, xmin, ymin, xmax, ymax);
+  }
+  else if (bsFlat || rightOK || leftOK)
+  {
+    Pt2i llast = plist->frontPoint ();
+    Pt2i rlast = plist->backPoint ();
+    if (llast.equals (rlast)) // Strange, should not be flat, rightok or leftok
+    {
+      plist = NULL;
+      return (NULL);
+    }
+    int xmin = llast.x ();
+    if (rlast.x () < llast.x ()) xmin = rlast.x ();
+    int ymin = llast.y ();
+    if (rlast.y () < llast.y ()) ymin = rlast.y ();
+    int xmax = llast.x ();
+    if (rlast.x () > llast.x ()) xmax = rlast.x ();
+    int ymax = llast.y ();
+    if (rlast.y () > llast.y ()) ymax = rlast.y ();
+    seg = new DigitalStraightSegment (llast, rlast,
+                                      DigitalStraightLine::DSL_THIN,
+                                      xmin, ymin, xmax, ymax);
+  }
+  else return (NULL);
+  Pt2i aps (-1, -1), ape (-1, -1), apv (-1, -1);
+  if (convexhull != NULL)
+    convexhull->antipodalEdgeAndVertex (aps, ape, apv);
+  BlurredSegment *bbs = new BlurredSegment (plist, seg, aps, ape, apv);
+  plist = NULL;  // NECESSARY TO AVOID CONTENTS CLEARANCE !!!
+  return (bbs);
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/bsproto.h b/Expes/Testers/TestLines/BlurredSegment/bsproto.h
new file mode 100644
index 0000000..b315d75
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bsproto.h
@@ -0,0 +1,165 @@
+#ifndef BLURRED_SEGMENT_PROTO_H
+#define BLURRED_SEGMENT_PROTO_H
+
+#include "blurredsegment.h"
+
+
+/** 
+ * @class BSProto bsproto.h
+ * \brief A prototype of blurred segment, untill complete specification.
+ * It is mostly based on a evolving list of points, its convex hull and
+ * the successive states of the blurred segment construction.
+ * Replaces former deprecated BlurredSegmentProto class.
+ */
+class BSProto : public BlurredSegment
+{
+public:
+
+  /**
+   * \brief Creates a blurred segment prototype.
+   * @param maxWidth Maximal width of the blurred segment to build
+   * @param pix Central point of the blurred segment to build
+   */
+  BSProto (int maxWidth, Pt2i pix);
+
+  /**
+   * \brief Creates a blurred segment prototype with lists of points.
+   * @param maxWidth Maximal width of the blurred segment to build.
+   * @param center Central point of the blurred segment to build.
+   * @param leftPts Points to add on left side
+   * @param rightPts Points to add on right side.
+   */
+  BSProto (int maxWidth, Pt2i center,
+           const std::vector<Pt2i> &leftPts, const std::vector<Pt2i> &rightPts);
+
+  /**
+   * \brief Deletes the blurred segment prototype.
+   */
+  ~BSProto ();
+
+  /**
+   * \brief Checks if the blurred segment has at least two points.
+   */
+  inline bool isExtending () const {
+    return (bsOK || bsFlat || leftOK || rightOK); }
+
+  /**
+   * \brief Checks if the blurred segment is not flat (true BS).
+   */
+  inline bool isNotFlat () const { return (bsOK); }
+
+  /**
+   * \brief Returns the built-in blurred segment strict thickness.
+   * The strict thickness is the distance between bounding lines, ie (nu-1)/p.
+   */
+  EDist strictThickness () const;
+
+  /**
+   * \brief Returns the built-in blurred segment digital thickness.
+   * The digital thickness is the width of the digital straight line, ie nu/p.
+   */
+  EDist digitalThickness () const;
+
+  /**
+   * \brief Returns the assigned maximal width of the segment.
+   */
+  inline const EDist getMaxWidth () const { return maxWidth; }
+
+  /**
+   * \brief Sets the assigned maximal width of the segment.
+   * @param maxwidth New value for the assigned maximal width.
+   */
+  inline void setMaxWidth (const EDist &val) { maxWidth.set (val); }
+
+  /**
+   * \brief Returns the optimal digital straight line.
+   */
+  DigitalStraightLine *getLine () const;
+
+  /**
+   * \brief Adds a new sorted point to the left.
+   * Added point may coincide to previous one.
+   * Returns True if the point is inserted.
+   * @param pix Point to be added.
+   */
+  bool addLeftSorted (Pt2i pix);
+
+  /**
+   * Adds a new sorted point to the right.
+   * Added point may coincide to previous one.
+   * Returns True if the point is inserted.
+   * @param pix Point to be added.
+   */
+  bool addRightSorted (Pt2i pix);
+
+  /**
+   * Adds a new point on the left.
+   * Added point may not coincide to previous one.
+   * Returns true if the point is inserted.
+   * @param pix Point to be added.
+   */
+  bool addLeft (Pt2i pix);
+
+  /**
+   * Adds a new point on the right.
+   * Added point may not coincide to previous one.
+   * Returns true if the point is inserted.
+   * @param pix Point to be added.
+   */
+  bool addRight (Pt2i pix);
+
+  /**
+   * \brief Remove last points on the left side.
+   * @param n Amount of points to remove.
+   */
+  void removeLeft (int n);
+
+  /**
+   * \brief Remove last points on the right side.
+   * @param n Amount of points to remove.
+   */
+  void removeRight (int n);
+
+  /**
+   * \brief Returns the support vector of the blurred segment.
+   */
+  Vr2i getSupportVector ();
+
+  /**
+   * \brief Returns a static blurred segment.
+   * The returned blurred segment can not be extended anymore.
+   * Returns NULL if the segment is inconsistent (less than 2 points).
+   */
+  BlurredSegment *endOfBirth ();
+
+
+protected:
+
+  /** Maximal width of the blurred segment. */
+  EDist maxWidth;
+
+  /** Maintained convex hull of the blurred segment. */
+  ConvexHull *convexhull;
+
+  /** Indicates if the blurred segment is constructed. */
+  bool bsOK;
+  /** Indicates if the points are aligned. */
+  bool bsFlat;
+  /** Indicates if the left point is defined. */
+  bool leftOK;
+  /** Indicates if the right point is defined. */
+  bool rightOK;
+
+  /** Flag indicating if the convex hull changed since last DSS extraction. */
+  bool chChanged;
+
+
+  /**
+   * \brief Submits a new point to extend the blurred segment.
+   * @param p Submitted point.
+   * @param onleft Adding direction (true for LEFT, false for RIGHT).
+   */
+  bool addPoint (Pt2i p, bool onleft);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/bstracker.cpp b/Expes/Testers/TestLines/BlurredSegment/bstracker.cpp
new file mode 100644
index 0000000..6e148b9
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bstracker.cpp
@@ -0,0 +1,422 @@
+#include "bstracker.h"
+#include "bsproto.h"
+
+
+const int BSTracker::DEFAULT_PROX_THRESHOLD = 10;
+const int BSTracker::MIN_SCAN = 8;
+const int BSTracker::DEFAULT_MAX_SCAN = 32;
+const int BSTracker::DEFAULT_FITTING_DELAY = 20;
+
+const int BSTracker::DEFAULT_ASSIGNED_THICKNESS_CONTROL_DELAY = 20;
+
+const int BSTracker::FAILURE_NO_START = 1;
+const int BSTracker::FAILURE_IMAGE_BOUND_ON_RIGHT = 2;
+const int BSTracker::FAILURE_IMAGE_BOUND_ON_LEFT = 4;
+const int BSTracker::FAILURE_LOST_ORIENTATION = 32;
+
+
+
+BSTracker::BSTracker ()
+{
+  proxTestOff = true;
+  proxThreshold = DEFAULT_PROX_THRESHOLD;
+  maxScan = DEFAULT_MAX_SCAN;
+  fail_status = 0;
+
+  fittingDelay = DEFAULT_FITTING_DELAY;
+  assignedThicknessControlDelay = DEFAULT_ASSIGNED_THICKNESS_CONTROL_DELAY;
+  recordScans = false;
+
+  gMap = NULL;
+  cand = new int[1]; // to avoid systematic tests
+}
+
+
+BSTracker::~BSTracker ()
+{
+  delete cand;
+}
+
+
+void BSTracker::clear ()
+{
+  scanBound1.clear ();
+  scanBound2.clear ();
+  scanLine.clear ();
+}
+
+
+void BSTracker::setGradientMap (VMap *data)
+{
+  gMap = data;
+  scanp.setSize (gMap->getWidth (), gMap->getHeight ());
+  delete cand;
+  cand = new int[data->getHeightWidthMax ()];
+}
+
+
+BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2,
+                                      int bsMaxWidth, int acceptedLacks,
+                                      int swidth, const Pt2i &pc)
+{
+  // Creates a static directional scanner
+  DirectionalScanner *ds = NULL;
+  if (swidth != 0)
+  {
+    if (swidth < MIN_SCAN) swidth = MIN_SCAN;
+    ds = scanp.getScanner (pc, p1.vectorTo (p2), swidth, false);
+  }
+  else ds = scanp.getScanner (p1, p2);
+  if (ds == NULL) return NULL;
+
+  // Gets a first scan
+  std::vector<Pt2i> pix;
+  if (ds->first (pix) < MIN_SCAN)
+  {
+    delete ds;
+    return NULL;
+  }
+  if (recordScans)
+  {
+    scanBound1.push_back (pix.front ());
+    scanBound2.push_back (pix.back ());
+    scanLine.push_back (pix);
+  }
+
+  // Initializes a blurred segment with a first candidate
+  int candide;
+  Pt2i pfirst;
+  if (swidth != 0) pfirst.set (pc.x (), pc.y ());
+  else
+  {
+    candide = gMap->largestIn (pix);
+    if (candide == -1)
+    {
+      delete ds;
+      return NULL;
+    }
+    pfirst.set (pix.at (candide));
+  }
+  BSProto bsp (bsMaxWidth, pfirst);
+  Pt2i lastLeft (pfirst);
+  Pt2i lastRight (pfirst);
+  
+  // Extends the segment
+  int lstop = 0;
+  int rstop = 0;
+  bool added = false;
+  bool scanningRight = true;
+  bool scanningLeft = true;
+  int fsCount = maxScan;
+
+  while ((scanningRight || scanningLeft) && (fsCount--))
+  {
+    // Extends on right
+    if (scanningRight)
+    {
+      // Gets next scan
+      if (ds->nextOnRight (pix) < MIN_SCAN) scanningRight = false;
+      else
+      {
+        if (recordScans)
+        {
+          scanBound1.push_back (pix.front ());
+          scanBound2.push_back (pix.back ());
+          scanLine.push_back (pix);
+        }
+
+        // Gets and tests a new candidate
+        added = false;
+        candide = gMap->largestIn (pix);
+        if (candide != -1)
+        {
+          if (proxTestOff
+              || lastRight.manhattan (pix.at (candide)) <= proxThreshold)
+            added = bsp.addRight (pix.at (candide));
+        }
+        if (added)
+        {
+          lastRight.set (pix.at (candide));
+          if (rstop != 0) rstop = 0;
+        }
+        else if (++rstop > acceptedLacks) scanningRight = false;
+      }
+    }
+
+    // Extends on left
+    if (scanningLeft)
+    {
+      // Gets next scan
+      if (ds->nextOnLeft (pix) < MIN_SCAN) scanningLeft = false;
+      else
+      {
+        if (recordScans)
+        {
+          scanBound1.push_back (pix.front ());
+          scanBound2.push_back (pix.back ());
+          scanLine.push_back (pix);
+        }
+
+        // Gets and tests a new candidate
+        added = false;
+        candide = gMap->largestIn (pix);
+        if (candide != -1)
+        {
+          if (proxTestOff
+              || lastLeft.manhattan (pix.at (candide)) <= proxThreshold)
+            added = bsp.addLeft (pix.at (candide));
+        }
+        if (added)
+        {
+          lastLeft.set (pix.at (candide));
+          if (lstop != 0) lstop = 0;
+        }
+        else if (++lstop > acceptedLacks) scanningLeft = false;
+      }
+    }
+  }
+  delete ds;
+
+  // Validates (regenerates) and returns the blurred segment
+  BlurredSegment *bs = bsp.endOfBirth ();
+  if (bs != NULL)
+  {
+    if (swidth != 0) bs->setScan (pc, p1.vectorTo (p2));
+    else bs->setScan (p1, p2);
+  }
+  return (bs);
+}
+
+
+
+BlurredSegment *BSTracker::fineTrack (const Pt2i &center, const Vr2i &scandir,
+                                      int bsMaxWidth, int acceptedLacks,
+                                      const Vr2i &gref)
+{
+  // Checks scan width minimal size
+  int scanwidth = 2 * bsMaxWidth;
+  if (scanwidth < MIN_SCAN) scanwidth = MIN_SCAN;
+
+  // Gets detected segment normal vector
+  Vr2i normal = scandir.orthog ();
+  if (! normal.directedAs (gref)) normal.invert ();
+
+  fail_status = 0;
+
+  // Creates an adaptive directional scanner
+  DirectionalScanner *ds = scanp.getScanner (center, normal, scanwidth, true);
+  if (ds == NULL)
+  {
+    fail_status = FAILURE_NO_START;
+    return NULL;
+  }
+
+  // Looks for a central point
+  std::vector<Pt2i> pix;
+  if (ds->first (pix) < MIN_SCAN)
+  {
+    delete ds;
+    fail_status = FAILURE_NO_START;
+    return NULL;
+  }
+  if (recordScans)
+  {
+    scanBound1.push_back (pix.front ());
+    scanBound2.push_back (pix.back ());
+    scanLine.push_back (pix);
+  }
+
+  // Gets candidates: sorted local max of gradient magnitude
+  int nbc = gMap->localMax (cand, pix, normal);
+  if (nbc == 0)
+  {
+    delete ds;
+    fail_status = FAILURE_NO_START;
+    return NULL;
+  }
+
+  // Initializes a blurred segment with the first candidate
+  BSProto bsp (bsMaxWidth, pix[cand[0]]);
+
+  // Handles assigned thickness control
+  bool atcOn = true;
+  int stab_count = 0;
+  int count = 0;
+
+  // Extends the segment
+  int lstop = 0;
+  int rstop = 0;
+  int lstart = 0;
+  int rstart = 0;
+  bool added = false;
+  bool scanningRight = true;
+  bool scanningLeft = true;
+
+  while (scanningRight || scanningLeft)
+  {
+    count ++;
+    EDist sw = bsp.strictThickness ();
+
+    // Handles assigned thickness control
+    if (atcOn && stab_count >= assignedThicknessControlDelay)
+    {
+      EDist finalWidth (bsp.digitalThickness().sumWithOneHalf ());
+      if (finalWidth.lessThan (bsp.getMaxWidth ()))
+        bsp.setMaxWidth (finalWidth);
+      atcOn = false;
+    }
+
+    // Resets the scan strip
+    if (count > fittingDelay && bsp.isExtending ())
+    {
+      // Stops the detection if the segment gets crosswise
+      if (count == fittingDelay + 1)
+      {
+        Vr2i dirn = bsp.getSupportVector ();
+        if (4 * dirn.squaredScalarProduct (scandir)
+            < 3 * dirn.norm2 () * scandir.norm2 ())  // div. angle > 30 degrees
+        {
+          scanningLeft = false;
+          scanningRight = false;
+          fail_status += FAILURE_LOST_ORIENTATION;
+        }
+      }
+      int ppa, ppb, ppc;
+      bsp.getLine()->getCentralLine (ppa, ppb, ppc);
+      ds->bindTo (ppa, ppb, ppc);
+    }
+
+    // Extends on right
+    if (scanningRight)
+    {
+      // Gets next scan
+      if (ds->nextOnRight (pix) < MIN_SCAN)
+      {
+        fail_status += FAILURE_IMAGE_BOUND_ON_RIGHT;
+        scanningRight = false;
+      }
+      else
+      {
+        if (recordScans)
+        {
+          scanBound1.push_back (pix.front ());
+          scanBound2.push_back (pix.back ());
+          scanLine.push_back (pix);
+        }
+
+        // Gets and tries candidates: sorted local max of gradient magnitude
+        added = false;
+        nbc = gMap->localMax (cand, pix, normal);
+        for (int i = 0; ! added && i < nbc; i++)
+          added = bsp.addRight (pix[cand[i]]);
+        stab_count ++;
+        if (added)
+        {
+          // Checks if the segment width is stable
+          if (atcOn && sw.lessThan (bsp.strictThickness ())) stab_count = 0;
+
+          // Handles detection interruptions
+          if (rstop == 0) rstart = 0;
+          else
+          {
+            rstart ++;
+            if (rstart >= rstop)
+            {
+              rstop = 0;
+              rstart = 0;
+            }
+          }
+        }
+        else
+        {
+          if (++rstop - rstart > acceptedLacks)
+          {
+            if (bsp.size () <= 3) fail_status = FAILURE_NO_START;
+            scanningRight = false;
+          }
+        }
+      }
+    }
+
+    // Extends on left
+    if (scanningLeft)
+    {
+      // Gets next scan
+      if (ds->nextOnLeft (pix) < MIN_SCAN)
+      {
+        fail_status += FAILURE_IMAGE_BOUND_ON_LEFT;
+        scanningLeft = false;
+      }
+      else
+      {
+        if (recordScans)
+        {
+          scanBound1.push_back (pix.front ());
+          scanBound2.push_back (pix.back ());
+          scanLine.push_back (pix);
+        }
+
+        // Gets and tries candidates: sorted local max of gradient magnitude
+        added = false;
+        nbc = gMap->localMax (cand, pix, normal);
+        for (int i = 0; ! added && i < nbc; i++)
+          added = bsp.addLeft (pix[cand[i]]);
+        stab_count ++;
+        if (added)
+        {
+          // Checks if the segment width is stable
+          if (atcOn && sw.lessThan (bsp.strictThickness ())) stab_count = 0;
+
+          // Handles detection interruptions
+          if (lstop == 0) lstart = 0;
+          else
+          {
+            lstart ++;
+            if (lstart >= lstop)
+            {
+              lstop = 0;
+              lstart = 0;
+            }
+          }
+        }
+        else
+        {
+          if (++lstop - lstart > acceptedLacks)
+          {
+            if (bsp.size () <= 3) fail_status = FAILURE_NO_START;
+            scanningLeft = false;
+          }
+        }
+      }
+    }
+  }
+  if (rstart) bsp.removeRight (rstart);
+  if (lstart) bsp.removeLeft (lstart);
+  delete ds;
+
+  // Validates (regenerates) and returns the blurred segment
+  BlurredSegment *bs = bsp.endOfBirth ();
+  if (bs != NULL) bs->setScan (center, normal);
+  return (bs);
+}
+
+
+void BSTracker::incProximityThreshold (bool inc)
+{
+  proxThreshold += (inc ? 1 : -1);
+  if (proxThreshold < 1) proxThreshold = 1;
+}
+
+
+void BSTracker::incAssignedThicknessControlDelay (int val)
+{
+  assignedThicknessControlDelay += val;
+  if (assignedThicknessControlDelay < 1) assignedThicknessControlDelay = 1;
+}
+
+
+void BSTracker::switchScanExtent ()
+{
+  maxScan = (maxScan == gMap->getHeightWidthMax () ?
+             DEFAULT_MAX_SCAN : gMap->getHeightWidthMax ());
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/bstracker.h b/Expes/Testers/TestLines/BlurredSegment/bstracker.h
new file mode 100644
index 0000000..681ccf4
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/bstracker.h
@@ -0,0 +1,200 @@
+#ifndef BLURRED_SEGMENT_TRACKER_H
+#define BLURRED_SEGMENT_TRACKER_H
+
+#include "scannerprovider.h"
+#include "blurredsegment.h"
+#include "vmap.h"
+
+
+/** 
+ * @class BSTracker bstracker.h
+ * \brief Blurred segment tracker in grey level images.
+ */
+class BSTracker
+{
+public:
+
+  /** Minimal length of scan length to be processed. */
+  static const int MIN_SCAN;
+
+  
+  /**
+   * \brief Creates a blurred segment tracker.
+   */
+  BSTracker ();
+
+  /**
+   * \brief Deletes the blurred segment tracker.
+   */
+  ~BSTracker ();
+
+  /**
+   * \brief Clears off stored information.
+   */
+  void clear ();
+
+  /**
+   * \brief Sets the image data.
+   * @param data Reference to gradient map to be processed.
+   */
+  void setGradientMap (VMap *data);
+
+  /**
+   * \brief Builds and returns a blurred segment from only gradient maximum.
+   * @param p1 Initial stroke start point.
+   * @param p2 Initial stroke end point.
+   * @param bsMaxWidth Blurred segment assigned maximal width.
+   * @param acceptedLacks Count of maximal successive detection fails.
+   * @param swidth Set to 0 if no start point is provided.
+   * @param pc Initial segment start point (if swidth is set).
+   */
+  BlurredSegment *fastTrack (const Pt2i &p1, const Pt2i &p2,
+                             int bsMaxWidth, int acceptedLacks,
+                             int swidth = 0, const Pt2i &pc = Pt2i ());
+
+  /**
+   * \brief Builds and returns a blurred segment from local gradient maxima.
+   * Finer detection using gradient ridges and direction input.
+   * @param center Central point of the scan.
+   * @param scandir Scan strip direction.
+   * @param bsMaxWidth Initial assigned maximal width of the blurred segment.
+   * @param acceptedLacks Count of maximal successive detection fails.
+   * @param gref Gradient vector reference to select candidates.
+   */
+  BlurredSegment *fineTrack (const Pt2i &center, const Vr2i &scandir,
+                             int bsMaxWidth, int acceptedLacks,
+                             const Vr2i &gref);
+
+  /**
+   * \brief Returns the proximity test status.
+   */
+  inline bool proximityConstraintOn () const { return (! proxTestOff); }
+
+  /**
+   * \brief Switches on or off the proximity test used for fast tracking.
+   */
+  inline void switchProximityConstraint () { proxTestOff = ! proxTestOff; }
+
+  /**
+   * \brief Returns the proximity threshold used for fast tracking.
+   */
+  inline int getProximityThreshold () const { return proxThreshold; }
+
+  /**
+   * \brief Increments the proximity threshold used for fast tracking.
+   * @param bool Increment value.
+   */
+  void incProximityThreshold (bool inc);
+
+  /**
+   * \brief Returns the registered upper bounds of the final scan lines.
+   * @param side Upper bound if set to 1, lower bound otherwise.
+   */
+  inline std::vector<Pt2i> getScanBound (int side) const {
+    return (side == 1 ? scanBound1 : scanBound2); }
+
+  /**
+   * \brief Returns the registered scan lines.
+   */
+  inline const std::vector <std::vector <Pt2i> > &getScans () const {
+    return scanLine; }
+
+  /**
+   * \brief Returns whether the scan record modality is set.
+   */
+  inline bool scanRecordOn () { return recordScans; }
+
+  /**
+   * \brief Sets the scan record modality.
+   * @param status Sets on if true, off otherwise.
+   */
+  inline void setScanRecord (bool status) { recordScans = status; }
+
+  /**
+   * \brief Switches the scan extent limitation.
+   */
+  void switchScanExtent ();
+
+  /**
+   * \brief Returns the scan extent limit.
+   */
+  inline int maxScanExtent () { return (maxScan); }
+
+  /**
+   * \brief Returns the assigned thickness control delay.
+   */
+  inline int getAssignedThicknessControlDelay () const {
+    return assignedThicknessControlDelay; }
+
+  /**
+   * \brief Increments the assigned thickness control delay.
+   * @param val New value for the delay of assigned thickness control start.
+   */
+  void incAssignedThicknessControlDelay (int val);
+
+
+private :
+
+  // Segment detection default parameters.
+  /** Default value for the proximity test used for fast tracking. */
+  static const int DEFAULT_PROX_THRESHOLD;
+  /** Default value for the maximal number of scans processed on each side. */
+  static const int DEFAULT_MAX_SCAN;
+
+  // Adaptive scan default parameters.
+  /* Count of points before activating the fitting on the detected segment. */
+  static const int DEFAULT_FITTING_DELAY;
+  /* Maximal count of points before activating assigned thickness control. */
+  static const int DEFAULT_ASSIGNED_THICKNESS_CONTROL_DELAY;
+
+  /** Segment stop information : no start point found. */
+  static const int FAILURE_NO_START;
+  /** Segment stop information : image bound reached on the right. */
+  static const int FAILURE_IMAGE_BOUND_ON_RIGHT;
+  /** Segment stop information : image bound reached on the left. */
+  static const int FAILURE_IMAGE_BOUND_ON_LEFT;
+  /** Segment stop information : lost orientation at dynamical reset start. */
+  static const int FAILURE_LOST_ORIENTATION;
+
+
+  /** Scanned map left bound. */
+  int xmin;
+  /** Scanned map lower bound. */
+  int ymin;
+  /** Scanned map width. */
+  int width;
+  /** Scanned map height. */
+  int height;
+
+  /** Reference to processed gradient map. */
+  VMap *gMap;
+  /** Candidates array for internal use. */
+  int *cand;
+  /** Failure cause registration. */
+  int fail_status;
+
+  /** Directional scanner provider (selects relevant octant). */
+  ScannerProvider scanp;
+  /** Dynamical scanner record modality. */
+  bool recordScans;
+  /** Upper bound of the scan. */
+  std::vector<Pt2i> scanBound1;
+  /** Lower bound of the scan. */
+  std::vector<Pt2i> scanBound2;
+  /** Scan lines. */
+  std::vector <std::vector <Pt2i> > scanLine;
+
+  /** Maximum number of scans to process at fast tracking stage. */
+  int maxScan;
+  /** Minimal detection width before activating the dynamical scans. */
+  int fittingDelay;
+  /** Count of stable point insertion before activation of ATC. */
+  int assignedThicknessControlDelay;
+
+  /** Status of the proximity constraint used for fast tracking. */
+  bool proxTestOff;   // DVPT
+  /** Proximity threshold used for fast tracking. */
+  int proxThreshold;  // DVPT
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/changed b/Expes/Testers/TestLines/BlurredSegment/changed
new file mode 100644
index 0000000..c398e67
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/changed
@@ -0,0 +1,14 @@
+cmp biptlist.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/biptlist.cpp
+cmp biptlist.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/biptlist.h
+cmp blurredsegment.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/blurredsegment.cpp
+cmp blurredsegment.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/blurredsegment.h
+cmp blurredsegmentproto.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/blurredsegmentproto.cpp
+cmp blurredsegmentproto.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/blurredsegmentproto.h
+cmp bsdetector.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bsdetector.cpp
+cmp bsdetector.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bsdetector.h
+cmp bsproto.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bsproto.cpp
+cmp bsproto.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bsproto.h
+cmp bstracker.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bstracker.cpp
+cmp bstracker.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/bstracker.h
+cmp nfafilter.cpp ~/git/2019-FBSD/Code/FBSD/BlurredSegment/nfafilter.cpp
+cmp nfafilter.h ~/git/2019-FBSD/Code/FBSD/BlurredSegment/nfafilter.h
diff --git a/Expes/Testers/TestLines/BlurredSegment/nfafilter.cpp b/Expes/Testers/TestLines/BlurredSegment/nfafilter.cpp
new file mode 100755
index 0000000..958d8d6
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/nfafilter.cpp
@@ -0,0 +1,139 @@
+#include <cmath>
+#include "nfafilter.h"
+
+const double NFAFilter::NFA_EPSILON = 1.0;
+const double NFAFilter::DEFAULT_LRATIO = 1.0;
+//const double NFAFilter::DEFAULT_LRATIO = 2.25;
+const int NFAFilter::DEFAULT_MIN_SECTION_LENGTH = 3;
+
+
+NFAFilter::NFAFilter ()
+{
+  min_section_length = DEFAULT_MIN_SECTION_LENGTH;
+  max_grad2 = 0;
+  gradient_map = NULL;
+  cum_histo = NULL;
+  bs_section_count = 0;
+  lratio = DEFAULT_LRATIO;
+}
+
+
+NFAFilter::~NFAFilter ()
+{
+  delete [] cum_histo;
+}
+
+
+void NFAFilter::init (VMap *gmap)
+{
+  // Stores the reference to the gradient map
+  gradient_map = gmap;
+  int width = gradient_map->getWidth ();
+  int height = gradient_map->getHeight ();
+
+  // Counts the number of non-gradient pixels
+  int m = 0;
+  max_grad2 = 0;
+  for (int j = 0; j < height; j++)
+  {
+    for (int i = 0; i < width; i++)
+    {
+      int gradval = gradient_map->sqNorm (i, j);
+      if (gradval != 0)
+      {
+        m++;
+        if (gradval > max_grad2) max_grad2 = gradval;
+      }
+    }
+  }
+
+  // Rectification 
+  m = (width -2) * (height - 2);
+
+  // Gets gradient histogram
+  int gmax = (int) (sqrt (max_grad2));
+  cum_histo = new double[gmax + 1];
+  for (int j = 0; j < height; j++)
+    for (int i = 0; i < width; i++)
+      cum_histo[(int) (sqrt (gradient_map->sqNorm (i, j)))] ++;
+
+  // Gets cumulated histogram
+  for (int i = gmax; i > 0; i--)
+    cum_histo[i-1] += cum_histo[i];
+
+  // Normalization
+  for (int i = 0; i <= gmax; i++)
+    cum_histo[i] /= m;
+}
+
+
+double NFAFilter::nfaValue (double proba, int length)
+{
+  length = (int) (length / lratio); // Magic number : divForTestSeg
+  double nfa = bs_section_count;
+  for (int i = 0; i < length && nfa > NFA_EPSILON; i++) nfa *= proba;
+  return nfa;
+}
+
+
+bool NFAFilter::filter (const BlurredSegment *bs, int start, int end)
+{
+  int length = end - start;
+  if (length < min_section_length) return false;
+
+  // Gets point with small gradient
+  int gmin = max_grad2;
+//  int pmin = -1;
+  std::vector<Pt2i> pts = bs->getAllPoints ();
+  for (int i = start; i < end; i++)
+  {
+    int gn = (gradient_map->getValue (pts[i])).norm2 ();
+    if (gn < gmin)
+    {
+      gmin = gn;
+//      pmin = i;
+    }
+  }
+
+  // Gets NFA and accept or split the segment
+  double nfa = nfaValue (cum_histo[(int) (sqrt (gmin))], length);
+  return (nfa < NFA_EPSILON);
+//  if (nfa < NFA_EPSILON) return true;
+//  return (filter (bs, start, pmin) && filter (bs, pmin + 1, end));
+}
+
+
+void NFAFilter::filter (const std::vector<BlurredSegment *> &bss,
+                        std::vector<BlurredSegment *> &vsegs,
+                        std::vector<BlurredSegment *> &rsegs)
+{
+  vsegs.clear ();
+  rsegs.clear ();
+
+  // Computes Np
+  bs_section_count = 0;
+  std::vector<BlurredSegment *>::const_iterator it = bss.begin ();
+  while (it != bss.end ())
+  {
+    int length = (*it)->size ();
+    bs_section_count += length * (length - 1) / 2;
+    it ++;
+  }
+
+  // Computes and test each segment NFA
+  it = bss.begin ();
+  while (it != bss.end ())
+  {
+    if (filter (*it, 0, (*it)->size ())) vsegs.push_back (*it);
+    else rsegs.push_back (*it);
+    it ++;
+  }
+}
+
+
+void NFAFilter::incLengthRatio (int inc)
+{
+  lratio += inc * 0.05;
+  if (lratio < 1.0) lratio = 1.0;
+  else if (lratio > 3.0) lratio = 3.0;
+}
diff --git a/Expes/Testers/TestLines/BlurredSegment/nfafilter.h b/Expes/Testers/TestLines/BlurredSegment/nfafilter.h
new file mode 100755
index 0000000..79c0055
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/nfafilter.h
@@ -0,0 +1,94 @@
+#ifndef NFA_FILTER_H
+#define NFA_FILTER_H
+
+#include "blurredsegment.h"
+#include "vmap.h"
+
+
+/** 
+ * @class NFAFilter nfafilter.h
+ * \brief Number of false alarm based filter for selecting blurred segments.
+ */
+class NFAFilter
+{
+public:
+
+  /**
+   * \brief Creates an empty NFA-based filter.
+   */
+  NFAFilter ();
+
+  /**
+   * \brief Deletes the filter.
+   */
+  ~NFAFilter ();
+
+  /**
+   * \brief Initializes the filter before any detection.
+   * @param gmap Reference to used gradient map.
+   */
+  void init (VMap *gmap);
+
+  /**
+   * \brief Filters a set of blurred segments.
+   * @param bss Input set of blurred segments.
+   * @param vbss Output set of valid blurred segments.
+   * @param rbss Output set of rejected blurred segments.
+   */
+  void filter (const std::vector<BlurredSegment *> &bss,
+               std::vector<BlurredSegment *> &vbss,
+               std::vector<BlurredSegment *> &rbss);
+
+  /**
+   * \brief Returns the division ratio applied to chain length for NFA test.
+   */
+  inline double lengthRatio () const { return lratio; }
+
+  /**
+   * \brief Increments the division ratio applied to chain length for NFA test.
+   * @param inc Increment sign (-1 or +1).
+   */
+  void incLengthRatio (int inc);
+
+
+private :
+
+  /** Tolered number of false alarm expectation. */
+  static const double NFA_EPSILON;
+  /** Default length ratio for NFA measure. */
+  static const double DEFAULT_LRATIO;
+  /** Default value for the smallest blurred segment section considered. */
+  static const int DEFAULT_MIN_SECTION_LENGTH;
+
+  /** Smallest blurred segment section considered. */
+  int min_section_length;
+  /** Maximal squarred gradient value. */
+  int max_grad2;
+  /** Reference to used gradient map. */
+  VMap *gradient_map;
+  /** Cumulated gradient histogramm (H). */
+  double *cum_histo;
+  /** Count of any blurred segment sections (Np). */
+  int bs_section_count;
+
+  /** Division ratio applied to chain length for NFA test. */
+  double lratio;
+
+
+  /** 
+    * \brief Computes number of false alarms of a segment section.
+    * @param proba Validation probability associated to min gradient point.
+    * @param length Section length.
+    */
+  double nfaValue (double proba, int length);
+
+  /**
+    * \brief Filters a blurred segment section.
+    * @param bss Reference to input blurred segment.
+    * @param start Index of start point in the section.
+    * @param end Index of first point out of the section.
+    */
+  bool filter (const BlurredSegment *bs, int start, int end);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/BlurredSegment/rechanged b/Expes/Testers/TestLines/BlurredSegment/rechanged
new file mode 100644
index 0000000..27a1635
--- /dev/null
+++ b/Expes/Testers/TestLines/BlurredSegment/rechanged
@@ -0,0 +1,12 @@
+cmp biptlist.cpp ~/tmp/ASD/BlurredSegment/biptlist.cpp
+cmp biptlist.h ~/tmp/ASD/BlurredSegment/biptlist.h
+cmp blurredsegment.cpp ~/tmp/ASD/BlurredSegment/blurredsegment.cpp
+cmp blurredsegment.h ~/tmp/ASD/BlurredSegment/blurredsegment.h
+cmp bsdetector.cpp ~/tmp/ASD/BlurredSegment/bsdetector.cpp
+cmp bsdetector.h ~/tmp/ASD/BlurredSegment/bsdetector.h
+cmp bsproto.cpp ~/tmp/ASD/BlurredSegment/bsproto.cpp
+cmp bsproto.h ~/tmp/ASD/BlurredSegment/bsproto.h
+cmp bstracker.cpp ~/tmp/ASD/BlurredSegment/bstracker.cpp
+cmp bstracker.h ~/tmp/ASD/BlurredSegment/bstracker.h
+cmp bsfilter.cpp ~/tmp/ASD/BlurredSegment/bsfilter.cpp
+cmp bsfilter.h ~/tmp/ASD/BlurredSegment/bsfilter.h
diff --git a/Expes/Testers/TestLines/ConvexHull/antipodal.cpp b/Expes/Testers/TestLines/ConvexHull/antipodal.cpp
new file mode 100644
index 0000000..992f524
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/antipodal.cpp
@@ -0,0 +1,335 @@
+#include "antipodal.h"
+
+
+Antipodal::Antipodal ()
+{
+  ix = 0;
+  iy = 1;
+  vpt = NULL;
+  ept1 = NULL;
+  ept2 = NULL;
+}
+
+
+void Antipodal::init (CHVertex *v1, CHVertex *v2, CHVertex *v3)
+{
+  if (v1->get (iy) < v2->get (iy))
+  {
+    if (v2->get (iy) < v3->get (iy))
+    {
+      vpt = v2;
+      ept1 = v1;
+      ept2 = v3;
+    }
+    else
+    {
+      if (v1->get (iy) < v3->get (iy))
+      {
+        vpt = v3;
+        ept1 = v1;
+        ept2 = v2;
+      }
+      else
+      {
+        vpt = v1;
+        ept1 = v2;
+        ept2 = v3;
+      }
+    }
+  }
+  else
+  {
+    if (v1->get (iy) < v3->get (iy))
+    {
+      vpt = v1;
+      ept1 = v2;
+      ept2 = v3;
+    }
+    else
+    {
+      if (v2->get (iy) <= v3->get (iy))     // EQUIV : rather than "<" !!!
+      {
+        vpt = v3;
+        ept1 = v1;
+        ept2 = v2;
+      }
+      else
+      {
+        vpt = v2;
+        ept1 = v1;
+        ept2 = v3;
+      }
+    }
+  }
+}
+
+
+EDist Antipodal::thickness () const
+{
+  int den = ept2->get (iy) - ept1->get (iy);
+  return (EDist (((vpt->get (ix) - ept1->get (ix)) * den
+                  - (vpt->get (iy) - ept1->get (iy))
+                    * (ept2->get (ix) - ept1->get (ix))), den));
+}
+
+
+int Antipodal::remainder (CHVertex *v) const
+{
+  int a = ept2->y () - ept1->y ();
+  int b = ept2->x () - ept1->x ();
+  if (a == 0) return ((b > 0 ? -b : b) * v->y ());
+  if (a < 0)
+  {
+    a = -a;
+    b = -b;
+  }
+  return (a * v->x () - b * v->y ());
+}
+
+
+bool Antipodal::edgeInFirstQuadrant () const
+{
+  if (iy) return true;
+  int a = ept2->y () - ept1->y ();
+  if (a == 0) return true;
+  return (a > 0 ? (ept1->x () < ept2->x ()) : (ept2->x () < ept1->x ()));
+}
+
+
+int Antipodal::getA () const
+{
+  int a = ept2->y () - ept1->y ();
+  return (a < 0 ? -a : a);
+}
+
+
+int Antipodal::getB () const
+{
+  int a = ept2->y () - ept1->y ();
+  int b = ept2->x () - ept1->x ();
+  if (a < 0) b = -b;
+  else if (a == 0 && b < 0) b = -b;
+  return (b);
+}
+
+
+/*
+ostream& operator<< (ostream &os, const Antipodal &ap)
+{
+  os << (ap.ix ? "AV [" : "AH [") << *(ap.vpt) << " + ("
+     << *(ap.ept1) << " - " << *(ap.ept2) << ")]";
+  if (ap.remainder (ap.vpt) == ap.remainder (ap.ept1)) os << "--HS--";
+  return os;
+}
+*/
+
+
+void Antipodal::update (CHVertex *pt)
+{
+  CHVertex *rpt = pt->right ();
+  CHVertex *lpt = pt->left ();
+
+  int rmp = remainder (pt);
+  int rmv = remainder (vpt);
+  int rme = remainder (ept1);
+  int zpt = pt->get (iy);     // vertical AP : Z -> X -- horizontal AP : Z -> Y
+  int zav = vpt->get (iy);    // coord of antipodal vertex
+  int zas = ept1->get (iy);   // coord of antipodal edge start
+  int zae = ept2->get (iy);   // coord of antipodal edge end
+
+  CHVertex *pvertex;
+  if (remainder (rpt) == rmv) pvertex = rpt;
+  else if (remainder (lpt) == rmv) pvertex = lpt;
+  else pvertex = vpt;
+
+  CHVertex *pedge;
+  if (remainder (rpt) == rme) pedge = rpt;
+  else if (remainder (lpt) == rme) pedge = lpt;
+  else pedge = ept1;
+
+
+  // P on the line supported by the Edge
+  if (rmp == rme)
+  {
+    // P between start end end of antipodal Edge : no change (IMPOSSIBLE)
+    if ((zpt == zas) || (zpt == zae) || ((zpt < zas) != (zpt < zae))) return;
+    // -> prolongation of antipodal Edge up to P
+    setEdge (pt, pedge);
+    return;
+  }
+
+  // P on the line (parallel to Edge) supported by the Vertex
+  if (rmp == rmv)
+  {
+    // P at the height of Edge -> P is the new Vertex
+    if ((zpt == zas) || (zpt == zae) || ((zpt < zas) != (zpt < zae)))
+      setVertex (pt);
+    else
+    {
+      // P beyond Edge Start : -> the Edge Start is the new Vertex
+      if ((zas == zae) || ((zas < zpt) != (zas < zae))) setVertex (ept1);
+      // P beyond Edge End : -> the Edge End is the new Vertex
+      if ((zae < zpt) != (zae < zas)) setVertex (ept2);
+      // -> the new Edge joins P to the former Vertex
+      setEdge (pt, pvertex);
+    }
+    return;
+  }
+ 
+  // P strictly between antipodal Edge and Vertex -> no change
+  if ((rmp < rmv) != (rmp < rme)) return;
+
+
+  // P at the height of the antipodal Vertex
+  if (zpt == zav)
+  {
+    // P beyond the antipodal Vertex
+    if ((rmv < rmp) != (rmv < rme))
+    {				
+      // -> P is the new Vertex
+      setVertex (pt);
+      return;
+    }
+
+    CHVertex *oldvpt = vpt;
+    if (zav != lpt->get (iy))
+    {
+      if (oldvpt->vprod (oldvpt->left (), lpt, pt) > 0)
+      {
+        setVertex (oldvpt);
+        setEdge (lpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (oldvpt, oldvpt->left ());
+      }
+    }
+    else
+    {
+      if (oldvpt->vprod (oldvpt->right (), rpt, pt) < 0)
+      {
+        setVertex (oldvpt);
+        setEdge (rpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (oldvpt, oldvpt->right ());
+      }
+    }
+    return;
+  }
+
+
+  // Main case
+  //==============================================================
+  CHVertex *cvx = NULL;   // candidate rotation vertex
+  CHVertex *lvx, *rvx;    // left and right vertices of candidate
+  int zvx;                // coord of candidate
+
+  bool firstQuad = true;
+  if (edgeInFirstQuadrant ())
+  {
+    if (((rmp > rme) && (rmp > rmv) && (zpt > zav))
+        || ((rmp < rme) && (rmp < rmv) && (zpt < zav))) firstQuad = false;
+  }
+  else
+    if (((rmp > rme) && (rmp > rmv) && (zpt < zav))
+        || ((rmp < rme) && (rmp < rmv) && (zpt > zav))) firstQuad = false;
+
+  if (firstQuad)
+  {
+    if ((rme < rmp) != (rme < rmv)) cvx = pvertex;
+    if ((rmv < rme) != (rmv < rmp))
+      cvx = (ept1->right () == ept2 ? ept1 : ept2);
+    zvx = cvx->get (iy);
+    lvx = cvx->left ();
+    rvx = cvx->right ();
+
+    while (cvx->vprod (rvx, rpt, pt) > 0)
+    {
+      cvx = rvx;
+      lvx = cvx->left ();
+      rvx = cvx->right ();
+      zvx = cvx->get (iy);
+      int zpn = lvx->get (iy);
+      if ((zpt == zvx) || (zpt == zpn) || ((zpt < zvx) != (zpt < zpn))) break;
+    }
+
+    if (zvx == zpt)
+    {
+      if (cvx->vprod (rvx, rpt, pt) <= 0)   // Au lieu de < chez Phuong
+      {
+        setVertex (cvx);
+        setEdge (rpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (cvx, rvx);
+      }
+    }
+    else
+    {
+      int zpn = rpt->get (iy);
+      if ((zvx == zpn) || ((zvx < zpt) != (zvx < zpn)))
+      {
+        setVertex (cvx);
+        setEdge (rpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (lvx, cvx);
+      }
+    }
+  }
+
+  else // second quadrant
+  {
+    if ((rme < rmp) != (rme < rmv)) cvx = pvertex;
+    if ((rmv < rme) != (rmv < rmp))
+      cvx = (ept1->left () == ept2 ? ept1 : ept2);
+    zvx = cvx->get (iy);
+    rvx = cvx->right ();
+    lvx = cvx->left ();
+
+    while (cvx->vprod (lvx, lpt, pt) < 0)
+    {
+      cvx = lvx;
+      rvx = cvx->right ();
+      lvx = cvx->left ();
+      zvx = cvx->get (iy);
+      int zvn = rvx->get (iy);
+      if ((zpt == zvx) || (zpt == zvn) || ((zpt < zvx) != (zpt < zvn))) break;
+    }
+    if (zvx == zpt)
+    {
+      if (cvx->vprod (lvx, lpt, pt) >= 0)
+      {
+        setVertex (cvx);
+        setEdge (lpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (cvx, lvx);
+      }
+    }
+    else
+    {
+      int zvn = lpt->get (iy);
+      if ((zvx == zvn) || ((zvx < zvn) != (zvx < zpt)))
+      {
+        setVertex (cvx);
+        setEdge (lpt, pt);
+      }
+      else
+      {
+        setVertex (pt);
+        setEdge (rvx, cvx);
+      }
+    }
+  }
+}
diff --git a/Expes/Testers/TestLines/ConvexHull/antipodal.h b/Expes/Testers/TestLines/ConvexHull/antipodal.h
new file mode 100644
index 0000000..52d8dba
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/antipodal.h
@@ -0,0 +1,135 @@
+#ifndef ANTIPODAL_H
+#define ANTIPODAL_H
+
+#include "chvertex.h"
+#include "edist.h"
+
+
+/** 
+ * @class Antipodal antipodal.h
+ * \brief Horizontal or vertical antipodal pair of a polyline convex hull.
+ */
+class Antipodal
+{
+public:
+
+  /**
+   * \brief Builds an empty (undetermined) horizontal antipodal pair.
+   */
+  Antipodal ();
+
+  /**
+   * \brief Aligns the antipodal pair on vertical direction.
+   */
+  inline void setVertical () { ix = 1; iy = 0; }
+
+  /**
+   * \brief Initializes the vertex/edge pair from three unordered vertices.
+   * @param v1 First vertex. 
+   * @param v2 Second vertex.
+   * @param v3 Third vertex.
+   */
+  void init (CHVertex *v1, CHVertex *v2, CHVertex *v3);
+
+  /**
+   * \brief Sets both vertex and edge of the antipodal pair.
+   * @param pt New vertex.
+   * @param es Start vertex of new edge.
+   * @param ee End vertex of new edge.
+   */
+  inline void setVertexAndEdge (CHVertex *pt, CHVertex *es, CHVertex *ee) {
+    vpt = pt; ept1 = es; ept2 = ee; }
+
+  /**
+   * \brief Sets the vertex of the antipodal pair.
+   * @param pt New vertex.
+   */
+  inline void setVertex (CHVertex *pt) { vpt = pt; }
+
+  /**
+   * \brief Sets the edge of the antipodal pair.
+   * @param es Start vertex of new edge.
+   * @param ee End vertex of new edge.
+   */
+  inline void setEdge (CHVertex *es, CHVertex *ee) {
+    ept1 = es; ept2 = ee; }
+
+  /**
+   * \brief Returns the vertex of the antipodal pair.
+   */
+  inline CHVertex *vertex () const { return vpt; }
+
+  /**
+   * \brief Returns the leaning edge start vertex of the antipodal pair.
+   */
+  inline CHVertex *edgeStart () const { return ept1; }
+
+  /**
+   * \brief Returns the leaning edge end vertex of the antipodal pair.
+   */
+  inline CHVertex *edgeEnd () const { return ept2; }
+
+  /**
+   * \brief Returns the antipodal pair horizontal thickness.
+   * It is computed as the vertex horizontal distance to the edge.
+   */
+  EDist thickness () const;
+
+  /**
+   * \brief Computes the antipodal pair horizontal thickness.
+   * It is the vertex horizontal distance to the edge.
+   * @param num Numerator of the thickness rational value.
+   * @param den Denominator of the thickness rational value.
+   */
+  //void thickness (int &num, int &den) const;
+
+  /**
+   * \brief Returns the remainder of the edge line equation for given vertex.
+   * @param v Given vertex.
+   */
+  int remainder (CHVertex *v) const;
+
+  /**
+   * \brief Checks if the antipodal edge lies in first quadrant.
+   * More formally, checks if sign(Ex) = sign(Ey).
+   */
+  bool edgeInFirstQuadrant () const;
+
+  /**
+   * \brief Returns the edge vector Y coordinate.
+   */
+  int getA () const;
+
+  /**
+   * \brief Returns the edge vector X coordinate.
+   */
+  int getB () const;
+
+  /**
+   * \brief Updates the antipodal pair after the insertion of a new vertex.
+   * @param pt Pointer to inserted vertex.
+   */
+  void update (CHVertex *pt);
+
+  /**
+   * \brief Returns a string that represents the antipodal pair.
+   */
+  // friend ostream& operator<< (ostream &os, const Antipodal &ap);
+
+
+protected:
+
+  /** First coordinate (X for horizonal pair, Y for vertical pair). */
+  int ix;
+  /** Second coordinate (Y for horizonal pair, X for vertical pair). */
+  int iy;
+
+  /** Leaning vertex. */
+  CHVertex *vpt;
+  /** Start vertex of leaning edge. */
+  CHVertex *ept1;
+  /** End vertex of leaning edge. */
+  CHVertex *ept2;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ConvexHull/changed b/Expes/Testers/TestLines/ConvexHull/changed
new file mode 100644
index 0000000..bb276c6
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/changed
@@ -0,0 +1,6 @@
+cmp antipodal.cpp ~/git/2019-FBSD/Code/FBSD/ConvexHull/antipodal.cpp
+cmp antipodal.h ~/git/2019-FBSD/Code/FBSD/ConvexHull/antipodal.h
+cmp chvertex.cpp ~/git/2019-FBSD/Code/FBSD/ConvexHull/chvertex.cpp
+cmp chvertex.h ~/git/2019-FBSD/Code/FBSD/ConvexHull/chvertex.h
+cmp convexhull.cpp ~/git/2019-FBSD/Code/FBSD/ConvexHull/convexhull.cpp
+cmp convexhull.h ~/git/2019-FBSD/Code/FBSD/ConvexHull/convexhull.h
diff --git a/Expes/Testers/TestLines/ConvexHull/chvertex.cpp b/Expes/Testers/TestLines/ConvexHull/chvertex.cpp
new file mode 100644
index 0000000..d52655b
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/chvertex.cpp
@@ -0,0 +1,36 @@
+#include "chvertex.h"
+
+
+CHVertex::CHVertex () : Pt2i ()
+{
+  lv = NULL;
+  rv = NULL;
+}
+
+
+CHVertex::CHVertex (int x, int y) : Pt2i (x, y)
+{
+  lv = NULL;
+  rv = NULL;
+}
+
+
+CHVertex::CHVertex (const Pt2i &p) : Pt2i (p)
+{
+  lv = NULL;
+  rv = NULL;
+}
+
+
+CHVertex::~CHVertex ()
+{
+}
+
+
+/*
+ostream& operator<< (ostream &os, const CHVertex &v)
+{
+  os << "(" << v.xp << ", " << v.yp << ")";
+  return os;
+}
+*/
diff --git a/Expes/Testers/TestLines/ConvexHull/chvertex.h b/Expes/Testers/TestLines/ConvexHull/chvertex.h
new file mode 100644
index 0000000..82b7226
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/chvertex.h
@@ -0,0 +1,92 @@
+#ifndef CHVERTEX_H
+#define CHVERTEX_H
+
+#include "pt2i.h"
+
+
+/** 
+ * @class CHVertex chvertex.h
+ * \brief Chained vertex with two adjacent points, on left and right.
+ */
+class CHVertex : public Pt2i
+{
+public:
+
+  /**
+   * \brief Builds a default vertex.
+   */
+  CHVertex ();
+
+  /**
+   * \brief Builds a vertex on given coordinates.
+   * @param x First ccordinate value.
+   * @param y Second ccordinate value.
+   */
+  CHVertex (int x, int y);
+
+  /**
+   * \brief Builds a vertex at position of given point.
+   * @param p Reference to given point.
+   */
+  CHVertex (const Pt2i &p);
+
+  /**
+   * \brief Deletes the vertex.
+   */
+  ~CHVertex ();
+
+  /**
+   * \brief Returns a pointer to adjacent vertex on left side.
+   */
+  inline CHVertex *left () const { return lv; }
+
+  /**
+   * \brief Returns a pointer to adjacent vertex on right side.
+   */
+  inline CHVertex *right () const { return rv; }
+
+  /**
+   * \brief Sets adjacent vertex on left side.
+   * @param v Pointer to new adjacent vertex.
+   */
+  inline void setLeft (CHVertex *v) { lv = v; }
+
+  /**
+   * \brief Sets adjacent vertex on right side.
+   * @param v Pointer to new adjacent vertex.
+   */
+  inline void setRight (CHVertex *v) { rv = v; }
+
+  /**
+   * \brief Returns the cross product of vector (pt - this) and vector (vx, vy).
+   * The cross product of U and V is defined by: CP = Ux * Vy - Vx * Uy.
+   * @param pt Given end point.
+   * @param vx First coordinate of given vector.
+   * @param vy Second coordinate of given vector.
+   */
+  inline int vprod (CHVertex *pt, int vx, int vy) const {
+    return ((pt->xp - xp) * vy - vx * (pt->yp - yp)); }
+
+  /**
+   * \brief Returns the cross product of vector (p2 - this) and vector (p4 - p3)
+   * The cross product of U and V is defined by: CP = Ux * Vy - Vx * Uy.
+   * @param p2 First end point.
+   * @param p3 Second start point.
+   * @param p4 Second end point.
+   */
+  inline int vprod (CHVertex *p2, CHVertex *p3, CHVertex *p4) const {
+    return ((p2->xp - xp) * (p4->yp - p3->yp)
+            - (p4->xp - p3->xp) * (p2->yp - yp)); }
+
+  // friend ostream& operator<< (ostream &os, const CHVertex &v);
+
+
+protected:
+
+  /** Adjacent vertex on left side. */
+  CHVertex *lv;
+  /** Adjacent vertex on right side. */
+  CHVertex *rv;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ConvexHull/convexhull.cpp b/Expes/Testers/TestLines/ConvexHull/convexhull.cpp
new file mode 100644
index 0000000..fa7d8c3
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/convexhull.cpp
@@ -0,0 +1,261 @@
+#include "convexhull.h"
+
+
+ConvexHull::ConvexHull (const Pt2i &lpt, const Pt2i &cpt, const Pt2i &rpt)
+{
+  CHVertex *cvert = new CHVertex (cpt);
+  leftVertex = new CHVertex (lpt);
+  rightVertex = new CHVertex (rpt);
+  lastToLeft = false;
+
+  if (lpt.toLeft (cpt, rpt))
+  {
+    leftVertex->setRight (cvert);
+    cvert->setLeft (leftVertex);
+    cvert->setRight (rightVertex);
+    rightVertex->setLeft (cvert);
+    rightVertex->setRight (leftVertex);
+    leftVertex->setLeft (rightVertex);
+  }
+  else
+  {
+    leftVertex->setRight (rightVertex);
+    rightVertex->setLeft (leftVertex);
+    rightVertex->setRight (cvert);
+    cvert->setLeft (rightVertex);
+    cvert->setRight (leftVertex);
+    leftVertex->setLeft (cvert);
+  }
+
+  aph.init (leftVertex, cvert, rightVertex);
+  apv.setVertical ();
+  apv.init (leftVertex, cvert, rightVertex);
+
+  gbg.push_back (leftVertex);
+  gbg.push_back (cvert);
+  gbg.push_back (rightVertex);
+
+  old_left = leftVertex;
+  old_right = rightVertex;
+  old_aph_vertex = aph.vertex ();
+  old_aph_edge_start = aph.edgeStart ();
+  old_aph_edge_end = aph.edgeEnd ();
+  old_apv_vertex = apv.vertex ();
+  old_apv_edge_start = apv.edgeStart ();
+  old_apv_edge_end = apv.edgeEnd ();
+}
+
+
+ConvexHull::~ConvexHull ()
+{
+  for (int i = 0; i < (int) (gbg.size ()); ++i) delete gbg [i];
+}
+
+
+void ConvexHull::preserve ()
+{
+  old_aph_vertex = aph.vertex ();
+  old_aph_edge_start = aph.edgeStart ();
+  old_aph_edge_end = aph.edgeEnd ();
+  old_apv_vertex = apv.vertex ();
+  old_apv_edge_start = apv.edgeStart ();
+  old_apv_edge_end = apv.edgeEnd ();
+  old_left = leftVertex;
+  old_right = rightVertex;
+}
+
+
+void ConvexHull::restore ()
+{
+  rconnect->setLeft (rdisconnect);
+  lconnect->setRight (ldisconnect);
+  leftVertex = old_left;
+  rightVertex = old_right;
+  aph.setVertexAndEdge (old_aph_vertex, old_aph_edge_start, old_aph_edge_end);
+  apv.setVertexAndEdge (old_apv_vertex, old_apv_edge_start, old_apv_edge_end);
+}
+
+
+bool ConvexHull::addPoint (const Pt2i &pt, bool toleft)
+{
+  if (inHull (pt, toleft)) return false;
+  CHVertex *vx = new CHVertex (pt);
+  lastToLeft = toleft;
+  gbg.push_back (vx);
+  preserve ();
+  insert (vx, toleft);
+  aph.update (vx);
+  apv.update (vx);
+  return true;
+}
+
+
+bool ConvexHull::addPointDS (const Pt2i &pt, bool toleft)
+{
+  CHVertex *vx = new CHVertex (pt);
+  lastToLeft = toleft;
+  gbg.push_back (vx);
+  preserve ();
+  insertDS (vx, toleft);
+  aph.update (vx);
+  apv.update (vx);
+  return true;
+}
+
+
+bool ConvexHull::moveLastPoint (const Pt2i &pos)
+{
+  restore ();
+  if (inHull (pos, lastToLeft)) return false;
+  gbg.pop_back ();
+  preserve ();
+  addPoint (pos, lastToLeft);
+  return true;
+}
+
+
+EDist ConvexHull::thickness () const
+{
+  EDist aphw = aph.thickness ();
+  EDist apvw = apv.thickness ();
+  return (apvw.lessThan (aphw) ? apvw : aphw);
+}
+
+
+void ConvexHull::antipodalEdgeAndVertex (Pt2i &s, Pt2i &e, Pt2i &v) const
+{
+  EDist aphw = aph.thickness ();
+  EDist apvw = apv.thickness ();
+  const Antipodal *ap = (apvw.lessThan (aphw) ? &apv : &aph);
+  s.set (*(ap->edgeStart ()));
+  e.set (*(ap->edgeEnd ()));
+  v.set (*(ap->vertex ()));
+}
+
+
+bool ConvexHull::inHull (const Pt2i &pt, bool toleft) const
+{
+  CHVertex *ext = (toleft ? leftVertex : rightVertex);
+  return (pt.toLeftOrOn (*ext, *(ext->right ()))
+          && pt.toLeftOrOn (*(ext->left ()), *ext));
+}
+
+
+void ConvexHull::insert (CHVertex *pt, bool toleft)
+{
+  bool opIn = false; // Opposite polyline top in the new convex hull
+  CHVertex *opVertex = NULL; // Opposite vertex
+
+  if (toleft)
+  {
+    lconnect = leftVertex;
+    rconnect = leftVertex;
+    leftVertex = pt;
+    opVertex = rightVertex;
+  }
+  else
+  {
+    lconnect = rightVertex;
+    rconnect = rightVertex;
+    rightVertex = pt;
+    opVertex = leftVertex;
+  }
+
+  ldisconnect = lconnect->right ();
+  while (pt->toLeftOrOn (*lconnect, *(lconnect->left ())))
+  {
+    if (lconnect == opVertex) opIn = true;
+    ldisconnect = lconnect;
+    lconnect = lconnect->left ();
+  }
+  if (opIn)
+  {
+    if (toleft) rightVertex = lconnect;
+    else leftVertex = lconnect;
+  }
+
+  opIn = false;
+  rdisconnect = rconnect->left ();
+  while (! pt->toLeft (*rconnect, *(rconnect->right ())))
+  {
+    if (rconnect == opVertex) opIn = true;
+    rdisconnect = rconnect;
+    rconnect = rconnect->right ();
+  }
+  if (opIn)
+  {
+    if (toleft) rightVertex = rconnect;
+    else leftVertex = rconnect;
+  }
+  
+  lconnect->setRight (pt);
+  pt->setLeft (lconnect);
+  rconnect->setLeft (pt);
+  pt->setRight (rconnect);
+}
+
+
+void ConvexHull::insertDS (CHVertex *pt, bool toleft)
+{
+  if (toleft)
+  {
+    lconnect = leftVertex;
+    rconnect = leftVertex;
+    leftVertex = pt;
+  }
+  else
+  {
+    lconnect = rightVertex;
+    rconnect = rightVertex;
+    rightVertex = pt;
+  }
+
+  ldisconnect = lconnect->right ();
+  while (pt->toLeftOrOn (*lconnect, *(lconnect->left ())))
+  {
+    ldisconnect = lconnect;
+    lconnect = lconnect->left ();
+  }
+
+  rdisconnect = rconnect->left ();
+  while (! pt->toLeft (*rconnect, *(rconnect->right ())))
+  {
+    rdisconnect = rconnect;
+    rconnect = rconnect->right ();
+  }
+  
+  lconnect->setRight (pt);
+  pt->setLeft (lconnect);
+  rconnect->setLeft (pt);
+  pt->setRight (rconnect);
+}
+
+
+/*
+ostream& operator<< (ostream &os, const ConvexHull &ch)
+{
+  os << "APH = " << ch.aph << endl;
+  os << "APV = " << ch.apv << endl;
+  os << "FIRST " << *(ch.leftVertex);
+  CHVertex *next = ch.leftVertex->right ();
+  int i = 0;
+  while (i++ < 20 && next != ch.leftVertex)
+  {
+    os << " - " << *next;
+    next = next->right ();
+  }
+  if (i >= 20) os << " ---";
+  os << endl;
+  os << "LAST " << *(ch.rightVertex);
+  next = ch.rightVertex->left ();
+  i = 0;
+  while (i++ < 20 && next != ch.rightVertex)
+  {
+    os << " - " << *next;
+    next = next->left ();
+  }
+  if (i >= 20) os << " ---";
+
+  return os;
+}
+*/
diff --git a/Expes/Testers/TestLines/ConvexHull/convexhull.h b/Expes/Testers/TestLines/ConvexHull/convexhull.h
new file mode 100644
index 0000000..d1483b5
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/convexhull.h
@@ -0,0 +1,195 @@
+#ifndef CONVEXHULL
+#define CONVEXHULL
+
+#include "antipodal.h"
+
+
+/** 
+ * @class ConvexHull convexhull.h
+ * \brief Convex hull of a polyline.
+ */
+class ConvexHull
+{
+public:
+
+  /**
+   * \brief Creates a convex hull from a triangle.
+   * Be very careful with the points ordering : lpt, cpt, then rpt.
+   * Ensure that the points are NOT COLINEAR (not tested here).
+   * @param lpt : left end vertex of the polyline.
+   * @param cpt : center vertex of the polyline.
+   * @param rpt : right end vertex of the polyline.
+   */
+  ConvexHull (const Pt2i &lpt, const Pt2i &cpt, const Pt2i &rpt);
+
+  /**
+   * \brief Deletes the convex hull.
+   * Removes all registered vertices.
+   */
+  ~ConvexHull ();
+
+  /**
+   * \brief Restores the convexhull features after a modification.
+   */
+  void restore ();
+
+  
+  /**
+   * \brief Appends a new point at one side of the convex hull.
+   * @param pt Reference to the point to add.
+   * @param Side at which the point is added.
+   */
+  bool addPoint (const Pt2i &pt, bool toleft);
+
+  /**
+   * \brief Appends a new point at one side of the convex hull.
+   * To be used with directional scans:
+   *   in that case, added point can not be inside the hull.
+   * @param pt Reference to the point to add.
+   * @param toleft Add the point at left side if true, right side otherwise.
+   */
+  bool addPointDS (const Pt2i &pt, bool toleft);
+
+  /**
+   * \brief Moves the last inserted point and returns the success.
+   * @param pos New position for the last point.
+   */
+  bool moveLastPoint (const Pt2i &pos);
+
+  /**
+   * \brief Checks whether the line to given point crosses the hull.
+   * @param pt Given point.
+   * @param toleft Set to true if the point was added on left side.
+   */
+  bool inHull (const Pt2i &pt, bool toleft) const;
+
+
+  /**
+   * \brief Returns the antipodal edge and vertex.
+   * @param s Edge start vertex.
+   * @param e Edge end vertex.
+   * @param v Vertex.
+   */
+  void antipodalEdgeAndVertex (Pt2i &s, Pt2i &e, Pt2i &v) const;
+
+  /**
+   * \brief Returns the convex hull thickness.
+   * The thickness is the minimal vertical or horizontal thickness.
+   * It is computed as the minimal value of both antipodal pairs.
+   */
+  EDist thickness () const;
+
+  /**
+   * \brief Returns a string that represents the convex hull.
+   */
+  // friend ostream& operator<< (ostream &os, const ConvexHull &ch);
+
+  /**
+   * \brief Returns the first (left) vertex of the convex hull.
+   */
+  inline CHVertex *getFirstVertex () const { return (leftVertex); }
+
+  /**
+   * \brief Returns the last (right) vertex of the convex hull.
+   */
+  inline CHVertex *getLastVertex () const { return (rightVertex); }
+
+  /**
+   * \brief Returns the horizontal antipodal vertex.
+   */
+  inline CHVertex *getAphVertex () const { return (aph.vertex ()); }
+
+  /**
+   * \brief Returns the horizontal antipodal edge start vertex.
+   */
+  inline CHVertex *getAphEdgeStart () const { return (aph.edgeStart ()); }
+
+  /**
+   * \brief Returns the horizontal antipodal edge end vertex.
+   */
+  inline CHVertex *getAphEdgeEnd () const { return (aph.edgeEnd ()); }
+
+  /**
+   * \brief Returns the vertical antipodal vertex.
+   */
+  inline CHVertex *getApvVertex () const { return (apv.vertex ()); }
+
+  /**
+   * \brief Returns the vertical antipodal edge start vertex.
+   */
+  inline CHVertex *getApvEdgeStart () const { return (apv.edgeStart ()); }
+
+  /**
+   * \brief Returns the vertical antipodal edge end vertex.
+   */
+  inline CHVertex *getApvEdgeEnd () const { return (apv.edgeEnd ()); }
+
+
+protected:
+
+  /** Polyline left end point. */
+  CHVertex *leftVertex;
+  /** Polyline right end point. */
+  CHVertex *rightVertex;
+  /** Indicates if the last vertex was entered to the left. */
+  bool lastToLeft;
+
+  /** Antipodal pair in horizontal direction. */
+  Antipodal aph;
+  /** Antipodal pair in vertical direction. */
+  Antipodal apv;
+
+  /** Registered vertex of previous horizontal antipodal pair. */
+  CHVertex *old_aph_vertex;
+  /** Registered edge start of previous horizontal antipodal pair. */
+  CHVertex *old_aph_edge_start;
+  /** Registered edge end of previous horizontal antipodal pair. */
+  CHVertex *old_aph_edge_end;
+  /** Registered vertex of previous vertical antipodal pair. */
+  CHVertex *old_apv_vertex;
+  /** Registered edge start of previous vertical antipodal pair. */
+  CHVertex *old_apv_edge_start;
+  /** Registered edge end of previous vertical antipodal pair. */
+  CHVertex *old_apv_edge_end;
+  /** Registered left end point of previous polyline. */
+  CHVertex *old_left;
+  /** Registered right end point of previous polyline. */
+  CHVertex *old_right;
+  /** Registered connected point to the left of previous polyline. */
+  CHVertex *lconnect;
+  /** Registered disconnected point to the left of previous polyline. */
+  CHVertex *ldisconnect;
+  /** Registered connected point to the right of previous polyline. */
+  CHVertex *rconnect;
+  /** Registered disconnected point to the right of previous polyline. */
+  CHVertex *rdisconnect;
+
+  /** Collection of released vertices for clearance. */
+  std::vector<CHVertex*> gbg;
+
+
+private:
+
+  /**
+   * \brief Stores convex hull features before a modification.
+   */
+  void preserve ();
+
+  /**
+   * \brief Inserts a new point into the convex hull.
+   * @param pt Pointer to the point to add.
+   * @param toleft Adds to left if true, to right otherwise.
+   */
+  void insert (CHVertex *pt, bool toleft);
+
+  /**
+   * \brief Inserts a new point into the convex hull.
+   * To be used with directional scans :
+   *   In that case, opposite ends of the polyline can never pass each other.
+   * @param pt Pointer to the point to add.
+   * @param toleft Adds to left if true, to right otherwise.
+   */
+  void insertDS (CHVertex *pt, bool toleft);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ConvexHull/rechanged b/Expes/Testers/TestLines/ConvexHull/rechanged
new file mode 100644
index 0000000..6503942
--- /dev/null
+++ b/Expes/Testers/TestLines/ConvexHull/rechanged
@@ -0,0 +1,6 @@
+cmp antipodal.cpp ~/tmp/ASD/ConvexHull/antipodal.cpp
+cmp antipodal.h ~/tmp/ASD/ConvexHull/antipodal.h
+cmp chvertex.cpp ~/tmp/ASD/ConvexHull/chvertex.cpp
+cmp chvertex.h ~/tmp/ASD/ConvexHull/chvertex.h
+cmp convexhull.cpp ~/tmp/ASD/ConvexHull/convexhull.cpp
+cmp convexhull.h ~/tmp/ASD/ConvexHull/convexhull.h
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.cpp b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.cpp
new file mode 100644
index 0000000..9e2bdf1
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.cpp
@@ -0,0 +1,262 @@
+#include "adaptivescannero1.h"
+
+
+AdaptiveScannerO1::AdaptiveScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+  this->dlc1 = a * sx + b * sy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO1::AdaptiveScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx ++;
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO1::AdaptiveScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx ++;
+    lcy --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cx--;
+    cy++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  rcx = lcx;
+  rcy = lcy;
+}
+
+
+AdaptiveScannerO1::AdaptiveScannerO1 (AdaptiveScannerO1 *ds)
+                 : DirectionalScanner (ds)
+{
+  templ_a = ds->templ_a;
+  templ_b = ds->templ_b;
+  templ_nu = ds->templ_nu;
+  dlc1 = ds->dlc1;
+}
+
+
+DirectionalScanner *AdaptiveScannerO1::getCopy ()
+{
+  return (new AdaptiveScannerO1 (this));
+}
+
+
+int AdaptiveScannerO1::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO1::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcx --;
+  // Whenever the control line changed
+  while (lcy < ymax - 1 && lcx >= xmin && dla * lcx + dlb * lcy > dlc1)
+  {
+    if (*lst2) lcx --;
+    lcy ++;
+    if (++lst2 >= fs) lst2 = steps;
+  }
+  while (lcy > ymin && lcx < xmax && dla * lcx + dlb * lcy < dlc1)
+  {
+    if (--lst2 < steps) lst2 = steps + nbs - 1;
+    if (*lst2) lcx ++;
+    lcy --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x --;
+    y ++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x --;
+    y ++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO1::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcx ++;
+  while (rcy < ymax - 1 && rcx >= xmin && dla * rcx + dlb * rcy > dlc1)
+  {
+    if (*rst2) rcx --;
+    rcy ++;
+    if (++rst2 >= fs) rst2 = steps;
+  }
+  while (rcy > ymin && rcx < xmax && dla * rcx + dlb * rcy < dlc1)
+  {
+    if (--rst2 < steps) rst2 = steps + nbs - 1;
+    if (*rst2) rcx ++;
+    rcy --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+void AdaptiveScannerO1::bindTo (int a, int b, int c)
+{
+  if (a < 0)
+  {
+    dla = -a;
+    dlb = -b;
+    c = -c;
+  }
+  else
+  {
+    dla = a;
+    dlb = b;
+  }
+  int old_b = (templ_b < 0 ? -templ_b : templ_b);
+  int old_n1 = templ_a + old_b;
+  int old_ninf = (old_b > templ_a ? old_b : templ_a);
+  int new_a = (a < 0 ? -a : a);
+  int new_b = (b < 0 ? -b : b);
+  int new_n1 = new_a + new_b;
+  int new_ninf = (new_b > new_a ? new_b : new_a);
+  int nu;
+  if (new_n1 * old_ninf > old_n1 * new_ninf)
+    nu = (templ_nu * new_n1) / old_n1;
+  else
+    nu = (templ_nu * new_ninf) / old_ninf;
+  if (dlb > 0)  // dlb should stay negative to avoid the direction change
+  {             //   of the support line inequations.
+    dla = -dla;
+    dlb = -dlb;
+    c = -c;
+  }
+  dlc1 = c + nu / 2;
+  dlc2 = c - nu / 2;
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.h b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.h
new file mode 100644
index 0000000..6121356
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero1.h
@@ -0,0 +1,138 @@
+#ifndef ADAPTIVE_SCANNER_O1_H
+#define ADAPTIVE_SCANNER_O1_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class Adaptive adaptivescannero1.h
+ * \brief Adaptive directional scanner for the 1st octant.
+ */
+class AdaptiveScannerO1 : public DirectionalScanner
+{
+public:
+
+  /**
+   * \brief Creates an adaptive DS from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  AdaptiveScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c,
+                     int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the support discrete line.
+   * @param b Value of parameter 'b' of the support discrete line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */ 
+  AdaptiveScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c1, int c2,
+                     int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  AdaptiveScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b,
+                     int nbs, bool *steps,
+                     int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Binds the scan strip to wrap the given digital line.
+   * Resets bounding lines parameters to center the scan strip on given line.
+   * @param a Parameter 'a' of given digital line.
+   * @param b Parameter 'b' of given digital line.
+   * @param c Parameter 'c' of given digital line.
+   */
+  void bindTo (int a, int b, int c);
+
+
+protected :
+  
+  /** Parameter 'a' of template support discrete line template. */
+  int templ_a;
+  /** Parameter 'b' of template support discrete line template. */
+  int templ_b;
+  /** Parameter 'nu' of template support discrete line template. */
+  int templ_nu;
+
+  /** Shift parameter of the lower support discrete line. */
+  int dlc1;
+
+
+  /**
+   * \brief Creates an empty adaptive directional scanner.
+   */
+  AdaptiveScannerO1 () { }
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  AdaptiveScannerO1 (AdaptiveScannerO1 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.cpp b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.cpp
new file mode 100644
index 0000000..6417c10
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.cpp
@@ -0,0 +1,256 @@
+#include "adaptivescannero2.h"
+
+
+AdaptiveScannerO2::AdaptiveScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+  this->dlc1 = a * sx + b * sy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO2::AdaptiveScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx ++;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO2::AdaptiveScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx ++;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cy++;
+    cx--;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  rcx = lcx;
+  rcy = lcy;
+}
+
+
+AdaptiveScannerO2::AdaptiveScannerO2 (AdaptiveScannerO2 *ds)
+                 : DirectionalScanner (ds)
+{
+  templ_a = ds->templ_a;
+  templ_b = ds->templ_b;
+  templ_nu = ds->templ_nu;
+  dlc1 = ds->dlc1;
+}
+
+
+DirectionalScanner *AdaptiveScannerO2::getCopy ()
+{
+  return (new AdaptiveScannerO2 (this));
+}
+
+
+int AdaptiveScannerO2::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;         // Current step in scan direction (jpts)
+
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO2::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcy --;
+  // Whenever the control line changed
+  while (lcx > xmin && lcy < ymax && dla * lcx + dlb * lcy > dlc1)
+  {
+    if (*lst2) lcy ++;
+    lcx --;
+    if (++lst2 >= fs) lst2 = steps;
+  }
+  while (lcx < xmax - 1 && lcy >= ymin && dla * lcx + dlb * lcy < dlc1)
+  {
+    if (--lst2 < steps) lst2 = steps + nbs - 1;
+    if (*lst2) lcy --;
+    lcx ++;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO2::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcy ++;
+  while (rcx > xmin && rcy < ymax && dla * rcx + dlb * rcy > dlc1)
+  {
+    if (*rst2) rcy ++;
+    rcx --;
+    if (++rst2 >= fs) rst2 = steps;
+  }
+  while (rcx < xmax - 1 && rcy >= ymin && dla * rcx + dlb * rcy < dlc1)
+  {
+    if (--rst2 < steps) rst2 = steps + nbs - 1;
+    if (*rst2) rcy --;
+    rcx ++;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+void AdaptiveScannerO2::bindTo (int a, int b, int c)
+{
+  if (a < 0)
+  {
+    dla = -a;
+    dlb = -b;
+    c = -c;
+  }
+  else
+  {
+    dla = a;
+    dlb = b;
+  }
+  int old_b = (templ_b < 0 ? -templ_b : templ_b);
+  int old_n1 = templ_a + old_b;
+  int old_ninf = (old_b > templ_a ? old_b : templ_a);
+  int new_a = (a < 0 ? -a : a);
+  int new_b = (b < 0 ? -b : b);
+  int new_n1 = new_a + new_b;
+  int new_ninf = (new_b > new_a ? new_b : new_a);
+  int nu;
+  if (new_n1 * old_ninf > old_n1 * new_ninf)
+    nu = (templ_nu * new_n1) / old_n1;
+  else
+    nu = (templ_nu * new_ninf) / old_ninf;
+  dlc1 = c + nu / 2;
+  dlc2 = c - nu / 2;
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.h b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.h
new file mode 100644
index 0000000..cdfab8f
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero2.h
@@ -0,0 +1,140 @@
+#ifndef ADAPTIVE_SCANNER_O2_H
+#define ADAPTIVE_SCANNER_O2_H
+
+#include "directionalscanner.h"
+
+
+
+/** 
+ * @class AdaptiveScannerO2 adaptivescannero2.h
+ * \brief Adaptive directional scanner for the 2nd octant.
+ */
+class AdaptiveScannerO2 : public DirectionalScanner
+{
+
+public:
+  
+  /**
+   * \brief Creates an adaptive DS from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  AdaptiveScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c,
+                     int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  AdaptiveScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c1, int c2,
+                     int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  AdaptiveScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b,
+                     int nbs, bool *steps,
+                     int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Binds the scan strip to wrap the given digital line.
+   * Resets bounding lines parameters to center the scan strip on given line.
+   * @param a Parameter 'a' of given digital line.
+   * @param b Parameter 'b' of given digital line.
+   * @param c Parameter 'c' of given digital line.
+   */
+  void bindTo (int a, int b, int c);
+
+
+protected :
+
+  /** Parameter 'a' of template support discrete line template. */
+  int templ_a;
+  /** Parameter 'b' of template support discrete line template. */
+  int templ_b;
+  /** Parameter 'nu' of template support discrete line template. */
+  int templ_nu;
+
+  /** Shift parameter of the lower support discrete line */
+  int dlc1;
+
+
+  /**
+   * \brief Creates an empty adaptive directional scanner.
+   */
+  AdaptiveScannerO2 () { }
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  AdaptiveScannerO2 (AdaptiveScannerO2 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.cpp b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.cpp
new file mode 100644
index 0000000..7c476ed
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.cpp
@@ -0,0 +1,256 @@
+#include "adaptivescannero7.h"
+
+
+AdaptiveScannerO7::AdaptiveScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+  this->dlc1 = a * sx + b * sy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO7::AdaptiveScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO7::AdaptiveScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cy++;
+    cx++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  rcx = lcx;
+  rcy = lcy;
+}
+
+
+AdaptiveScannerO7::AdaptiveScannerO7 (AdaptiveScannerO7 *ds)
+                 : DirectionalScanner (ds)
+{
+  templ_a = ds->templ_a;
+  templ_b = ds->templ_b;
+  templ_nu = ds->templ_nu;
+  dlc1 = ds->dlc1;
+}
+
+
+DirectionalScanner *AdaptiveScannerO7::getCopy ()
+{
+  return (new AdaptiveScannerO7 (this));
+}
+
+
+int AdaptiveScannerO7::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO7::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcy ++;
+  while (lcx < xmax - 1 && lcy < ymax && dla * lcx + dlb * lcy < dlc1)
+  {
+    if (*lst2) lcy ++;
+    lcx ++;
+    if (++lst2 >= fs) lst2 = steps;
+  }
+  while (lcx > xmin && lcy >= ymin && dla * lcx + dlb * lcy > dlc1)
+  {
+    if (--lst2 < steps) lst2 = steps + nbs - 1;
+    if (*lst2) lcy --;
+    lcx --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO7::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcy --;
+  // Whenever the control corridor changed
+  while (rcx < xmax - 1 && rcy < ymax && dla * rcx + dlb * rcy < dlc1)
+  {
+    if (*rst2) rcy ++;
+    rcx ++;
+    if (++rst2 >= fs) rst2 = steps;
+  }
+  while (rcx > xmin && rcy >= ymin && dla * rcx + dlb * rcy > dlc1)
+  {
+    if (--rst2 < steps) rst2 = steps + nbs - 1;
+    if (*rst2) rcy --;
+    rcx --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst == fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst == fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+void AdaptiveScannerO7::bindTo (int a, int b, int c)
+{
+  if (a < 0)
+  {
+    dla = -a;
+    dlb = -b;
+    c = -c;
+  }
+  else
+  {
+    dla = a;
+    dlb = b;
+  }
+  int old_b = (templ_b < 0 ? -templ_b : templ_b);
+  int old_n1 = templ_a + old_b;
+  int old_ninf = (old_b > templ_a ? old_b : templ_a);
+  int new_a = (a < 0 ? -a : a);
+  int new_b = (b < 0 ? -b : b);
+  int new_n1 = new_a + new_b;
+  int new_ninf = (new_b > new_a ? new_b : new_a);
+  int nu;
+  if (new_n1 * old_ninf > old_n1 * new_ninf)
+    nu = (templ_nu * new_n1) / old_n1;
+  else
+    nu = (templ_nu * new_ninf) / old_ninf;
+  dlc1 = c - nu / 2;
+  dlc2 = c + nu / 2;
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.h b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.h
new file mode 100644
index 0000000..50a6223
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero7.h
@@ -0,0 +1,139 @@
+#ifndef ADAPTIVE_SCANNER_O7_H
+#define ADAPTIVE_SCANNER_O7_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class AdaptiveScannerO7 adaptivescannero7.h
+ * \brief Adaptive directional scanner for the 7th octant.
+ */
+class AdaptiveScannerO7 : public DirectionalScanner
+{
+
+public:
+  
+  /**
+   * \brief Creates an adaptive DS from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  AdaptiveScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c,
+                     int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  AdaptiveScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c1, int c2,
+                     int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  AdaptiveScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b,
+                     int nbs, bool *steps,
+                     int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Binds the scan strip to wrap the given digital line.
+   * Resets bounding lines parameters to center the scan strip on given line.
+   * @param a Parameter 'a' of given digital line.
+   * @param b Parameter 'b' of given digital line.
+   * @param c Parameter 'c' of given digital line.
+   */
+  void bindTo (int a, int b, int c);
+
+
+protected :
+
+  /** Parameter 'a' of template support discrete line template. */
+  int templ_a;
+  /** Parameter 'b' of template support discrete line template. */
+  int templ_b;
+  /** Parameter 'nu' of template support discrete line template. */
+  int templ_nu;
+
+  /** Shift parameter of the lower support discrete line */
+  int dlc1;
+
+
+  /**
+   * \brief Creates an empty adaptive directional scanner.
+   */
+  AdaptiveScannerO7 () { }
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  AdaptiveScannerO7 (AdaptiveScannerO7 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.cpp b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.cpp
new file mode 100644
index 0000000..1c838fe
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.cpp
@@ -0,0 +1,262 @@
+#include "adaptivescannero8.h"
+
+
+AdaptiveScannerO8::AdaptiveScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+  this->dlc1 = a * sx + b * sy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO8::AdaptiveScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx --;
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+  fs = steps + nbs;
+}
+
+
+AdaptiveScannerO8::AdaptiveScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx --;
+    lcy --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cx++;
+    cy++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  rcx = lcx;
+  rcy = lcy;
+}
+
+
+AdaptiveScannerO8::AdaptiveScannerO8 (AdaptiveScannerO8 *ds)
+                 : DirectionalScanner (ds)
+{
+  templ_a = ds->templ_a;
+  templ_b = ds->templ_b;
+  templ_nu = ds->templ_nu;
+  dlc1 = ds->dlc1;
+}
+
+
+DirectionalScanner *AdaptiveScannerO8::getCopy ()
+{
+  return (new AdaptiveScannerO8 (this));
+}
+
+
+int AdaptiveScannerO8::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO8::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcx --;
+  while (lcy < ymax - 1 && lcx < xmax && dla * lcx + dlb * lcy < dlc1)
+  {
+    if (*lst2) lcx ++;
+    lcy ++;
+    if (++lst2 >= fs) lst2 = steps;
+  }
+  while (lcy > ymin && lcx >= xmin && dla * lcx + dlb * lcy > dlc1)
+  {
+    if (--lst2 < steps) lst2 = steps + nbs - 1;
+    if (*lst2) lcx --;
+    lcy --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int AdaptiveScannerO8::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcx ++;
+  // Whenever the control corridor changed
+  while (rcy < ymax - 1 && rcx < xmax && dla * rcx + dlb * rcy < dlc1)
+  {
+    if (*rst2) rcx ++;
+    rcy ++;
+    if (++rst2 >= fs) rst2 = steps;
+  }
+  while (rcy > ymin && rcx >= xmin && dla * rcx + dlb * rcy > dlc1)
+  {
+    if (--rst2 < steps) rst2 = steps + nbs - 1;
+    if (*rst2) rcx --;
+    rcy --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+void AdaptiveScannerO8::bindTo (int a, int b, int c)
+{
+  if (a < 0)
+  {
+    dla = -a;
+    dlb = -b;
+    c = -c;
+  }
+  else
+  {
+    dla = a;
+    dlb = b;
+  }
+  int old_b = (templ_b < 0 ? -templ_b : templ_b);
+  int old_n1 = templ_a + old_b;
+  int old_ninf = (old_b > templ_a ? old_b : templ_a);
+  int new_a = (a < 0 ? -a : a);
+  int new_b = (b < 0 ? -b : b);
+  int new_n1 = new_a + new_b;
+  int new_ninf = (new_b > new_a ? new_b : new_a);
+  int nu;
+  if (new_n1 * old_ninf > old_n1 * new_ninf)
+    nu = (templ_nu * new_n1) / old_n1;
+  else
+    nu = (templ_nu * new_ninf) / old_ninf;
+  if (dlb < 0) // dlb should stay positive to avoid the direction change
+  {            //   of the support line inequations.
+    dla = -dla;
+    dlb = -dlb;
+    c = -c;
+  }
+  dlc1 = c - nu / 2;
+  dlc2 = c + nu / 2;
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.h b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.h
new file mode 100644
index 0000000..fcb196c
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/adaptivescannero8.h
@@ -0,0 +1,138 @@
+#ifndef ADAPTIVE_SCANNER_O8_H
+#define ADAPTIVE_SCANNER_O8_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class AdaptiveScannerO8 adaptivescannero8.h
+ * \brief Adaptive directional scanner for the 8th octant.
+ */
+class AdaptiveScannerO8 : public DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Creates an adaptive DS from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  AdaptiveScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c,
+                     int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  AdaptiveScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b, int c1, int c2,
+                     int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates an adaptive DS from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  AdaptiveScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                     int a, int b,
+                     int nbs, bool *steps,
+                     int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Binds the scan strip to wrap the given digital line.
+   * Resets bounding lines parameters to center the scan strip on given line.
+   * @param a Parameter 'a' of given digital line.
+   * @param b Parameter 'b' of given digital line.
+   * @param c Parameter 'c' of given digital line.
+   */
+  void bindTo (int a, int b, int c);
+
+
+protected :
+
+  /** Parameter 'a' of template support discrete line template. */
+  int templ_a;
+  /** Parameter 'b' of template support discrete line template. */
+  int templ_b;
+  /** Parameter 'nu' of template support discrete line template. */
+  int templ_nu;
+
+  /** Shift parameter of the discrete lower support line */
+  int dlc1;
+
+
+  /**
+   * \brief Creates an empty adaptive directional scanner.
+   */
+  AdaptiveScannerO8 () { }
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  AdaptiveScannerO8 (AdaptiveScannerO8 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/changed b/Expes/Testers/TestLines/DirectionalScanner/changed
new file mode 100644
index 0000000..41fc5a2
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/changed
@@ -0,0 +1,28 @@
+cmp directionalscanner.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscanner.cpp
+cmp directionalscanner.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscanner.h
+cmp directionalscannero1.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero1.cpp
+cmp directionalscannero1.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero1.h
+cmp directionalscannero2.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero2.cpp
+cmp directionalscannero2.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero2.h
+cmp directionalscannero7.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero7.cpp
+cmp directionalscannero7.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero7.h
+cmp directionalscannero8.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero8.cpp
+cmp directionalscannero8.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/directionalscannero8.h
+cmp adaptivescannero1.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero1.cpp
+cmp adaptivescannero1.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero1.h
+cmp adaptivescannero2.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero2.cpp
+cmp adaptivescannero2.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero2.h
+cmp adaptivescannero7.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero7.cpp
+cmp adaptivescannero7.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero7.h
+cmp adaptivescannero8.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero8.cpp
+cmp adaptivescannero8.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/adaptivescannero8.h
+cmp scannerprovider.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/scannerprovider.cpp
+cmp scannerprovider.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/scannerprovider.h
+cmp vhscannero1.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero1.cpp
+cmp vhscannero1.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero1.h
+cmp vhscannero2.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero2.cpp
+cmp vhscannero2.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero2.h
+cmp vhscannero7.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero7.cpp
+cmp vhscannero7.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero7.h
+cmp vhscannero8.cpp ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero8.cpp
+cmp vhscannero8.h ~/git/2019-FBSD/Code/FBSD/DirectionalScanner/vhscannero8.h
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.cpp b/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.cpp
new file mode 100644
index 0000000..a056e18
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.cpp
@@ -0,0 +1,22 @@
+#include "directionalscanner.h"
+
+
+DirectionalScanner::~DirectionalScanner ()
+{
+  if (steps != NULL) delete steps;
+  steps = NULL;
+}
+
+
+void DirectionalScanner::bindTo (int a, int b, int c)
+{
+  (void) a;
+  (void) b;
+  (void) c;
+}
+
+
+Pt2i DirectionalScanner::locate (const Pt2i & pt) const
+{
+  return (Pt2i (pt));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.h b/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.h
new file mode 100644
index 0000000..6ee1b13
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscanner.h
@@ -0,0 +1,157 @@
+#ifndef DIRECTIONAL_SCANNER_H
+#define DIRECTIONAL_SCANNER_H
+
+#include "pt2i.h"
+
+
+/** 
+ * @class DirectionalScanner directionalscanner.h
+ * \brief Incremental directional scanner.
+ * This scanner iterately provides parallel scan lines.
+ */
+class DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Deletes the directional scanner.
+   */
+  virtual ~DirectionalScanner ();
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  virtual DirectionalScanner *getCopy () = 0;
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  virtual int first (std::vector<Pt2i> &scan) const = 0;
+
+  /**
+   * \brief Gets next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  virtual int nextOnLeft (std::vector<Pt2i> &scan) = 0;
+
+  /**
+   * \brief Gets next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  virtual int nextOnRight (std::vector<Pt2i> &scan) = 0;
+
+  /**
+   * \brief Binds the scan strip to wrap the given digital line.
+   * Resets bounding lines parameters to center the scan strip on given line.
+   * @param a New value for the 'a' parameter of current scan strip.
+   * @param b New value for the 'b' parameter of current scan strip.
+   * @param c New value for the 'c' parameter of current scan strip.
+   */
+  virtual void bindTo (int a, int b, int c);
+
+  /**
+   * \brief Returns the scanner coordinates of given point.
+   * Scanner coordinates are the scan index and the position in the scan.
+   * @param pt Image coordinates of the point.
+   */
+  virtual Pt2i locate (const Pt2i &pt) const;
+
+  /**
+   * \brief Releases clearance status of output vector before filling.
+   */
+  inline void releaseClearance () { clearance = false; }
+
+
+protected:
+
+  /** Scanable area left border. */
+  int xmin;
+  /** Scanable area bottom border. */
+  int ymin;
+  /** Scanable area right border. */
+  int xmax;
+  /** Scanable area top border. */
+  int ymax;
+
+  /** Parameter 'a' of the upper support discrete line. */
+  int dla;
+  /** Parameter 'b' of the upper support discrete line. */
+  int dlb;
+  /** Parameter 'c' of the upper support discrete line. */
+  int dlc2;
+
+  /** Size of the discrete line pattern. */
+  int nbs;
+
+  /** Discrete line pattern. */
+  bool *steps;
+  /** Pointer to the end of discrete line pattern. */
+  bool *fs;
+
+  /** X-start position of central scan (still used in locate (Pt2i)). */
+  int ccx;
+  /** Y-start position of central scan (still used in locate (Pt2i)). */
+  int ccy;
+  /** X-start position of last scan to the left. */
+  int lcx;
+  /** Y-start position of last scan to the left. */
+  int lcy;
+  /** X-start position of last scan to the right. */
+  int rcx;
+  /** Y-start position of last scan to the right. */
+  int rcy;
+
+  /** Current pattern step in scan line direction for left scans. */
+  bool *lst2;
+  /** Current pattern step in scan line direction for right scans. */
+  bool *rst2;
+
+  /** Flag indicating if the output vector should be cleared before filling.
+      Set to true by default. */
+  bool clearance;
+
+
+  /**
+   * \brief Creates an empty directional scanner.
+   */
+  DirectionalScanner () { }
+
+  /**
+   * \brief Creates an incremental directional scanner.
+   * Creates a directional scanner from pattern and start.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point and a line pattern.
+   * @param xmini Left border of the scan area.
+   * @param ymini Bottom border of the scan area.
+   * @param xmaxi Right border of the scan area.
+   * @param ymaxi Top border of the scan area.
+   * @param nb Size of the support line pattern.
+   * @param st Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  DirectionalScanner (int xmini, int ymini, int xmaxi, int ymaxi,
+                      int nb, bool* st, int sx, int sy)
+             : xmin (xmini), ymin (ymini), xmax (xmaxi), ymax (ymaxi),
+               nbs (nb), steps (st),
+               ccx (sx), ccy (sy), lcx (sx), lcy (sy), rcx (sx), rcy (sy),
+               clearance (true) { }
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  DirectionalScanner (DirectionalScanner *ds)
+         : xmin (ds->xmin), ymin (ds->ymin), xmax (ds->xmax), ymax (ds->ymax),
+           dla (ds->dla), dlb (ds->dlb), dlc2 (ds->dlc2),
+           nbs (ds->nbs), steps (ds->steps), fs (ds->fs),
+           ccx (ds->ccx), ccy (ds->ccy),
+           lcx (ds->lcx), lcy (ds->lcy), rcx (ds->rcx), rcy (ds->rcy),
+           lst2 (ds->lst2), rst2 (ds->rst2), clearance (ds->clearance) { }
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.cpp b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.cpp
new file mode 100644
index 0000000..c4a634f
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.cpp
@@ -0,0 +1,337 @@
+#include "directionalscannero1.h"
+
+
+DirectionalScannerO1::DirectionalScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+
+  lst1 = steps;
+  rst1 = steps;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO1::DirectionalScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else this->dlc2 = c2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx ++;
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  fs = steps + nbs;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO1::DirectionalScannerO1 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx ++;
+    lcy --;
+  }
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cx--;
+    cy++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO1::DirectionalScannerO1 (DirectionalScannerO1 *ds)
+                    : DirectionalScanner (ds)
+{
+  lst1 = ds->lst1;
+  rst1 = ds->rst1;
+  lstop = ds->lstop;
+  rstop = ds->rstop;
+}
+
+
+DirectionalScanner *DirectionalScannerO1::getCopy ()
+{
+  return (new DirectionalScannerO1 (this));
+}
+
+
+int DirectionalScannerO1::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO1::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (lstop)
+  {
+    lcy --;
+    if (--lst2 < steps) lst2 = fs - 1;
+    lstop = false;
+  }
+  else
+  {
+    if (--lst1 < steps) lst1 = fs - 1;
+    lcx --;
+    if (*lst1)
+    {
+      lcy --;
+      if (--lst2 < steps) lst2 = fs - 1;
+      if (*lst2)
+      {
+        if (++lst2 >= fs) lst2 = steps;
+        lcy ++;
+        lstop = true;
+      }
+    }
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO1::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (rstop)
+  {
+    rcx ++;
+    rstop = false;
+  }
+  else
+  {
+    rcx ++;
+    if (*rst1)
+    {
+      if (*rst2)
+      {
+        rcx --;
+        rstop = true;
+      }
+      rcy ++;
+      if (++rst2 >= fs) rst2 = steps;
+    }
+    if (++rst1 >= fs) rst1 = steps;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((x >= xmax || y < ymin) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x--;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+Pt2i DirectionalScannerO1::locate (const Pt2i &pt) const
+{
+  int x = ccx, y = ccy;      // Current position coordinates
+  bool *nst = steps;         // Current step in scan direction (jpts)
+  int cx = 0, cy = pt.y () - y;
+  bool *st1 = steps;
+  bool *st2 = steps;
+  
+  if (cy >= 0)
+  {
+    // Climbs the first scan up
+    while (y < pt.y ())
+    {
+      if (*nst) x--;
+      y++;
+      if (++nst >= fs) nst = steps;
+    }
+  }
+  else
+  {
+    // Climbs the first scan down
+    while (y > pt.y ())
+    {
+      y--;
+      if (--nst < steps) nst = fs -1;
+      if (*nst) x++;
+    }
+  }
+  cx = pt.x () - x;
+
+  // Comes back to scan origin
+  x = ccx;
+  y = ccy;
+  int nx = cx;
+  bool trans = false;
+  while (nx != 0)
+  {
+    // Jumps leftwards along scan bound
+    if (cx < 0)
+    {
+      if (trans)
+      {
+        y --;
+        if (--st2 < steps) st2 = fs - 1;
+        trans = false;
+      }
+      else
+      {
+        if (--st1 < steps) st1 = fs - 1;
+        x --;
+        if (*st1)
+        {
+          y --;
+          if (--st2 < steps) st2 = fs - 1;
+          if (*st2)
+          {
+            if (++st2 >= fs) st2 = steps;
+            y ++;
+            trans = true;
+          }
+        }
+      }
+      nx ++;
+    }
+    else
+    // Jumps rightwards along scan bound
+    {
+      if (trans)
+      {
+        x ++;
+        trans = false;
+      }
+      else
+      {
+        x ++;
+        if (*st1)
+        {
+          if (*st2)
+          { 
+            x --;
+            trans = true;
+          }
+          y ++;
+          if (++st2 >= fs) st2 = steps;
+        }
+        if (++st1 >= fs) st1 = steps;
+      }
+      nx --;
+    }
+  }
+
+  return (Pt2i (cx, pt.y () - y));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.h b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.h
new file mode 100644
index 0000000..f815866
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero1.h
@@ -0,0 +1,131 @@
+#ifndef DIRECTIONAL_SCANNER_O1_H
+#define DIRECTIONAL_SCANNER_O1_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class DirectionalScannerO1 directionalscannero1.h
+ * \brief Incremental directional scanner for the 1st octant.
+ */
+class DirectionalScannerO1 : public DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Creates a directional scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  DirectionalScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c,
+                        int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */ 
+  DirectionalScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c1, int c2,
+                        int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  DirectionalScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b,
+                        int nbs, bool *steps,
+                        int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Returns the scanner coordinates of given point.
+   * Scanner coordinates are the scan index and the position in the scan.
+   * @param pt Image coordinates of the point.
+   */
+  virtual Pt2i locate (const Pt2i &pt) const;
+
+
+private:
+
+  /** Current pattern step in strip direction on left side. */
+  bool *lst1;
+  /** Current pattern step in strip direction on right side. */
+  bool *rst1;
+
+  /** Status indicating no move in strip direction on next left scan. */
+  bool lstop;
+  /** Status indicating no move in strip direction on next right scan. */
+  bool rstop;
+
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  DirectionalScannerO1 (DirectionalScannerO1 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.cpp b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.cpp
new file mode 100644
index 0000000..e4164b7
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.cpp
@@ -0,0 +1,335 @@
+#include "directionalscannero2.h"
+
+
+DirectionalScannerO2::DirectionalScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+
+  lst1 = steps;
+  rst1 = steps;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO2::DirectionalScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else this->dlc2 = c2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx ++;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  fs = steps + nbs;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO2::DirectionalScannerO2 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx ++;
+  }
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cy++;
+    cx--;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  lstop = false; 
+  rstop = false;
+}
+
+
+DirectionalScannerO2::DirectionalScannerO2 (DirectionalScannerO2 *ds)
+                    : DirectionalScanner (ds)
+{
+  lst1 = ds->lst1;
+  rst1 = ds->rst1;
+  lstop = ds->lstop;
+  rstop = ds->rstop;
+}
+
+
+DirectionalScanner *DirectionalScannerO2::getCopy ()
+{
+  return (new DirectionalScannerO2 (this));
+}
+
+
+int DirectionalScannerO2::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO2::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (lstop)
+  {
+    lcy --;
+    lstop = false;
+  }
+  else
+  {
+    if (--lst1 < steps) lst1 = fs - 1;
+    lcy --;
+    if (*lst1)
+    {
+      lcx --;
+      if (*lst2)
+      {
+        lcy ++;
+        lstop = true;
+      }
+      if (++lst2 >= fs) lst2 = steps;
+    }
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO2::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (rstop)
+  {
+    rcx ++;
+    if (--rst2 < steps) rst2 = fs - 1;
+    rstop = false;
+  }
+  else
+  {
+    rcy ++;
+    if (*rst1)
+    {
+      if (--rst2 < steps) rst2 = fs - 1;
+      if (*rst2)
+      {
+        if (++rst2 >= fs) rst2 = steps;
+        rstop = true;
+      }
+      else rcx ++;
+    }
+    if (++rst1 >= fs) rst1 = steps;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x--;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+Pt2i DirectionalScannerO2::locate (const Pt2i &pt) const
+{
+  int x = ccx, y = ccy;      // Current position coordinates
+  bool *nst = steps;         // Current step in scan direction (jpts)
+  int cx = pt.x () - x, cy = 0;
+  bool *st1 = steps;
+  bool *st2 = steps;
+  
+  if (cx <= 0)
+  {
+    // Climbs the first scan up
+    while (x > pt.x ())
+    {
+      if (*nst) y++;
+      x--;
+      if (++nst >= fs) nst = steps;
+    }
+  }
+  else
+  {
+    // Climbs the first scan down
+    while (x < pt.x ())
+    {
+      x++;
+      if (--nst < steps) nst = fs - 1;
+      if (*nst) y--;
+    }
+  }
+  cy = pt.y () - y;
+
+  // Comes back to scan origin
+  x = ccx;
+  y = ccy;
+  int ny = cy;
+  bool trans = false;
+  while (ny != 0)
+  {
+    // Jumps leftwards along scan bound
+    if (cy < 0)
+    {
+      if (trans)
+      {
+        y --;
+        trans = false;
+      }
+      else
+      {
+        if (--st1 < steps) st1 = fs - 1;
+        y --;
+        if (*st1)
+        {
+          x --;
+          if (*st2)
+          {
+            y ++;
+            trans = true;
+          }
+          if (++st2 >= fs) st2 = steps;
+        }
+      }
+      ny ++;
+    }
+    else
+    // Jumps rightwards along scan bound
+    {
+      if (trans)
+      {
+        x ++;
+        if (--st2 < steps) st2 = fs - 1;
+        trans = false;
+      }
+      else
+      {
+        y ++;
+        if (*st1)
+        {
+          if (--st2 < steps) st2 = fs - 1;
+          if (*st2)
+          {
+            if (++st2 >= fs) st2 = steps;
+            trans = true;
+          }
+          else x ++;
+        }
+        if (++st1 >= fs) st1 = steps;
+      }
+      ny --;
+    }
+  }
+
+  return (Pt2i (cy, x - pt.x ()));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.h b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.h
new file mode 100644
index 0000000..ab6d543
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero2.h
@@ -0,0 +1,131 @@
+#ifndef DIRECTIONAL_SCANNER_O2_H
+#define DIRECTIONAL_SCANNER_O2_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class DirectionalScannerO2 directionalscannero2.h
+ * \brief Incremental directional scanner for the 2nd octant.
+ */
+class DirectionalScannerO2 : public DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Creates a directional scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'b' 'a' of the discrete support line.
+   * @param b Value of parameter 'b' 'b' of the discrete support line.
+   * @param c Value of parameter 'b' 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  DirectionalScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c,
+                        int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Valur of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  DirectionalScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c1, int c2,
+                        int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'a' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  DirectionalScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b,
+                        int nbs, bool *steps,
+                        int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Returns the scanner coordinates of given point.
+   * Scanner coordinates are the scan index and the position in the scan.
+   * @param pt Image coordinates of the point.
+   */
+  virtual Pt2i locate (const Pt2i &pt) const;
+
+
+private:
+
+  /** Current pattern step in strip direction on left side. */
+  bool *lst1;
+  /** Current pattern step in strip direction on right side. */
+  bool *rst1;
+
+  /** Status indicating no move in strip direction on next left scan. */
+  bool lstop;
+  /** Status indicating no move in strip direction on next right scan. */
+  bool rstop;
+
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  DirectionalScannerO2 (DirectionalScannerO2 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.cpp b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.cpp
new file mode 100644
index 0000000..efa3d7d
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.cpp
@@ -0,0 +1,335 @@
+#include "directionalscannero7.h"
+
+
+DirectionalScannerO7::DirectionalScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+
+  lst1 = steps;
+  rst1 = steps;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO7::DirectionalScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else this->dlc2 = c2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  fs = steps + nbs;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO7::DirectionalScannerO7 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcy --;
+    lcx --;
+  }
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cy++;
+    cx++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO7::DirectionalScannerO7 (DirectionalScannerO7 *ds)
+                    : DirectionalScanner (ds)
+{
+  lst1 = ds->lst1;
+  rst1 = ds->rst1;
+  lstop = ds->lstop;
+  rstop = ds->rstop;
+}
+
+
+DirectionalScanner *DirectionalScannerO7::getCopy ()
+{
+  return (new DirectionalScannerO7 (this));
+}
+
+
+int DirectionalScannerO7::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO7::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (lstop)
+  {
+    lcx --;
+    if (--lst2 < steps) lst2 = fs - 1;
+    lstop = false;
+  }
+  else
+  {
+    if (--lst1 < steps) lst1 = fs - 1;
+    lcy ++;
+    if (*lst1)
+    {
+      if (--lst2 < steps) lst2 = fs - 1;
+      if (*lst2)
+      {
+        if (++lst2 >= fs) lst2 = steps;
+        lstop = true;
+      }
+      else lcx --;
+    }
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO7::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (rstop)
+  {
+    rcy --;
+    rstop = false;
+  }
+  else
+  {
+    rcy --;
+    if (*rst1)
+    {
+      rcx ++;
+      if (*rst2)
+      {
+        rcy ++;
+        rstop = true;
+      }
+      if (++rst2 >= fs) rst2 = steps;
+    }
+    if (++rst1 >= fs) rst1 = steps;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((y < ymin || x < xmin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) y++;
+    x++;
+    if (++nst == fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) y++;
+    x++;
+    if (++nst == fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+Pt2i DirectionalScannerO7::locate (const Pt2i &pt) const
+{
+  int x = ccx, y = ccy;      // Current position coordinates
+  bool *nst = steps;         // Current step in scan direction (jpts)
+  int cx = pt.x () - x, cy = 0;
+  bool *st1 = steps;
+  bool *st2 = steps;
+  
+  if (cx >= 0)
+  {
+    // Climbs the first scan up
+    while (x < pt.x ())
+    {
+      if (*nst) y++;
+      x++;
+      if (++nst >= fs) nst = steps;
+    }
+  }
+  else
+  {
+    // Climbs the first scan down
+    while (x < pt.x ())
+    {
+      x--;
+      if (--nst < steps) nst = fs - 1;
+      if (*nst) y--;
+    }
+  }
+  cy = y - pt.y ();
+
+  // Comes back to scan origin
+  x = ccx;
+  y = ccy;
+  int ny = cy;
+  bool trans = false;
+  while (ny != 0)
+  {
+    // Jumps leftwards along scan bound
+    if (cy < 0)
+    {
+      if (trans)
+      {
+        y --;
+        trans = false;
+      }
+      else
+      {
+        if (--st1 < steps) st1 = fs - 1;
+        y --;
+        if (*st1)
+        {
+          x --;
+          if (*st2)
+          {
+            y ++;
+            trans = true;
+          }
+          if (++st2 >= fs) st2 = steps;
+        }
+      }
+      ny ++;
+    }
+    else
+    // Jumps rightwards along scan bound
+    {
+      if (trans)
+      {
+        x ++;
+        if (--st2 < steps) st2 = fs - 1;
+        trans = false;
+      }
+      else
+      {
+        y ++;
+        if (*st1)
+        {
+          if (--st2 < steps) st2 = fs - 1;
+          if (*st2)
+          {
+            if (++st2 >= fs) st2 = steps;
+            trans = true;
+          }
+          else x ++;
+        }
+        if (++st1 >= fs) st1 = steps;
+      }
+      ny --;
+    }
+  }
+
+  return (Pt2i (cy, pt.x () - x));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.h b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.h
new file mode 100644
index 0000000..9873163
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero7.h
@@ -0,0 +1,131 @@
+#ifndef DIRECTIONAL_SCANNER_O7_H
+#define DIRECTIONAL_SCANNER_O7_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class DirectionalScannerO7 directionalscannero7.h
+ * \brief Incremental directional scanner for the 7th octant.
+ */
+class DirectionalScannerO7 : public DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Creates a directional scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  DirectionalScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c,
+                        int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  DirectionalScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c1, int c2,
+                        int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  DirectionalScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b,
+                        int nbs, bool *steps,
+                        int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Returns the scanner coordinates of given point.
+   * Scanner coordinates are the scan index and the position in the scan.
+   * @param pt Image coordinates of the point.
+   */
+  virtual Pt2i locate (const Pt2i &pt) const;
+
+
+private:
+
+  /** Current pattern step in strip direction on left side. */
+  bool *lst1;
+  /** Current pattern step in strip direction on right side. */
+  bool *rst1;
+
+  /** Status indicating no move in strip direction on next left scan. */
+  bool lstop;
+  /** Status indicating no move in strip direction on next right scan. */
+  bool rstop;
+
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  DirectionalScannerO7 (DirectionalScannerO7 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.cpp b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.cpp
new file mode 100644
index 0000000..1134235
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.cpp
@@ -0,0 +1,335 @@
+#include "directionalscannero8.h"
+
+
+DirectionalScannerO8::DirectionalScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, sx, sy)
+{
+  this->dla = a;
+  this->dlb = b;
+  this->dlc2 = c;
+
+  lst1 = steps;
+  rst1 = steps;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO8::DirectionalScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else this->dlc2 = c2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  do
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx --;
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+  lst2 = st;
+  rst2 = st;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  fs = steps + nbs;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO8::DirectionalScannerO8 (
+                          int xmin, int ymin, int xmax, int ymax,
+                          int a, int b,
+                          int nbs, bool *steps, int cx, int cy, int length)
+                    : DirectionalScanner (xmin, ymin, xmax, ymax,
+                                          nbs, steps, cx, cy)
+{
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  bool *st = steps + nbs;
+  for (int i = 0; i < w_2; i++)
+  {
+    if (--st < steps) st = steps + nbs - 1;
+    if (*st) lcx --;
+    lcy --;
+  }
+  lst2 = st;
+  rst2 = st;
+
+  // Looking for the upper leaning line
+  st = steps;
+  while (w_2-- > 0)
+  {
+    if (*st) cx++;
+    cy++;
+    if (++st >= fs) st = steps;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  rcx = lcx;
+  rcy = lcy;
+/** ZZZ */
+ccx = lcx;
+ccy = lcy;
+/** ZZZ */
+  lst1 = steps;
+  rst1 = steps;
+  lstop = false;
+  rstop = false;
+}
+
+
+DirectionalScannerO8::DirectionalScannerO8 (DirectionalScannerO8 *ds)
+                    : DirectionalScanner (ds)
+{
+  lst1 = ds->lst1;
+  rst1 = ds->rst1;
+  lstop = ds->lstop;
+  rstop = ds->rstop;
+}
+
+
+DirectionalScanner *DirectionalScannerO8::getCopy ()
+{
+  return (new DirectionalScannerO8 (this));
+}
+
+
+int DirectionalScannerO8::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+  bool *nst = lst2;          // Current step in scan direction (jpts)
+
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO8::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (lstop)
+  {
+    lcx --;
+    lstop = false;
+  }
+  else
+  {
+    if (--lst1 < steps) lst1 = fs - 1;
+    lcx --;
+    if (*lst1)
+    {
+      lcy ++;
+      if (*lst2)
+      {
+        lcx ++;
+        lstop = true;
+      }
+      if (++lst2 >= fs) lst2 = steps;
+    }
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  bool *nst = lst2;
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int DirectionalScannerO8::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  if (rstop)
+  {
+    rcy --;
+    if (--rst2 < steps) rst2 = fs - 1;
+    rstop = false;
+  }
+  else
+  {
+    rcx ++;
+    if (*rst1)
+    {
+      if (--rst2 < steps) rst2 = fs - 1;
+      if (*rst2)
+      {
+        if (++rst2 >= fs) rst2 = steps;
+        rstop = true;
+      }
+      else rcy --;
+    }
+    if (++rst1 >= fs) rst1 = steps;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  bool *nst = rst2;
+  while ((x < xmin || y < ymin) && dla * x + dlb * y <= dlc2)
+  {
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    if (*nst) x++;
+    y++;
+    if (++nst >= fs) nst = steps;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+Pt2i DirectionalScannerO8::locate (const Pt2i &pt) const
+{
+  int x = ccx, y = ccy;      // Current position coordinates
+  bool *nst = steps;         // Current step in scan direction (jpts)
+  int cx = 0, cy = pt.y () - y;
+  bool *st1 = steps;
+  bool *st2 = steps;
+  
+  if (cy >= 0)
+  {
+    // Climbs the first scan up
+    while (y < pt.y ())
+    {
+      if (*nst) x++;
+      y++;
+      if (++nst >= fs) nst = steps;
+    }
+  }
+  else
+  {
+    // Climbs the first scan down
+    while (y > pt.y ())
+    {
+      y--;
+      if (--nst < steps) nst = fs -1;
+      if (*nst) x--;
+    }
+  }
+  cx = pt.x () - x;
+
+  // Comes back to scan origin
+  x = ccx;
+  y = ccy;
+  int nx = cx;
+  bool trans = false;
+  while (nx != 0)
+  {
+    // Jumps leftwards along scan bound
+    if (cx < 0)
+    {
+      if (trans)
+      {
+        x --;
+        trans = false;
+      }
+      else
+      {
+        if (--st1 < steps) st1 = fs - 1;
+        x --;
+        if (*st1)
+        {
+          y ++;
+          if (*st2)
+          {
+            x ++;
+            trans = true;
+          }
+          if (++st2 >= fs) st2 = steps;
+        }
+      }
+      nx ++;
+    }
+    else
+    // Jumps rightwards along scan bound
+    {
+      if (trans)
+      {
+        y --;
+        if (--st2 < steps) st2 = fs - 1;
+        trans = false;
+      }
+      else
+      { 
+        x ++;
+        if (*st1)
+        {
+          if (--st2 < steps) st2 = fs - 1;
+          if (*st2)
+          {
+            if (++st2 >= fs) st2 = steps;
+            trans = true;
+          }
+          else y --;
+        }
+        if (++st1 >= fs) st1 = steps;
+      }
+      nx --;
+    }
+  }
+
+  return (Pt2i (cx, pt.y () - y));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.h b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.h
new file mode 100644
index 0000000..ff56274
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/directionalscannero8.h
@@ -0,0 +1,131 @@
+#ifndef DIRECTIONAL_SCANNER_O8_H
+#define DIRECTIONAL_SCANNER_O8_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class DirectionalScannerO8 directionalscannero8.h
+ * \brief Incremental directional scanner for the 8th octant.
+ */
+class DirectionalScannerO8 : public DirectionalScanner
+{
+public:
+  
+  /**
+   * \brief Creates a directional scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  DirectionalScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c,
+                        int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  DirectionalScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b, int c1, int c2,
+                        int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a directional scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  DirectionalScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                        int a, int b,
+                        int nbs, bool *steps,
+                        int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Returns the scanner coordinates of given point.
+   * Scanner coordinates are the scan index and the position in the scan.
+   * @param pt Image coordinates of the point.
+   */
+  virtual Pt2i locate (const Pt2i &pt) const;
+
+
+private:
+
+  /** Current pattern step in strip direction on left side. */
+  bool *lst1;
+  /** Current pattern step in strip direction on right side. */
+  bool *rst1;
+
+  /** Status indicating no move in strip direction on next left scan. */
+  bool lstop;
+  /** Status indicating no move in strip direction on next right scan. */
+  bool rstop;
+
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  DirectionalScannerO8 (DirectionalScannerO8 *ds);
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/rechanged b/Expes/Testers/TestLines/DirectionalScanner/rechanged
new file mode 100644
index 0000000..6eab3c6
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/rechanged
@@ -0,0 +1,28 @@
+cmp directionalscanner.cpp ~/tmp/ASD/DirectionalScanner/directionalscanner.cpp
+cmp directionalscanner.h ~/tmp/ASD/DirectionalScanner/directionalscanner.h
+cmp directionalscannero1.cpp ~/tmp/ASD/DirectionalScanner/directionalscannero1.cpp
+cmp directionalscannero1.h ~/tmp/ASD/DirectionalScanner/directionalscannero1.h
+cmp directionalscannero2.cpp ~/tmp/ASD/DirectionalScanner/directionalscannero2.cpp
+cmp directionalscannero2.h ~/tmp/ASD/DirectionalScanner/directionalscannero2.h
+cmp directionalscannero7.cpp ~/tmp/ASD/DirectionalScanner/directionalscannero7.cpp
+cmp directionalscannero7.h ~/tmp/ASD/DirectionalScanner/directionalscannero7.h
+cmp directionalscannero8.cpp ~/tmp/ASD/DirectionalScanner/directionalscannero8.cpp
+cmp directionalscannero8.h ~/tmp/ASD/DirectionalScanner/directionalscannero8.h
+cmp adaptivescannero1.cpp ~/tmp/ASD/DirectionalScanner/adaptivescannero1.cpp
+cmp adaptivescannero1.h ~/tmp/ASD/DirectionalScanner/adaptivescannero1.h
+cmp adaptivescannero2.cpp ~/tmp/ASD/DirectionalScanner/adaptivescannero2.cpp
+cmp adaptivescannero2.h ~/tmp/ASD/DirectionalScanner/adaptivescannero2.h
+cmp adaptivescannero7.cpp ~/tmp/ASD/DirectionalScanner/adaptivescannero7.cpp
+cmp adaptivescannero7.h ~/tmp/ASD/DirectionalScanner/adaptivescannero7.h
+cmp adaptivescannero8.cpp ~/tmp/ASD/DirectionalScanner/adaptivescannero8.cpp
+cmp adaptivescannero8.h ~/tmp/ASD/DirectionalScanner/adaptivescannero8.h
+cmp scannerprovider.cpp ~/tmp/ASD/DirectionalScanner/scannerprovider.cpp
+cmp scannerprovider.h ~/tmp/ASD/DirectionalScanner/scannerprovider.h
+cmp vhscannero1.cpp ~/tmp/ASD/DirectionalScanner/vhscannero1.cpp
+cmp vhscannero1.h ~/tmp/ASD/DirectionalScanner/vhscannero1.h
+cmp vhscannero2.cpp ~/tmp/ASD/DirectionalScanner/vhscannero2.cpp
+cmp vhscannero2.h ~/tmp/ASD/DirectionalScanner/vhscannero2.h
+cmp vhscannero7.cpp ~/tmp/ASD/DirectionalScanner/vhscannero7.cpp
+cmp vhscannero7.h ~/tmp/ASD/DirectionalScanner/vhscannero7.h
+cmp vhscannero8.cpp ~/tmp/ASD/DirectionalScanner/vhscannero8.cpp
+cmp vhscannero8.h ~/tmp/ASD/DirectionalScanner/vhscannero8.h
diff --git a/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.cpp b/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.cpp
new file mode 100644
index 0000000..8d4d492
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.cpp
@@ -0,0 +1,194 @@
+#include "scannerprovider.h"
+#include "directionalscannero2.h"
+#include "directionalscannero7.h"
+#include "directionalscannero1.h"
+#include "directionalscannero8.h"
+#include "vhscannero2.h"
+#include "vhscannero7.h"
+#include "vhscannero1.h"
+#include "vhscannero8.h"
+
+
+DirectionalScanner *ScannerProvider::getScanner (Pt2i p1, Pt2i p2,
+                                                 bool controlable)
+{
+  // Enforces P1 to be lower than P2
+  // or to left of P2 in case of equality
+  lastScanReversed = (p1.y () > p2.y ())
+                     || ((p1.y () == p2.y ()) && (p1.x () > p2.x ()));
+  if (lastScanReversed)
+  {
+    Pt2i tmp (p1);
+    p1.set (p2);
+    p2.set (tmp);
+  }
+
+  // Computes the steps position array
+  int nbs = 0;
+  bool *steps = p1.stepsTo (p2, &nbs);
+
+  // Equation of the strip support lines : ax + by = c
+  int a = p2.x () - p1.x ();
+  int b = p2.y () - p1.y ();
+  if (a < 0 || (a == 0 && b < 0)) // Enforces a >= 0, then b > 0
+  {
+    a = -a;
+    b = -b;
+  }
+  int c2 = a * p2.x () + b * p2.y ();
+
+  // Builds and returns the appropriate scanner
+  if (b < 0)
+    if (-b > a)
+    {
+      if (isOrtho)
+      {
+        int repx = (p1.x () + p2.x ()) / 2;    // central scan start
+        int repy = p1.y () - (int) ((p1.x () - repx) * (p1.x () - p2.x ())
+                                    / (p2.y () - p1.y ()));
+        return (new VHScannerO1 (xmin, ymin, xmax, ymax,
+                                 a, b, c2, nbs, steps, repx, repy));
+      }
+      else return (controlable ?
+                   (DirectionalScanner *)
+                   new AdaptiveScannerO1 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()) :
+                   new DirectionalScannerO1 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()));
+    }
+    else
+    {
+      if (isOrtho)
+      {
+        int repy = (p1.y () + p2.y ()) / 2;    // central scan start
+        int repx = p1.x () + (int) ((repy - p1.y ()) * (p2.y () - p1.y ())
+                                    / (p1.x () - p2.x ()));
+        return (new VHScannerO2 (xmin, ymin, xmax, ymax,
+                                 a, b, c2, nbs, steps, repx, repy));
+      }
+      else return (controlable ?
+                   (DirectionalScanner *)
+                   new AdaptiveScannerO2 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()) :
+                   new DirectionalScannerO2 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()));
+    }
+  else
+    if (b > a)
+    {
+      if (isOrtho)
+      {
+        int repx = (p1.x () + p2.x ()) / 2;    // central scan start
+        int repy = p1.y () - (int) ((repx - p1.x ()) * (p2.x () - p1.x ())
+                                    / (p2.y () - p1.y ()));
+        return (new VHScannerO8 (xmin, ymin, xmax, ymax,
+                                 a, b, c2, nbs, steps, repx, repy));
+      }
+      else return (controlable ?
+                   (DirectionalScanner *)
+                   new AdaptiveScannerO8 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()) :
+                   new DirectionalScannerO8 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()));
+    }
+    else
+    {
+      if (isOrtho)
+      {
+        int repy = (p1.y () + p2.y ()) / 2;    // central scan start
+        int repx = p1.x () - (int) ((repy - p1.y ()) * (p2.y () - p1.y ())
+                                    / (p2.x () - p1.x ()));
+        return (new VHScannerO7 (xmin, ymin, xmax, ymax,
+                                 a, b, c2, nbs, steps, repx, repy));
+      }
+      else return (controlable ?
+                   (DirectionalScanner *)
+                   new AdaptiveScannerO7 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()) :
+                   new DirectionalScannerO7 (xmin, ymin, xmax, ymax,
+                          a, b, c2, nbs, steps, p1.x (), p1.y ()));
+    }
+}
+
+
+DirectionalScanner *ScannerProvider::getScanner (Pt2i centre, Vr2i normal,
+                                                 int length, bool controlable)
+{
+  // Gets the steps position array
+  int nbs = 0;
+  bool *steps = centre.stepsTo (Pt2i (centre.x () + normal.x (),
+                                      centre.y () + normal.y ()), &nbs);
+
+  // Orients rightwards
+  int a = normal.x ();
+  int b = normal.y ();  // as equation is (ax + by = c)
+  if (a < 0 || (a == 0 && b < 0))
+  {
+    a = -a;
+    b = -b;
+  }
+
+  // Builds and returns the appropriate scanner
+  if (b < 0)
+    if (-b > a)
+      return (controlable ?
+              (isOrtho ?
+               (DirectionalScanner *)
+               new VHScannerO1 (xmin, ymin, xmax, ymax,
+                                a, b, nbs, steps,
+                                centre.x (), centre.y (), length) :
+               (DirectionalScanner *)
+               new AdaptiveScannerO1 (xmin, ymin, xmax, ymax,
+                                      a, b, nbs, steps,
+                                      centre.x (), centre.y (), length)) :
+              (DirectionalScanner *)
+              new DirectionalScannerO1 (xmin, ymin, xmax, ymax,
+                                        a, b, nbs, steps,
+                                        centre.x (), centre.y (), length));
+    else
+      return (controlable ?
+              (isOrtho ?
+               (DirectionalScanner *)
+               new VHScannerO2 (xmin, ymin, xmax, ymax,
+                                a, b, nbs, steps,
+                                centre.x (), centre.y (), length) :
+               (DirectionalScanner *)
+               new AdaptiveScannerO2 (xmin, ymin, xmax, ymax,
+                                      a, b, nbs, steps,
+                                      centre.x (), centre.y (), length)) :
+              (DirectionalScanner *)
+              new DirectionalScannerO2 (xmin, ymin, xmax, ymax,
+                                        a, b, nbs, steps,
+                                        centre.x (), centre.y (), length));
+  else
+    if (b > a)
+      return (controlable ?
+              (isOrtho ?
+               (DirectionalScanner *)
+               new VHScannerO8 (xmin, ymin, xmax, ymax,
+                                a, b, nbs, steps,
+                                centre.x (), centre.y (), length) :
+               (DirectionalScanner *)
+               new AdaptiveScannerO8 (xmin, ymin, xmax, ymax,
+                                      a, b, nbs, steps,
+                                      centre.x (), centre.y (), length)) :
+              (DirectionalScanner *)
+              new DirectionalScannerO8 (xmin, ymin, xmax, ymax,
+                                        a, b, nbs, steps,
+                                        centre.x (), centre.y (), length));
+    else
+      return (controlable ?
+              (isOrtho ?
+               (DirectionalScanner *)
+               new VHScannerO7 (xmin, ymin, xmax, ymax,
+                                a, b, nbs, steps,
+                                centre.x (), centre.y (), length) :
+               (DirectionalScanner *)
+               new AdaptiveScannerO7 (xmin, ymin, xmax, ymax,
+                                      a, b, nbs, steps,
+                                      centre.x (), centre.y (), length)) :
+              (DirectionalScanner *)
+              new DirectionalScannerO7 (xmin, ymin, xmax, ymax,
+                                        a, b, nbs, steps,
+                                        centre.x (), centre.y (), length));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.h b/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.h
new file mode 100644
index 0000000..f8af1f7
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/scannerprovider.h
@@ -0,0 +1,93 @@
+#ifndef SCANNER_PROVIDER_H
+#define SCANNER_PROVIDER_H
+
+#include "directionalscanner.h"
+
+
+/** 
+ * @class ScannerProvider scannerprovider.h
+ * \brief Directional scanner provider.
+ * Provides ad-hoc directional scanners in the relevant octant
+ *   and according to static or dynamical control.
+ */
+class ScannerProvider
+{
+public:
+
+  /**
+   * \brief Builds a directional scanner provider.
+   */
+  ScannerProvider () : isOrtho (false), lastScanReversed (false),
+                       xmin (0), ymin (0), xmax (100), ymax (100) { }
+  
+  /**
+   * \brief Sets the scanned area size.
+   * @param sizex Scan area width.
+   * @param sizey Scan area height.
+   */
+   void setSize (int sizex, int sizey) {
+     xmax = xmin + sizex; ymax = ymin + sizey; }
+
+  /**
+   * \brief Sets the scanned area size.
+   * @param x0 Left column coordinate of the scan area.
+   * @param y0 Lower line coordinate of the scan area.
+   * @param sizex Scan area width.
+   * @param sizey Scan area height.
+   */
+   void setArea (int x0, int y0, int sizex, int sizey) {
+     xmin = x0, ymin = y0, xmax = x0 + sizex; ymax = y0 + sizey; }
+
+  /**
+   * \brief Returns a directional scanner from initial scan end points.
+   * Returns a directional scanner from two control points.
+   * The scan strip is composed of parallel scans (line segments),
+   *   the initial one being defined by control points p1 and p2.
+   * @param p1 Initial scan start point.
+   * @param p2 Initial scan end point.
+   * @param controlable Control modality (true for an adaptive scanner).
+   */
+  DirectionalScanner *getScanner (Pt2i p1, Pt2i p2, bool controlable = false);
+  
+  /**
+   * \brief Returns a directional scanner from scan center, vector and length.
+   * The scan strip is composed of parallel scans (line segments),
+   *   the first one defined by its center, its direct vector, and its length.
+   * @param centre Initial scan center.
+   * @param normal Initial scan direct vector.
+   * @param length Initial scan length.
+   * @param controlable Control modality (true for an adaptive scanner).
+   */
+  DirectionalScanner *getScanner (Pt2i centre, Vr2i normal,
+                                  int length, bool controlable = false);
+
+  /**
+   * \brief Returns whether the currently used scan end points were permutated.
+   */
+  inline bool isLastScanReversed () const { return lastScanReversed; }
+
+  /**
+   * \brief Sets the orthogonal scanner modality.
+   * @param status New status for the orthogonal scanner modality.
+   */
+  inline void setOrtho (bool status) { isOrtho = status; }
+
+
+private:
+
+  /** Orthogonal scanner modality. */
+  bool isOrtho;
+  /** Last scan end points permutation modality. */
+  bool lastScanReversed;
+
+  /** Scan area lowest x coordinate. */
+  int xmin;
+  /** Scan area lowest y coordinate. */
+  int ymin;
+  /** Scan area highest x coordinate. */
+  int xmax;
+  /** Scan area highest y coordinate. */
+  int ymax;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.cpp b/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.cpp
new file mode 100644
index 0000000..8a7c512
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.cpp
@@ -0,0 +1,194 @@
+#include "vhscannero1.h"
+
+
+VHScannerO1::VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : AdaptiveScannerO1 (xmin, ymin, xmax, ymax,
+                                         a, b, c, nbs, steps, sx, sy)
+{
+}
+
+
+VHScannerO1::VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  // Looking for the central scan start position
+  do
+  {
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+VHScannerO1::VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int nbs, bool *steps,
+                          int cx, int cy, int length)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  for (int i = 0; i < w_2; i++)
+  {
+    lcy --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+
+  // Looking for the upper leaning line
+  while (w_2-- > 0)
+  {
+    cy++;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+}
+
+
+VHScannerO1::VHScannerO1 (VHScannerO1 *ds) : AdaptiveScannerO1 (ds)
+{
+}
+
+
+DirectionalScanner *VHScannerO1::getCopy ()
+{
+  return (new VHScannerO1 (this));
+}
+
+
+int VHScannerO1::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+
+  while (y < ymin && dla * x + dlb * y >= dlc2)
+  {
+    y++;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO1::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcx --;
+  if (lcx < xmin) return 0;
+
+  // Whenever the control line changed
+  while (lcy < ymax - 1 && dla * lcx + dlb * lcy > dlc1)
+  {
+    lcy ++;
+  }
+  while (lcy > ymin && dla * lcx + dlb * lcy < dlc1)
+  {
+    lcy --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  while (y < ymin && dla * x + dlb * y >= dlc2)
+  {
+    y ++;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y ++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO1::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcx ++;
+  if (rcx >= xmax) return 0;
+
+  while (rcy < ymax - 1 && dla * rcx + dlb * rcy > dlc1)
+  {
+    rcy ++;
+  }
+  while (rcy > ymin && dla * rcx + dlb * rcy < dlc1)
+  {
+    rcy --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  while (y < ymin && dla * x + dlb * y >= dlc2)
+  {
+    y++;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y++;
+  }
+  return ((int) (scan.size ()));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.h b/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.h
new file mode 100644
index 0000000..868dfbe
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero1.h
@@ -0,0 +1,113 @@
+#ifndef VH_SCANNER_O1_H
+#define VH_SCANNER_O1_H
+
+#include "adaptivescannero1.h"
+
+
+/** 
+ * @class VHScannerO1 vhscannero1.h
+ * \brief Vertical/horizontal adaptive DS for the 1st octant.
+ */
+class VHScannerO1 : public AdaptiveScannerO1
+{
+public:
+  
+  /**
+   * \brief Creates a vh scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c,
+               int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */ 
+  VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c1, int c2,
+               int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and length .
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  VHScannerO1 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int nbs, bool *steps,
+               int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+
+private:
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  VHScannerO1 (VHScannerO1 *ds);
+
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.cpp b/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.cpp
new file mode 100644
index 0000000..005b7db
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.cpp
@@ -0,0 +1,194 @@
+#include "vhscannero2.h"
+
+
+VHScannerO2::VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : AdaptiveScannerO2 (xmin, ymin, xmax, ymax,
+                                         a, b, c, nbs, steps, sx, sy)
+{
+}
+
+
+VHScannerO2::VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  if (c2 > c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  // Looking for the central scan start position
+  do
+  {
+    lcx ++;
+  }
+  while (dla * lcx + dlb * lcy < c1);
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+VHScannerO2::VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int nbs, bool *steps,
+                          int cx, int cy, int length)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  for (int i = 0; i < w_2; i++)
+  {
+    lcx ++;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+
+  // Looking for the upper leaning line
+  while (w_2-- > 0)
+  {
+    cx--;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc1 - this->dlc2;
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+}
+
+
+VHScannerO2::VHScannerO2 (VHScannerO2 *ds) : AdaptiveScannerO2 (ds)
+{
+}
+
+
+DirectionalScanner *VHScannerO2::getCopy ()
+{
+  return (new VHScannerO2 (this));
+}
+
+
+int VHScannerO2::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+
+  while (x >= xmax && dla * x + dlb * y >= dlc2)
+  {
+    x--;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    x--;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO2::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcy --;
+  if (lcy < ymin) return 0;
+
+  // Whenever the control line changed
+  while (lcx > xmin && dla * lcx + dlb * lcy > dlc1)
+  {
+    lcx --;
+  }
+  while (lcx < xmax - 1 && dla * lcx + dlb * lcy < dlc1)
+  {
+    lcx ++;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  while (x >= xmax && dla * x + dlb * y >= dlc2)
+  {
+    x--;
+  }
+  while (dla * x + dlb * y >= dlc2 && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    x--;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO2::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcy ++;
+  if (rcy >= ymax) return 0;
+
+  while (rcx > xmin && dla * rcx + dlb * rcy > dlc1)
+  {
+    rcx --;
+  }
+  while (rcx < xmax - 1 && dla * rcx + dlb * rcy < dlc1)
+  {
+    rcx ++;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  while ((y < ymin || x >= xmax) && dla * x + dlb * y >= dlc2)
+  {
+    x--;
+  }
+  while (dla * x + dlb * y >= dlc2 && y < ymax && x >= xmin)
+  {
+    scan.push_back (Pt2i (x, y));
+    x--;
+  }
+  return ((int) (scan.size ()));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.h b/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.h
new file mode 100644
index 0000000..6012abb
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero2.h
@@ -0,0 +1,113 @@
+#ifndef VH_SCANNER_O2_H
+#define VH_SCANNER_O2_H
+
+#include "adaptivescannero2.h"
+
+
+/** 
+ * @class VHScannerO2 vhscannero2.h
+ * \brief Vertical / horizontal adpative DS for the 2nd octant.
+ */
+class VHScannerO2 : public AdaptiveScannerO2
+{
+public:
+  
+  /**
+   * \brief Creates a vh scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c,
+               int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c1, int c2,
+               int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  VHScannerO2 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int nbs, bool *steps,
+               int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+
+private :
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  VHScannerO2 (VHScannerO2 *ds);
+
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.cpp b/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.cpp
new file mode 100644
index 0000000..924bff3
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.cpp
@@ -0,0 +1,194 @@
+#include "vhscannero7.h"
+
+
+VHScannerO7::VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : AdaptiveScannerO7 (xmin, ymin, xmax, ymax,
+                                         a, b, c, nbs, steps, sx, sy)
+{
+}
+
+
+VHScannerO7::VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  // Looking for the central scan start position
+  do
+  {
+    lcx --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+VHScannerO7::VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int nbs, bool *steps,
+                          int cx, int cy, int length)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  for (int i = 0; i < w_2; i++)
+  {
+    lcx --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+
+  // Looking for the upper leaning line
+  while (w_2-- > 0)
+  {
+    cx++;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+}
+
+
+VHScannerO7::VHScannerO7 (VHScannerO7 *ds) : AdaptiveScannerO7 (ds)
+{
+}
+
+
+DirectionalScanner *VHScannerO7::getCopy ()
+{
+  return (new VHScannerO7 (this));
+}
+
+
+int VHScannerO7::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+
+  while (x < xmin && dla * x + dlb * y <= dlc2)
+  {
+    x++;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    x++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO7::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcy ++;
+  if (lcy >= ymax) return 0;
+
+  while (lcx < xmax - 1 && dla * lcx + dlb * lcy < dlc1)
+  {
+    lcx ++;
+  }
+  while (lcx > xmin && dla * lcx + dlb * lcy > dlc1)
+  {
+    lcx --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  while (x < xmin && dla * x + dlb * y <= dlc2)
+  {
+    x++;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    x++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO7::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcy --;
+  if (rcy < ymin) return 0;
+
+  // Whenever the control corridor changed
+  while (rcx < xmax - 1 && dla * rcx + dlb * rcy < dlc1)
+  {
+    rcx ++;
+  }
+  while (rcx > xmin && dla * rcx + dlb * rcy > dlc1)
+  {
+    rcx --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  while (x < xmin && dla * x + dlb * y <= dlc2)
+  {
+    x++;
+  }
+  while (dla * x + dlb * y <= dlc2 && x < xmax)
+  {
+    scan.push_back (Pt2i (x, y));
+    x++;
+  }
+  return ((int) (scan.size ()));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.h b/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.h
new file mode 100644
index 0000000..3e31ddc
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero7.h
@@ -0,0 +1,113 @@
+#ifndef VH_SCANNER_O7_H
+#define VH_SCANNER_O7_H
+
+#include "adaptivescannero7.h"
+
+
+/** 
+ * @class VHScannerO7 vhscannero7.h
+ * \brief Vertical / horizontal adaptive DS for the 7th octant.
+ */
+class VHScannerO7 : public AdaptiveScannerO7
+{
+public:
+  
+  /**
+   * \brief Creates a vh scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c,
+               int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c1, int c2,
+               int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  VHScannerO7 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int nbs, bool *steps,
+               int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+
+private :
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  VHScannerO7 (VHScannerO7 *ds);
+
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.cpp b/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.cpp
new file mode 100644
index 0000000..00703b2
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.cpp
@@ -0,0 +1,194 @@
+#include "vhscannero8.h"
+
+
+VHScannerO8::VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c,
+                          int nbs, bool *steps, int sx, int sy)
+                    : AdaptiveScannerO8 (xmin, ymin, xmax, ymax,
+                                         a, b, c, nbs, steps, sx, sy)
+{
+}
+
+
+VHScannerO8::VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int c1, int c2,
+                          int nbs, bool *steps, int cx, int cy)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  if (c2 < c1)
+  {
+    this->dlc1 = c2;
+    this->dlc2 = c1;
+    c1 = c2;
+  }
+  else
+  {
+    this->dlc1 = c1;
+    this->dlc2 = c2;
+  }
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  // Looking for the central scan start position
+  do
+  {
+    lcy --;
+  }
+  while (dla * lcx + dlb * lcy > c1);
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+  fs = steps + nbs;
+}
+
+
+VHScannerO8::VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+                          int a, int b, int nbs, bool *steps,
+                          int cx, int cy, int length)
+{
+  this->xmin = xmin;
+  this->xmax = xmax;
+  this->ymin = ymin;
+  this->ymax = ymax;
+  this->nbs = nbs;
+  this->steps = steps;
+  lcx = cx;
+  lcy = cy;
+  rcx = cx;
+  rcy = cy;
+  this->dla = a;
+  this->dlb = b;
+  fs = steps + nbs;
+  int w_2 = (length + 1) / 2;
+
+  // Looking for the central scan start position
+  for (int i = 0; i < w_2; i++)
+  {
+    lcy --;
+  }
+  dlc1 = dla * lcx + dlb * lcy;
+
+  // Looking for the upper leaning line
+  while (w_2-- > 0)
+  {
+    cy++;
+  }
+  dlc2 = dla * cx + dlb * cy;
+
+  this->templ_a = a;
+  this->templ_b = b;
+  this->templ_nu = this->dlc2 - this->dlc1;
+
+  rcx = lcx;
+  rcy = lcy;
+  lst2 = steps;
+  rst2 = steps;
+}
+
+
+VHScannerO8::VHScannerO8 (VHScannerO8 *ds) : AdaptiveScannerO8 (ds)
+{
+}
+
+
+DirectionalScanner *VHScannerO8::getCopy ()
+{
+  return (new VHScannerO8 (this));
+}
+
+
+int VHScannerO8::first (std::vector<Pt2i> &scan) const
+{
+  int x = lcx, y = lcy;      // Current position coordinates
+
+  while (y < ymin && dla * x + dlb * y <= dlc2)
+  {
+    y++;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO8::nextOnLeft (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  lcx --;
+  if (lcx < xmin) return 0;
+
+  while (lcy < ymax - 1 && dla * lcx + dlb * lcy < dlc1)
+  {
+    lcy ++;
+  }
+  while (lcy > ymin && dla * lcx + dlb * lcy > dlc1)
+  {
+    lcy --;
+  }
+
+  // Computes the next scan
+  int x = lcx;
+  int y = lcy;
+  while (y < ymin && dla * x + dlb * y <= dlc2)
+  {
+    y++;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y++;
+  }
+  return ((int) (scan.size ()));
+}
+
+
+int VHScannerO8::nextOnRight (std::vector<Pt2i> &scan)
+{
+  // Prepares the next scan
+  if (clearance) scan.clear ();
+  rcx ++;
+  if (rcx >= xmax) return 0;
+
+  // Whenever the control corridor changed
+  while (rcy < ymax - 1 && dla * rcx + dlb * rcy < dlc1)
+  {
+    rcy ++;
+  }
+  while (rcy > ymin && dla * rcx + dlb * rcy > dlc1)
+  {
+    rcy --;
+  }
+
+  // Computes the next scan
+  int x = rcx;
+  int y = rcy;
+  while (y < ymin && dla * x + dlb * y <= dlc2)
+  {
+    y++;
+  }
+  while (dla * x + dlb * y <= dlc2 && y < ymax)
+  {
+    scan.push_back (Pt2i (x, y));
+    y++;
+  }
+  return ((int) (scan.size ()));
+}
diff --git a/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.h b/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.h
new file mode 100644
index 0000000..85fbe8d
--- /dev/null
+++ b/Expes/Testers/TestLines/DirectionalScanner/vhscannero8.h
@@ -0,0 +1,113 @@
+#ifndef VH_SCANNER_O8_H
+#define VH_SCANNER_O8_H
+
+#include "adaptivescannero8.h"
+
+
+/** 
+ * @class VHScannerO8 vhscannero8.h
+ * \brief Vertical / horizontal adaptive DS for the 8th octant.
+ */
+class VHScannerO8 : public AdaptiveScannerO8
+{
+public:
+  
+  /**
+   * \brief Creates a vh scanner from pattern, start and upper bound.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a start point, a line pattern, and an upper bound.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c Value of parameter 'c' of the upper bounding line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param sx X-coordinate of the central scan start point.
+   * @param sy Y-coordinate of the central scan start point.
+   */
+  VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c,
+               int nbs, bool *steps, int sx, int sy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and bounds.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, upper and lower bounds.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'b' of the discrete support line.
+   * @param c1 Value of parameter 'c' of one of the support lines.
+   * @param c2 Value of parameter 'c' of the other support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   */
+  VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int c1, int c2,
+               int nbs, bool *steps, int cx, int cy);
+
+  /**
+   * \brief Creates a vh scanner from pattern, center and length.
+   * The scan strip is composed of parallel scan lines, the first one being
+   *   defined by a center, a line pattern, and a length value.
+   * @param xmin Left border of the scan area.
+   * @param ymin Bottom border of the scan area.
+   * @param xmax Right border of the scan area.
+   * @param ymax Top border of the scan area.
+   * @param a Value of parameter 'a' of the discrete support line.
+   * @param b Value of parameter 'a' of the discrete support line.
+   * @param nbs Size of the support line pattern.
+   * @param steps Support line pattern.
+   * @param cx X-coordinate of the central scan center.
+   * @param cy Y-coordinate of the central scan center.
+   * @param length Length of a scan strip.
+   */
+  VHScannerO8 (int xmin, int ymin, int xmax, int ymax,
+               int a, int b, int nbs, bool *steps,
+               int cx, int cy, int length);
+
+  /**
+   * \brief Returns a copy of the directional scanner.
+   */
+  DirectionalScanner *getCopy ();
+
+  /**
+   * \brief Gets the central scan in a vector.
+   * Adds central scan points to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int first (std::vector<Pt2i> &scan) const;
+
+  /**
+   * \brief Gets the next scan on the left in a vector.
+   * Adds points of next left scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnLeft (std::vector<Pt2i> &scan);
+
+  /**
+   * \brief Gets the next scan on the right in a vector.
+   * Adds points of next right scan to given vector and returns its new size.
+   * @param scan Vector of points to be completed.
+   */
+  int nextOnRight (std::vector<Pt2i> &scan);
+
+
+private :
+
+  /**
+   * \brief Creates a copy of given directional scanner.
+   * @param ds Source directional scanner.
+   */
+  VHScannerO8 (VHScannerO8 *ds);
+
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/absrat.h b/Expes/Testers/TestLines/ImageTools/absrat.h
new file mode 100644
index 0000000..ffdb786
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/absrat.h
@@ -0,0 +1,71 @@
+#ifndef ABSOLUTE_RATIONAL_H
+#define ABSOLUTE_RATIONAL_H
+
+
+/** 
+ * @class AbsRat absrat.h
+ * \brief Absolutely useless rational type.
+ * 
+ * This type is only maintained to ensure the compatibility of
+ *   DigitalStraightSegment::naiveLine function used
+ *   for IpolDemo and AMREL (seeds selection).
+ * Better not use it anymore.
+ */
+class AbsRat
+{
+public:
+
+  /**
+   * \brief Creates an rational number with null value.
+   */
+  AbsRat () : r_num (0), r_den (1) { }
+
+  /**
+   * \brief Sets a value for numerator and denominator.
+   * @param numerator Numerator value.
+   * @param denominator Denominator value.
+   */
+  inline void set (int numerator, int denominator) {
+    r_num = numerator; r_den = denominator; }
+
+  /**
+   * \brief Sets a integer value for the rational number.
+   * @param val Integer value.
+   */
+  inline void set (int val) { r_num = val; r_den = 1; }
+
+  /**
+   * \brief Deletes the rational number.
+   */
+  ~AbsRat () { }
+
+  /**
+   * \brief Returns the numerator of the rational number.
+   */
+  inline int numerator () const { return r_num; }
+
+  /**
+   * \brief Returns the denominator of the rational number.
+   */
+  inline int denominator () const { return r_den; }
+
+  /**
+   * \brief Returns the numerator of the rational number.
+   */
+  inline int num () const { return r_num; }
+
+  /**
+   * \brief Returns the denominator of the rational number.
+   */
+  inline int den () const { return r_den; }
+
+
+protected:
+
+  /** Numerator of the rational number. */
+  int r_num;
+  /** Denominator of the rational number. */
+  int r_den;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/changed b/Expes/Testers/TestLines/ImageTools/changed
new file mode 100644
index 0000000..9697e2a
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/changed
@@ -0,0 +1,13 @@
+cmp absrat.h ~/git/2019-FBSD/Code/FBSD/ImageTools/absrat.h
+cmp digitalstraightline.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/digitalstraightline.cpp
+cmp digitalstraightline.h ~/git/2019-FBSD/Code/FBSD/ImageTools/digitalstraightline.h
+cmp digitalstraightsegment.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/digitalstraightsegment.cpp
+cmp digitalstraightsegment.h ~/git/2019-FBSD/Code/FBSD/ImageTools/digitalstraightsegment.h
+cmp edist.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/edist.cpp
+cmp edist.h ~/git/2019-FBSD/Code/FBSD/ImageTools/edist.h
+cmp pt2i.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/pt2i.cpp
+cmp pt2i.h ~/git/2019-FBSD/Code/FBSD/ImageTools/pt2i.h
+cmp vmap.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/vmap.cpp
+cmp vmap.h ~/git/2019-FBSD/Code/FBSD/ImageTools/vmap.h
+cmp vr2i.cpp ~/git/2019-FBSD/Code/FBSD/ImageTools/vr2i.cpp
+cmp vr2i.h ~/git/2019-FBSD/Code/FBSD/ImageTools/vr2i.h
diff --git a/Expes/Testers/TestLines/ImageTools/digitalstraightline.cpp b/Expes/Testers/TestLines/ImageTools/digitalstraightline.cpp
new file mode 100644
index 0000000..c7dede7
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/digitalstraightline.cpp
@@ -0,0 +1,460 @@
+#include "digitalstraightline.h"
+
+const int DigitalStraightLine::DSL_THIN = 1;
+const int DigitalStraightLine::DSL_NAIVE = 2;
+const int DigitalStraightLine::DSL_STANDARD = 3;
+
+
+DigitalStraightLine::DigitalStraightLine (int a, int b, int c, int nu)
+{
+  this->a = a;
+  this->b = b;
+  if (nu < 0)
+  {
+    this->c = c + 1 + nu;
+    this->nu = - nu;
+  }
+  else
+  {
+    this->c = c;
+    this->nu = nu;
+  }
+  if (a < 0)
+  {
+    this->a = - this->a;
+    this->b = - this->b;
+    this->c = 1 - c - nu;
+  }
+  else if (a == 0 && b < 0)
+  {
+    this->b = - this->b;
+    this->c = 1 - c - nu;
+  }
+  int pg = pgcd (a, (b < 0 ?  - b : b));
+  if (pg != 1)
+  {
+    a /= pg;
+    b /= pg;
+    c /= pg;
+    nu /= pg;
+  }
+}
+
+
+DigitalStraightLine::DigitalStraightLine (Pt2i p1, Pt2i p2, int type)
+{
+  if (p1.y () < p2.y ())
+  {
+    a = p2.y () - p1.y ();
+    b = p1.x () - p2.x ();
+  }
+  else
+  {
+    a = p1.y () - p2.y ();
+    b = p2.x () - p1.x ();
+    if (a == 0 && b < 0) b = -b;
+  }
+  int pg = pgcd (a, b < 0 ? -b : b);
+  a /= pg;
+  b /= pg;
+  c = a * p1.x () + b * p1.y ();
+
+  if (type == DSL_NAIVE)
+  {
+    nu = b;
+    if (nu < 0) nu = -nu;
+    if (nu < a) nu = a;
+    // To match Pt2i::stepsTo method ...
+    c -= nu / 2;
+  }
+
+  else if (type == DSL_STANDARD)
+  {
+    nu = a + (b < 0 ? -b : b);
+    if ((b > 0 && a > b) || (b < 0 && a < -b))
+      c -= (nu - 1) / 2;
+    else
+      c -= nu / 2;
+  }
+
+  else // type == DSL_THIN
+    nu = 1;
+}
+
+
+DigitalStraightLine::DigitalStraightLine (Pt2i p1, Pt2i p2, Pt2i p3)
+{
+  if (p1.y () < p2.y ())
+  {
+    a = p2.y () - p1.y ();
+    b = p1.x () - p2.x ();
+  }
+  else
+  {
+    a = p1.y () - p2.y ();
+    b = p2.x () - p1.x ();
+    if (a == 0 && b < 0) b = -b;
+  }
+  int pg = pgcd (a, b < 0 ? -b : b);
+  a /= pg;
+  b /= pg;
+  c = a * p1.x () + b * p1.y ();
+  int d = a * p3.x () + b * p3.y ();
+  if (d < c)
+  {
+    nu = c - d + 1;
+    c = d;
+  }
+  else nu = d - c + 1;
+}
+
+
+DigitalStraightLine::DigitalStraightLine (Pt2i p1, Pt2i p2,
+                                          int type, int atRight)
+{
+  if (p1.y () < p2.y ())
+  {
+    a = p2.y () - p1.y ();
+    b = p1.x () - p2.x ();
+  }
+  else
+  {
+    a = p1.y () - p2.y ();
+    b = p2.x () - p1.x ();
+    if (a == 0 && b < 0) b = -b;
+  }
+  int pg = pgcd (a, b < 0 ? -b : b);
+  a /= pg;
+  b /= pg;
+  c = a * p1.x () + b * p1.y ();
+
+  int bb = (b < 0 ? -b : b);
+  c += atRight * (a < bb ? bb : a);
+
+  if (type == DSL_NAIVE)
+  {
+    nu = b;
+    if (nu < 0) nu = -nu;
+    if (nu < a) nu = a;
+    // To match Pt2i::stepsTo method ...
+    if ((b > 0 && a > b) || (b < 0 && a < -b))
+      c -= (nu - 1) / 2;
+    else
+      c -= nu / 2;
+  }
+
+  else if (type == DSL_STANDARD)
+  {
+    nu = a + (b < 0 ? -b : b);
+    if ((b > 0 && a > b) || (b < 0 && a < -b))
+      c -= (nu - 1) / 2;
+    else
+      c -= nu / 2;
+  }
+
+  else // type == DSL_THIN
+    nu = 1;
+}
+
+
+DigitalStraightLine::DigitalStraightLine (const DigitalStraightLine &l)
+{
+  a = l.a;
+  b = l.b;
+  c = l.c;
+  nu = l.nu;
+}
+
+
+int DigitalStraightLine::manhattan (Pt2i pix) const
+{
+  int absb = b < 0 ? -b : b;
+  int per = (a < absb ? absb : a);
+  int pos = a * pix.x () + b * pix.y () - c;
+  if (pos < 0) return ((pos + 1 - per) / per);
+  else if (pos >= nu) return ((pos + per - nu) / per);
+  else return 0;
+}
+
+
+Pt2i DigitalStraightLine::getABoundingPoint (bool upper) const
+{
+  int sa = a, sb = b, u1 = 1, v1 = 0, u2 = 0, v2 = 1;
+  while (sb != 0)
+  {
+    int r = sa % sb;
+    int q = sa / sb;
+    int u3 = u1 - q * u2;
+    int v3 = v1 - q * v2;
+    u1 = u2;
+    v1 = v2;
+    u2 = u3;
+    v2 = v3;
+    sa = sb;
+    sb = r;
+  }
+  if (sa < 0)  // should be 1 or -1 if a and b are primal
+  {
+    u1 = - u1;
+    v1 = - v1;
+  }
+  return (upper ? Pt2i (u1 * (c + nu - 1), v1 * (c + nu - 1))
+                : Pt2i (u1 * c, v1 * c));
+}
+
+
+void DigitalStraightLine::adjustWorkArea (int &xmin, int &ymin,
+                                          int &width, int &height) const
+{
+  (void) xmin;
+  (void) ymin;
+  (void) width;
+  (void) height;
+}
+
+
+void DigitalStraightLine::getBounds (std::vector<Pt2i> &bound,
+                             int xmin, int ymin, int width, int height) const
+{
+  getBoundPoints (bound, false, xmin, ymin, width, height);
+  if (nu > period ()) getBoundPoints (bound, true, xmin, ymin, width, height);
+}
+
+
+void DigitalStraightLine::getBoundPoints (std::vector<Pt2i> &points,
+            bool opposite, int xmin, int ymin, int width, int height) const
+{
+  if (opposite && nu < period ()) return;
+
+  int x, y, dec, r;
+  Pt2i pb = getABoundingPoint (opposite);
+  adjustWorkArea (xmin, ymin, width, height);
+
+  if (b > 0)   // downwards
+    if (b >= a) // rather horizontal (8th octant)
+    {
+      x = pb.x ();
+      y = pb.y ();
+      dec = x <= xmin ? (xmin - x) / b : (xmin - x) / b - 1;
+      x += dec * b;
+      y -= dec * a;
+      r = (opposite ? b - 1 : 0);
+
+      while (x < xmin)
+      {
+        x++;
+        r += a; if (r >= b)
+        {
+          y --;
+          r -= b;
+        }
+      }
+      if ((opposite || r < nu ) && y >= ymin && y < ymin + height)
+        points.push_back (Pt2i (x, y));
+      while (++x < xmin + width)
+      {
+        r += a;
+        if (r >= b)
+        {
+          y --;
+          r -= b;
+        }
+        if ((opposite || r < nu) && y >= ymin && y < ymin + height)
+          points.push_back (Pt2i (x, y));
+      }
+    }
+    else // rather vertical (7th octant)
+    {
+      x = pb.x ();
+      y = pb.y ();
+      dec = y >= ymin + height ? (y - ymin - height) / a
+                                 : (y - ymin - height) / a - 1;
+      x += dec * b;
+      y -= dec * a;
+      r = (opposite ? 0 : a - 1);
+
+      while (y >= ymin + height)
+      {
+        y--;
+        r += b;
+        if (r >= a)
+        {
+          x ++;
+          r -= a;
+        }
+      }
+
+      if ((opposite || r >= a - nu) && x >= xmin && x < xmin + width)
+        points.push_back (Pt2i (x, y));
+      while (y-- > ymin)
+      {
+        r += b;
+        if (r >= a)
+        {
+          x ++;
+          r -= a;
+        }
+        if ((opposite || r >= a - nu) && x >= xmin && x < xmin + width)
+          points.push_back (Pt2i (x, y));
+      }
+    }
+  else   // upwards
+    if (-b >= a) // rather horizontal (1st octant)
+    {
+      x = pb.x ();
+      y = pb.y ();
+      dec = x <= xmin ? (x - xmin) / b : (x - xmin) / b - 1;
+      x -= dec * b;
+      y += dec * a;
+      r = (opposite ? b + 1 : 0);
+
+      while (x < xmin)
+      {
+        x++;
+        r -= a;
+        if (r <= b)
+        {
+          y ++;
+          r -= b;
+        }
+      }
+
+      if ((opposite || r > -nu) && y >= ymin && y < ymin + height)
+        points.push_back (Pt2i (x, y));
+      while (++x < xmin + width)
+      {
+        r -= a;
+        if (r <= b)
+        {
+          y ++;
+          r -= b;
+        }
+        if ((opposite || r > -nu) && y >= ymin && y < ymin + height)
+          points.push_back (Pt2i (x, y));
+      }
+    }
+    else // rather vertical (2nd octant)
+    {
+      x = pb.x ();
+      y = pb.y ();
+      dec = y > ymin ? (ymin - y) / a - 1 : (ymin - y) / a;
+      x -= dec * b;
+      y += dec * a;
+      r = (opposite ? 0 : a - 1);
+
+      while (y < ymin)
+      {
+        y++;
+        r -= b;
+        if (r >= a)
+        {
+          x ++;
+          r -= a;
+        }
+      }
+
+      if ((opposite || r >= a - nu) && x >= xmin && x < xmin + width)
+        points.push_back (Pt2i (x, y));
+      while (++y < ymin + height)
+      {
+        r -= b;
+        if (r >= a)
+        {
+          x ++;
+          r -= a;
+        }
+        if ((opposite || r >= a - nu) && x >= xmin && x < xmin + width)
+          points.push_back (Pt2i (x, y));
+      }
+    }
+}
+
+
+const Pt2i DigitalStraightLine::centerOfIntersection (
+                                     DigitalStraightLine *l) const
+{
+  int den = a * l->b - b * l->a;
+  if (den == 0) return (Pt2i (0, 0));
+  return (Pt2i (
+    ((c + nu / 2) * l->b - b * (l->c + l->nu / 2) + den / 2) / den,
+    (a * (l->c + l->nu / 2) - (c + nu / 2) * l->a + den / 2) / den));
+}
+
+
+const Pt2i DigitalStraightLine::centerOfIntersection (
+                                     Pt2i p1, Pt2i p2) const
+{
+  int sa = p2.y () - p1.y ();
+  int sb = p1.x () - p2.x ();
+  if (sa == 0)
+  {
+    if (sb == 0) return (Pt2i (0, 0));
+    if (sb < 0) sb = -sb;
+  }
+  if (sa < 0)
+  {
+    sa = -sa;
+    sb = -sb;
+  }
+  int pg = pgcd (sa, sb < 0 ? -sb : sb);
+  sa /= pg;
+  sb /= pg;
+
+  int den = a * sb - b * sa;
+  if (den == 0) return (Pt2i (0, 0));
+  int sc = sa * p1.x () + sb * p1.y ();
+  return (Pt2i (((c + nu / 2) * sb - b * sc + den / 2) / den,
+                 (a * sc - (c + nu / 2) * sa + den / 2) / den));
+}
+
+
+bool DigitalStraightLine::owns (const Pt2i &p) const
+{
+  int val = a * p.x () + b * p.y () - c;
+  return (val >= 0 && val < nu);
+}
+
+
+bool DigitalStraightLine::owns (const Pt2i &p1, const Pt2i &p2) const
+{
+  int val1 = a * p1.x () + b * p1.y () - c;
+  int val2 = a * p2.x () + b * p2.y () - c;
+  return (val1 < val2 ? val1 <= 0 && val2 < nu
+                      : val2 <= 0 && val1 < nu);
+}
+
+
+bool DigitalStraightLine::crosses (const Pt2i &p1, const Pt2i &p2) const
+{
+  int val1 = a * p1.x () + b * p1.y () - c;
+  int val2 = a * p2.x () + b * p2.y () - c;
+  return (val1 < val2 ? val2 >= 0 && val1 < nu
+                      : val1 >= 0 && val2 < nu);
+}
+
+
+int DigitalStraightLine::pavingIndex (Pt2i pt) const
+{
+  int rmd = a * pt.x () + b * pt.y () - c;
+  if (a == 0) rmd = -rmd;
+  return (rmd < 0 ? (rmd + 1) / nu - 1 : rmd / nu);
+}
+
+
+int DigitalStraightLine::rmd (Pt2i pt) const
+{
+  return (a * pt.x () + b * pt.y () - c);
+}
+
+
+int DigitalStraightLine::pgcd (int a, int b)
+{
+  int r;
+  while (b != 0)
+  {
+    r = a % b;
+    a = b;
+    b = r;
+  }
+  return (a);
+}
diff --git a/Expes/Testers/TestLines/ImageTools/digitalstraightline.h b/Expes/Testers/TestLines/ImageTools/digitalstraightline.h
new file mode 100644
index 0000000..fb4da72
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/digitalstraightline.h
@@ -0,0 +1,255 @@
+#ifndef DIGITAL_STRAIGHT_LINE_H
+#define DIGITAL_STRAIGHT_LINE_H
+
+#include "pt2i.h"
+#include "edist.h"
+
+
+/** 
+ * @class DigitalStraightLine digitalstraightline.h
+ * \brief Digital straight line.
+ * The digital straightline is defined by equation : c <= ax + by < c + nu
+ *   where a >= 0, b > 0 if a = 0, and nu > 0.
+ */
+class DigitalStraightLine
+{
+public:
+
+  /** Digital line type : Thin line (width = 1). */
+  static const int DSL_THIN;
+  /** Digital line type : Naive line (width = max (|a|,|b|)). */
+  static const int DSL_NAIVE;
+  /** Digital line type : Standard line (width = |a|+|b|). */
+  static const int DSL_STANDARD;
+
+
+  /**
+   * \brief Creates a digital straightline from its equation parameters.
+   * @param a X value slope parameter of equation : c <= ax + by < c + nu
+   * @param b Y value slope parameter of equation : c <= ax + by < c + nu
+   * @param c Shift parameter of equation : c <= ax + by < c + nu
+   * @param nu Width parameter of equation : c <= ax + by < c + nu
+   */
+  DigitalStraightLine (int a, int b, int c, int nu);
+
+  /**
+   * \brief Creates a digital straight line centered on two points.
+   * @param p1 First leaning point.
+   * @param p2 Second leaning point.
+   * @param type Digital line type : DSL_THIN, DSL_NAIVE or DSL_STANDARD.
+   */
+  DigitalStraightLine (Pt2i p1, Pt2i p2, int type);
+
+  /**
+   * \brief Creates a digital straight line from an antipodal pair.
+   * @param p1 First segment end point of the antipodal pair.
+   * @param p1 Second segment end point of the antipodal pair.
+   * @param p3 Opposite point of the antipodal pair.
+   */
+  DigitalStraightLine (Pt2i p1, Pt2i p2, Pt2i p3);
+
+  /**
+   * \brief Creates a digital straight line from two points and side shift.
+   * It creates a parallel line to the line centered on given points,
+   *   with side shift.
+   * Unknown use, care the side correctness in case of.
+   * @param p1 First point.
+   * @param p2 Second point.
+   * @param type Digital line type : DSL_THIN, DSL_NAIVE or DSL_STANDARD
+   * @param atRight Rightwards orthogonal shift to p1p2 line.
+   */
+  DigitalStraightLine (Pt2i p1, Pt2i p2, int type, int atRight);
+
+  /**
+   * Creates a similar digital straight line to an other one.
+   * @param l The original line.
+   */
+  DigitalStraightLine (const DigitalStraightLine &l);
+
+  /**
+   * Deletes the digital straight line.
+   */
+  virtual ~DigitalStraightLine () { }
+
+  /**
+   * \brief Returns the parameters of the digital straight line equations.
+   * @param a X Slope parameter to provide.
+   * @param b Y Slope parameter to provide.
+   * @param c Shift parameter to provide.
+   * @param nu Width parameter to provide.
+   */
+  inline void equation (int &a, int &b, int &c, int &nu) const {
+    a = this->a; b = this->b; c = this->c; nu = this->nu; }
+
+  /**
+   * \brief Sets given values with the three central naive line parameters.
+   * @param a X Slope parameter to provide.
+   * @param b Y Slope parameter to provide.
+   * @param c0 Shift parameter of the central naive line.
+   */
+  inline void getCentralLine (int &a, int &b, int &c0) const {
+    a = this->a; b = this->b; c0 = c + nu / 2; }
+
+  /**
+   * \brief Returns the period of the digital straight line : max (|a|,|b|).
+   */
+  inline int period () const {
+    int absb = b < 0 ? -b : b;
+    return (a < absb ? absb : a); }
+
+  /**
+   * \brief Returns the lower icoefficient of the digital straight line.
+   * Returns min (|a|,|b|).
+   */
+  inline int antiperiod () const {
+    int absb = b < 0 ? -b : b;
+    return (a < absb ? a : absb); }
+
+  /**
+   * \brief Returns the standard width : |a| + |b|.
+   */
+  inline int standard () const { return (a + (b < 0 ? -b : b)); }
+
+  /**
+   * \brief Returns the manhattan width of the digital straight line.
+   */
+  inline int width () const { return (nu); }
+
+  /**
+   * \brief Returns a support vector of the digital straight line.
+   */
+  inline Vr2i supportVector () const { return (Vr2i (-b, a)); }
+
+  /**
+   * \brief Returns the signed manhattan distance to the given point.
+   * Returns the distance to line bounds
+   * Right values are provided for points on the right side (yp > line (yp)).
+   */
+  int manhattan (Pt2i pix) const;
+
+  /**
+   * \brief Returns a bounding point of the digital straight line.
+   * @param upper Set to true for upper bounding point, to false for lower one.
+   */
+  virtual Pt2i getABoundingPoint (bool upper) const;
+
+  /**
+   * \brief Adds points of one of the bounding lines to given vector.
+   *   The bounding line is naive if (nu < period).
+   *   Restricts the points in the specified area.
+   * @param bound Vector of points to complete.
+   * @param opposite True to get the opposite bounding line (ax+by=c+nu-1).
+   * @param xmin Left border of the viewport.
+   * @param ymin Bottom border of the viewport.
+   * @param width Width of the viewport.
+   * @param height Height of the viewport.
+   */
+  void getBoundPoints (std::vector<Pt2i> &bound, bool opposite,
+                       int xmin, int ymin, int width, int height) const;
+
+  /**
+   * \brief Adds points of both bounding lines to given vector.
+   * @param bound Vector of points to complete.
+   * @param xmin Left border of the viewport.
+   * @param ymin Bootom border of the viewport.
+   * @param width Width of the viewport.
+   * @param height Height of the viewport.
+   */
+  void getBounds (std::vector<Pt2i> &bound,
+                  int xmin, int ymin, int width, int height) const;
+
+  /**
+   * \brief Checks if given point belongs to the digital line.
+   * @param p Given point.
+   */
+  bool owns (const Pt2i &p) const;
+
+  /**
+   * \brief Checks if given segment entirely belongs to the digital line.
+   * @param p1 Given segment start point.
+   * @param p2 Given segment end point.
+   */
+  bool owns (const Pt2i &p1, const Pt2i &p2) const;
+
+  /**
+   * \brief Checks if given segment belongs even partially to the digital line.
+   * @param p1 Given segment start point.
+   * @param p2 Given segment end point.
+   */
+  bool crosses (const Pt2i &p1, const Pt2i &p2) const;
+
+  /**
+   * \brief Returns the center of the intersection with another digital line.
+   * @param l The other digital line.
+   */
+  const Pt2i centerOfIntersection (DigitalStraightLine *l) const;
+
+  /**
+   * \brief Returns the center of the intersection with line P1-P2.
+   *   Care : returns (0,0) if p1 == p2 or if P1P2 is parallel to the line.
+   * @param p1 Start point of the crossed line.
+   * @param p2 End point of the crossed line.
+   */
+  const Pt2i centerOfIntersection (Pt2i p1, Pt2i p2) const;
+
+  /**
+   * \brief Returns the squared Euclidean thickness of the digital line.
+   */
+  const EDist squaredEuclideanThickness () const {
+    return (EDist (nu * nu, a * a + b * b)); }
+
+  /**
+   * \brief Returns the plane paving index of given point.
+   *    Plane paving index is the index of the line containing the point
+   * when paving the Euclidean plane by the digital straight line.
+   * @param pt Given point.
+   */
+  int pavingIndex (Pt2i pt) const;
+  int rmd (Pt2i pt) const;
+
+
+
+protected:
+
+  /**
+   * \brief X value of the slope parameter in equation : c <= ax + by < c + nu.
+   *  a is greater or equal to 0.
+   */
+  int a;
+
+  /**
+   * \brief Y value of the slope parameter in equation : c <= ax + by < c + nu.
+   * b is a positive value when the line is horizontal (a = 0).
+   */
+  int b;
+
+  /**
+   * \brief Shift parameter in equation : c <= ax + by < c + nu.
+   */
+  int c;
+
+  /**
+   * \brief Width parameter in equation : c <= ax + by < c + nu.
+   * nu is a positive value.
+   */
+  int nu;
+
+
+  /**
+   * \brief Adjusts the provided area on the straight line limits.
+   * @param xmin Left coordinate of the area.
+   * @param ymin Bottom coordinate of the area.
+   * @param width Width of the area.
+   * @param height Height of the area.
+   */
+  virtual void adjustWorkArea (int &xmin, int &ymin,
+                               int &width, int &height) const;
+
+  /**
+   * \brief Returns the greater common divisor between two integer values.
+   * @param a First integer.
+   * @param b Second integer.
+   */
+  static int pgcd (int a, int b);
+};
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.cpp b/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.cpp
new file mode 100644
index 0000000..c2b509f
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.cpp
@@ -0,0 +1,277 @@
+#include "digitalstraightsegment.h"
+
+
+DigitalStraightSegment::DigitalStraightSegment ()
+                      : DigitalStraightLine (1, 1, 0, 1)
+{
+  min = 0;
+  max = 1;
+}
+
+
+DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, int type,
+                                 int xmin, int ymin, int xmax, int ymax)
+                      : DigitalStraightLine (p1, p2, type)
+{
+  if (a < (b < 0 ? -b : b))
+  {
+    min = xmin;
+    max = xmax;
+  }
+  else
+  {
+    min = ymin;
+    max = ymax;
+  }
+}
+
+
+DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, Pt2i p3,
+                                 int xmin, int ymin, int xmax, int ymax)
+                      : DigitalStraightLine (p1, p2, p3)
+{
+  if (a < (b < 0 ? -b : b))
+  {
+    min = xmin;
+    max = xmax;
+  }
+  else
+  {
+    min = ymin;
+    max = ymax;
+  }
+}
+
+
+DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, int width)
+                      : DigitalStraightLine (p1, p2, DSL_THIN)
+{
+  nu = width * period ();
+  c = a * p1.x () + b * p1.y () - nu / 2;
+  if (a < (b < 0 ? -b : b))
+  {
+    min = (p1.x () < p2.x () ? p1.x () : p2.x ());
+    max = (p1.x () < p2.x () ? p2.x () : p1.x ());
+  }
+  else
+  {
+    min = (p1.y () < p2.y () ? p1.y () : p2.y ());
+    max = (p1.y () < p2.y () ? p2.y () : p1.y ());
+  }
+}
+
+
+DigitalStraightSegment::DigitalStraightSegment (int va, int vb, int vc,
+                                                int vnu, int vmin, int vmax)
+                      : DigitalStraightLine (va, vb, vc, vnu)
+{
+  min = vmin;
+  max = vmax;
+}
+
+
+DigitalStraightSegment::DigitalStraightSegment (DigitalStraightSegment *dss)
+                      : DigitalStraightLine (dss->a, dss->b, dss->c, dss->nu)
+{
+  min = dss->min;
+  max = dss->max;
+}
+
+
+Pt2i DigitalStraightSegment::getABoundingPoint (bool upper) const
+{
+  int sa = a, sb = b, u1 = 1, v1 = 0, u2 = 0, v2 = 1;
+  while (sb != 0)
+  {
+    int r = sa % sb;
+    int q = sa / sb;
+    int u3 = u1 - q * u2;
+    int v3 = v1 - q * v2;
+    u1 = u2;
+    v1 = v2;
+    u2 = u3;
+    v2 = v3;
+    sa = sb;
+    sb = r;
+  }
+  if (sa < 0)  // should be 1 or -1 if a and b are primal
+  {
+    u1 = - u1;   // necessary if sa = -1
+    v1 = - v1;
+  }
+  Pt2i extr (upper ? Pt2i (u1 * (c + nu - 1), v1 * (c + nu - 1))
+                   : Pt2i (u1 * c, v1 * c));
+  
+  int dec = 0;
+  int bb = (b < 0 ? -b : b);
+  if (a < bb)
+  {
+    if (extr.x () > max)
+      dec = 1 + (extr.x () - max) / bb;
+    else if (extr.x () < min)
+      dec = -1 - (min - extr.x ()) / bb;
+    if (b < 0) dec = -dec;
+  }
+  else
+  {
+    if (extr.y () > max)
+      dec = -1 - (extr.y () - max) / a;
+    else if (extr.y () < min)
+      dec = 1 + (min - extr.y ()) / a;
+  }
+  extr.set (extr.x () - dec * b, extr.y () + dec * a);
+  return extr;
+}
+
+
+void DigitalStraightSegment::adjustWorkArea (int &xmin, int &ymin,
+                                             int &width, int &height) const
+{
+  if (b > a || -b > a)
+  {
+    if (xmin < min) xmin = min;
+    // Caution, segment max limit is excluded
+    int x2 = (xmin + width < max + 1 ? xmin + width : max + 1);
+    width = (xmin >= x2 ? 0 : x2 - xmin);
+  }
+  else
+  {
+    if (ymin < min) ymin = min;
+    // Cochon, segment max limit is excluded
+    int y2 = (ymin + height < max + 1 ? ymin + height : max + 1);
+    height = (ymin >= y2 ? 0 : y2 - ymin);
+  }
+}
+
+
+void DigitalStraightSegment::getPoints (std::vector<Pt2i> &pts) const
+{
+  int xmin, ymin, w, h;
+  if (b > a || -b > a)
+  {
+    xmin = min;
+    w = max - min;
+    ymin = (b < 0 ? (c + nu - a * min) / b - 1 : (c - a * max) / b - 1);
+    h = (b < 0 ? (c - a * max) / b + 1 : (c + nu - a * min) / b + 1) - ymin;
+  }
+  else
+  {
+    ymin = min;
+    h = max - min;
+    xmin = (b < 0 ? (c - b * min) / a - 1 : (c - b * max) / a - 1);
+    w = (b < 0 ? (c + nu - b * max) / a : (c + nu - b * min) / a) + 1 - xmin;
+  }
+  std::vector<Pt2i> lowbound;
+  getBoundPoints (lowbound, false, xmin, ymin, w, h);
+  std::vector<Pt2i>::iterator it = lowbound.begin ();
+
+  while (it != lowbound.end ())
+  {
+    Pt2i p = *it;
+    while (owns (p))
+    {
+      pts.push_back (p);
+      if (b > a) p.set (p.x (), p.y () + 1);
+      else if (-b > a) p.set (p.x (), p.y () - 1);
+      else p.set (p.x () + 1, p.y ());
+    }
+    it ++;
+  }
+}
+
+
+void DigitalStraightSegment::naiveLine (AbsRat &x1, AbsRat &y1,
+                                        AbsRat &x2, AbsRat &y2) const
+{
+  if (a < (b < 0 ? -b : b))
+  {
+    x1.set (min);
+    y1.set (2 * c + nu - 1 - 2 * a * min, 2 * b);
+    x2.set (max);
+    y2.set (2 * c + nu - 1 - 2 * a * max, 2 * b);
+  }
+  else
+  {
+    y1.set (min);
+    x1.set (2 * c + nu - 1 - 2 * b * min, 2 * a);
+    y2.set (max);
+    x2.set (2 * c + nu - 1 - 2 * b * max, 2 * a);
+  }
+}
+
+
+DigitalStraightSegment *DigitalStraightSegment::erosion (int num, int den) const
+{
+  int newwidth = nu;
+  if (nu > period ())
+  {
+    newwidth = nu - (num * period ()) / den;
+    if (newwidth < period ()) newwidth = period ();
+  }
+  return (new DigitalStraightSegment (a, b, c + (nu - newwidth) / 2,
+                                      newwidth, min, max));
+}
+
+
+DigitalStraightSegment *DigitalStraightSegment::dilation (
+                                                   int num, int den) const
+{
+  int newwidth = nu + (num * period ()) / den;
+  return (new DigitalStraightSegment (a, b, c + (nu - newwidth) / 2,
+                                      newwidth, min, max));
+}
+
+
+DigitalStraightSegment *DigitalStraightSegment::dilation (int ar_width) const
+{
+  return (new DigitalStraightSegment (a, b, c - ar_width,
+                                      nu + 2 * ar_width, min, max));
+}
+
+
+void DigitalStraightSegment::dilate (int ar_width)
+{
+  nu += 2 * ar_width;
+  c -= ar_width;
+}
+
+
+void DigitalStraightSegment::setNaive ()
+{
+  int p = period ();
+  c += (nu - p) / 2;
+  nu = p;
+}
+
+
+bool DigitalStraightSegment::contains (Pt2i p, int tol) const
+{
+  int pos = a * p.x () + b * p.y ();
+  tol *= period ();
+  if (pos < c - tol || pos >= c + nu + tol) return (false);
+  if (a < (b < 0 ? -b : b))
+    return (p.x () >= min && p.x () <= max);
+  else
+    return (p.y () >= min && p.y () <= max);
+}
+
+
+int DigitalStraightSegment::length2 () const
+{
+  int numin, numax, den;
+  if (a < (b < 0 ? -b : b))
+  {
+    numin = c - a * min;
+    numax = c - a * max;
+    den = b;
+  }
+  else
+  {
+    numin = c - b * min;
+    numax = c - b * max;
+    den = a;
+  }
+  return ((int) (((max - min) * (max - min) * den * den
+                  + (numax - numin) * (numax - numin)
+                  + (den * den) / 2) / (den * den)));
+}
diff --git a/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.h b/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.h
new file mode 100644
index 0000000..891b6a2
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/digitalstraightsegment.h
@@ -0,0 +1,181 @@
+#ifndef DIGITAL_STRAIGHT_SEGMENT_H
+#define DIGITAL_STRAIGHT_SEGMENT_H
+
+#include "digitalstraightline.h"
+#include "absrat.h"
+
+
+/** 
+ * @class DigitalStraightSegment digitalstraightsegment.h
+ * \brief Digital straight segment is a bounded digital straight line.
+ * The digital straightline is defined by equation : c <= ax + by < c + nu
+ *   where a >= 0 and nu > 0. Seemingly b is unconstrained when a = 0.
+ * The bounds are horizontal lines (min <= y <= max) if the segment is vertical,
+ *   vertical lines (min <= x <= max) if the segment is horizontal.
+ * The bound points belong to the digital straight segment.
+ */
+class DigitalStraightSegment : public DigitalStraightLine
+{
+public:
+
+  /**
+   * \brief Creates a default digital straight segment.
+   */
+  DigitalStraightSegment ();
+
+  /**
+   * \brief Creates a null-thick segment passing through two points.
+   * Caution: the segment ends on given min-max bounds !
+   * To create a segment ending on the two points, use constructor with
+   * two points and width instead.
+   * @param p1 First point on the line.
+   * @param p2 Second point on the line.
+   * @param type Digital line type : DSL_THIN, DSL_NAIVE or DSL_STANDARD.
+   * @param xmin Segment min X-coordinate.
+   * @param ymin Segment min Y-coordinate.
+   * @param xmax Segment max X-coordinate.
+   * @param ymax Segment max Y-coordinate.
+   */
+  DigitalStraightSegment (Pt2i p1, Pt2i p2, int type,
+                          int xmin, int ymin, int xmax, int ymax);
+
+  /**
+   * \brief Creates a digital straight segment from an antipodal pair.
+   * @param p1 First segment end of the antipodal pair.
+   * @param p1 Second segment end of the antipodal pair.
+   * @param p3 Opposite point of the antipodal pair.
+   * @param xmin Segment min X coordinate.
+   * @param ymin Segment min Y coordinate.
+   * @param xmax Segment max X coordinate.
+   * @param ymax Segment max Y coordinate.
+   */
+  DigitalStraightSegment (Pt2i p1, Pt2i p2, Pt2i p3,
+                          int xmin, int ymin, int xmax, int ymax);
+
+  /**
+   * \brief Creates a digital straight segment from end points and width.
+   * @param p1 First end point of the segment.
+   * @param p2 Second end point of the segment.
+   * @param width Width value: 1 for a naive line.
+   */
+  DigitalStraightSegment (Pt2i p1, Pt2i p2, int width);
+
+  /**
+   * \brief Sets identical to given digital straight segment.
+   * @param dss Original straight segment.
+   */
+  inline void set (const DigitalStraightSegment &dss) {
+    a = dss.a; b = dss.b; c = dss.c; nu = dss.nu;
+    min = dss.min; max = dss.max; }
+
+  /**
+   * \brief Creates a digital straight segment from another one.
+   * @param dss Pointer to the digital straight segment to copy.
+   */
+  DigitalStraightSegment (DigitalStraightSegment *dss);
+
+  /**
+   * \brief Returns a bounding point of the digital line.
+   * @param upper True for an upper bounding point, false for a lower one.
+   */
+  Pt2i getABoundingPoint (bool upper) const;
+
+  /**
+   * \brief Adds segment points to the provided vector.
+   * @param pts Vector of points to complete.
+   */
+  void getPoints (std::vector<Pt2i> &pts) const;
+
+  /**
+   * \brief Provides the naive central segment end points coordinates.
+   * @param x1 Start point X-coordinate to set.
+   * @param x2 Start point Y-coordinate to set.
+   * @param x2 End point X-coordinate to set.
+   * @param y2 End point Y-coordinate to set.
+   */
+  void naiveLine (AbsRat &x1, AbsRat &y1, AbsRat &x2, AbsRat &y2) const;
+
+  /**
+   * \brief Returns an erosion of the segment.
+   * @param num Erosion value numerator.
+   * @param den Erosion value denominator.
+   */
+  DigitalStraightSegment *erosion (int num, int den) const;
+
+  /**
+   * \brief Returns a dilation of the segment.
+   * @param num Dilation value numerator.
+   * @param den Dilation value denominator.
+   */
+  DigitalStraightSegment *dilation (int num, int den) const;
+
+  /**
+   * \brief Returns a dilated segment of given arithmetical width on each side.
+   * @param radius Dilation arithmetical width.
+   */
+  DigitalStraightSegment *dilation (int ar_width) const;
+
+  /**
+   * \brief Dilates the segment of given arithmetical width on each side.
+   * @param radius Dilation arithmetical width.
+   */
+  void dilate (int ar_width);
+
+  /**
+   * \brief Erodes the segment to its naive center line.
+   */
+  void setNaive ();
+
+  /**
+   * \brief Inquires if given point belongs to a dilation of the segment.
+   * @param p Tested point.
+   * @param tol Dilation value (some tolerence).
+   */
+  bool contains (Pt2i p, int tol) const;
+
+  /**
+   * \brief Returns the squared length of the digital straight segment.
+   */
+  int length2 () const;
+
+
+protected:
+
+  /**
+   * \brief Bounding line lower coordinate.
+   * If the segment is stictly horizontal, it enforces x >= xmin.
+   * If the segment is vertical or diagonal, it enforces y >= ymin.
+   * The bound belongs to the segment.
+   */
+  int min;
+  /**
+   * \brief Bounding line upper coordinate.
+   * If the segment is stictly horizontal, it enforces x <= xmax.
+   * If the segment is vertical or diagonal, it enforces y <= ymax.
+   * The bound belongs to the segment.
+   */
+  int max;
+
+
+  /**
+   * \brief Creates a segment from parameter values.
+   * @param va Slope X coordinate.
+   * @param vb Slope Y coordinate.
+   * @param vc Shift to origin.
+   * @param vnu Arithmetical width.
+   * @param vmin Bounding line lower coordinate.
+   * @param vmax Bounding line upper coordinate.
+   */
+  DigitalStraightSegment (int va, int vb, int vc, int vnu, int vmin, int vmax);
+
+  /**
+   * \brief Sets the provided area on the segment limits.
+   * @param xmin Left border of the area to set.
+   * @param ymin Bottom border of the area to set.
+   * @param width Width of the area to set.
+   * @param height Height of the area to set.
+   */
+  void adjustWorkArea (int &xmin, int &ymin, int &width, int &height) const;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/edist.cpp b/Expes/Testers/TestLines/ImageTools/edist.cpp
new file mode 100644
index 0000000..eecca11
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/edist.cpp
@@ -0,0 +1,22 @@
+#include "edist.h"
+
+
+EDist::EDist ()
+{
+  d_num = 0;
+  d_den = 1;
+}
+
+
+EDist::EDist (int numerator, int denominator)
+{
+  d_num = (numerator < 0 ? - numerator : numerator);
+  d_den = (denominator < 0 ? - denominator : denominator);
+}
+
+
+EDist::EDist (const EDist &dist)
+{
+  d_num = dist.d_num;
+  d_den = dist.d_den;
+}
diff --git a/Expes/Testers/TestLines/ImageTools/edist.h b/Expes/Testers/TestLines/ImageTools/edist.h
new file mode 100644
index 0000000..633c576
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/edist.h
@@ -0,0 +1,154 @@
+#ifndef EUCLIDEAN_DISTANCE_H
+#define EUCLIDEAN_DISTANCE_H
+
+#include <inttypes.h>
+
+
+/** 
+ * @class EDist edist.h
+ * \brief Euclidean distance rational value.
+ * 
+ * Caution: this absolute rational number may have a null denominator.
+ * It should not be evaluated.
+ * It is mostly intended to comparison operations.
+ */
+class EDist
+{
+public:
+
+  /**
+   * \brief Creates a Euclidean distance with null value.
+   */
+  EDist ();
+
+  /**
+   * \brief Creates a Euclidean distance from numerator and denominator.
+   *   Forces numerator and denominator to their absolute value.
+   * @param numerator Numerator value.
+   * @param denominator Denominator value.
+   */
+  EDist (int numerator, int denominator);
+
+  /**
+   * \brief Creates a Euclidean distance from another one.
+   * @param dist The Euclidean distance to copy.
+   */
+  EDist (const EDist &dist);
+
+  /**
+   * \brief Deletes the Euclidean distance.
+   */
+  ~EDist () { }
+
+  /**
+   * \brief Returns the numerator of the Euclidean distance.
+   */
+  //inline int numerator () const { return d_num; }
+
+  /**
+   * \brief Returns the denominator of the Euclidean distance.
+   */
+  //inline int denominator () const { return d_den; }
+
+  /**
+   * \brief Returns the numerator of the Euclidean distance.
+   */
+  inline int num () const { return d_num; }
+
+  /**
+   * \brief Returns the denominator of the Euclidean distance.
+   */
+  inline int den () const { return d_den; }
+
+  /**
+   * \brief Returns the nearest smaller integer value.
+   */
+  inline int floor () const { return (d_num / d_den); }
+
+  /**
+   * \brief Sets a new value from another Euclidean distance.
+   * @value dist Other Euclidean distance.
+   */
+  inline void set (const EDist &dist) {
+    d_num = dist.d_num; d_den = dist.d_den; }
+
+  /**
+   * \brief Sets a new integer value.
+   * @value val Integer value.
+   */
+  inline void set (int val) { d_num = val; d_den = 1; }
+
+  /**
+   * \brief Sets a new value from a numerator and a denominator.
+   * @value numerator New numerator value.
+   * @value denominator New denominator value.
+   */
+  inline void set (int numerator, int denominator) {
+    d_num = numerator; d_den = denominator; }
+
+  /**
+   * \brief Checks equivalence to another Euclidean distance.
+   * @param dist Other Euclidean distance.
+   */
+  inline bool equals (const EDist &dist) const {
+    return (d_num * (int64_t) (dist.d_den) == d_den * (int64_t) (dist.d_num)); }
+
+  /**
+   * \brief Checks if the distance is strictly inferior to another one.
+   * @param dist Other Euclidean distance.
+   */
+  inline bool lessThan (const EDist &dist) const {
+    return (d_num * (int64_t) (dist.d_den) < d_den * (int64_t) (dist.d_num)); }
+
+  /**
+   * \brief Checks if the distance is inferior or equal to another one.
+   * @param dist Other Euclidean distance.
+   */
+  inline bool lessEqThan (const EDist &dist) const {
+    return (d_num * (int64_t) (dist.d_den) <= d_den * (int64_t) (dist.d_num)); }
+
+  /**
+   * \brief Checks if the distance is strictly superior to another one.
+   * @param dist Other Euclidean distance.
+   */
+  inline bool greaterThan (const EDist &dist) const {
+    return (d_num * (int64_t) (dist.d_den) > d_den * (int64_t) (dist.d_num)); }
+
+  /**
+   * \brief Checks if the distance is superior or equal to another one.
+   * @param dist Other Euclidean distance.
+   */
+  inline bool greaterEqThan (const EDist &dist) const {
+    return (d_num * (int64_t) (dist.d_den) >= d_den * (int64_t) (dist.d_num)); }
+
+  /**
+   * \brief Multiplies the Euclidean distance by another one.
+   * @param dist Other Euclidean distance.
+   */
+  inline void mult (const EDist &dist) {
+    d_num *= dist.d_num; d_den *= dist.d_den; }
+
+  /**
+   * \brief Returns the sum of the Euclidean distance and a integer length.
+   * @param length integer length.
+   */
+  inline EDist sum (int length) const {
+    return (EDist (d_num + length * d_den, d_den)); }
+
+  /**
+   * \brief Returns the sum of the Euclidean distance and 1/2.
+   */
+  inline EDist sumWithOneHalf () const {
+    return (d_den % 2 == 1 ? EDist (2 * d_num + d_den, 2 * d_den)
+                           : EDist (d_num + d_den / 2, d_den)); }
+
+
+protected:
+
+  /** Positive numerator of the Euclidean distance. */
+  int d_num;
+  /** Positive denominator of the Euclidean distance (might be null). */
+  int d_den;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/pt2i.cpp b/Expes/Testers/TestLines/ImageTools/pt2i.cpp
new file mode 100644
index 0000000..a9b63fe
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/pt2i.cpp
@@ -0,0 +1,832 @@
+#include "pt2i.h"
+
+
+Pt2i::Pt2i ()
+{
+  xp = 0;
+  yp = 0;
+}
+
+
+Pt2i::Pt2i (int x, int y)
+{
+  xp = x;
+  yp = y;
+}
+
+
+Pt2i::Pt2i (const Pt2i &p)
+{
+  xp = p.xp;
+  yp = p.yp;
+}
+
+
+bool Pt2i::inTriangle (Pt2i p1, Pt2i p2, Pt2i p3) const
+{
+  int x1 = p1.xp, y1 = p1.yp;
+  int x2 = p2.xp, y2 = p2.yp;
+  int x3 = p3.xp, y3 = p3.yp;
+
+  // Checks bounding rectangle
+  int xmin = x1, ymin = y1, xmax = x1, ymax = y1;
+  if (x2 < xmin) xmin = x2;
+  if (x3 < xmin) xmin = x3;
+  if (xp < xmin) return false;
+  if (x2 > xmax) xmax = x2;
+  if (x3 > xmax) xmax = x3;
+  if (xp > xmax) return false;
+  if (y2 < ymin) ymin = y2;
+  if (y3 < ymin) ymin = y3;
+  if (yp < ymin) return false;
+  if (y2 > ymax) ymax = y2;
+  if (y3 > ymax) ymax = y3;
+  if (yp > ymax) return false;
+
+  // Case of aligned triangle vertices
+  if ((x2 - x1) * (y3 - y1) == (x3 - x1) * (y2 - y1))
+    return ((x2 - x1) * (yp - y1) == (xp - x1) * (y2 - y1));
+
+  // Checks orientation to triangle edges
+  int pv1 = (xp - x1) * (y2 - y1) - (yp - y1) * (x2 - x1);
+  int pv2 = (xp - x2) * (y3 - y2) - (yp - y2) * (x3 - x2);
+  int pv3 = (xp - x3) * (y1 - y3) - (yp - y3) * (x1 - x3);
+  return ((pv1 >= 0 && pv2 >= 0 && pv3 >= 0)
+          || (pv1 <= 0 && pv2 <= 0 && pv3 <= 0));
+}
+
+
+Vr2i Pt2i::vectorTo (Pt2i p) const
+{
+  return (Vr2i (p.xp - xp, p.yp - yp));
+}
+
+
+Pt2i *Pt2i::drawing (const Pt2i p, int *n) const
+{
+  int x1, y1, x2, y2;
+  if (xp > p.xp)
+  {
+    x1 = p.xp;
+    x2 = xp;
+    y1 = p.yp;
+    y2 = yp;
+  }
+  else
+  {
+    x1 = xp;
+    x2 = p.xp;
+    y1 = yp;
+    y2 = p.yp;
+  }
+  int dx = x2 - x1;
+  int dy = y2 - y1;
+  int e, i = 0;
+  Pt2i *pts;
+
+  if (dy > 0)
+  {
+    // Octant 1
+    if (dx >= dy)
+    {
+      *n = dx + 1;
+      pts = new Pt2i[dx + 1];
+      e = dx - 1; // middle point lies below the line
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        pts[i++].set (x1, y1);
+        x1 ++;
+        e -= dy;
+        if (e < 0)
+        {
+          y1 ++;
+          e += dx;
+        }
+      }
+      pts[i].set (x1, y1);
+    }
+
+    // Octant 2
+    else
+    {
+      *n = dy + 1;
+      pts = new Pt2i[dy + 1];
+      e = dy; // middle point lies to the right of the line
+      dx *= 2;
+      dy *= 2;
+      while (y1 < y2)
+      {
+        pts[i++].set (x1, y1);
+        y1 ++;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e += dy;
+        }
+      }
+      pts[i].set (x1, y1);
+    }
+  }
+
+  else
+  {
+    // Octant 8
+    if (dx >= -dy)
+    {
+      *n = 1 + dx;
+      pts = new Pt2i[dx + 1];
+      e = dx - 1; // middle point lies below the line
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        pts[i++].set (x1, y1);
+        x1 ++;
+        e += dy;
+        if (e < 0)
+        {
+          y1 --;
+          e += dx;
+        }
+      }
+      pts[i].set (x1, y1);
+    }
+
+    // Octant 7
+    else
+    {
+      *n = 1 - dy;
+      pts = new Pt2i[1 - dy];
+      e = - dy; // middle point lies to the left of the line
+      dx *= 2;
+      dy *= 2;
+      while (y1 > y2)
+      {
+        pts[i++].set (x1, y1);
+        y1 --;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e -= dy;
+        }
+      }
+      pts[i].set (x1, y1);
+    }
+  }
+  return (pts);
+}
+
+
+Pt2i *Pt2i::clipLine (const Pt2i p, int left, int low, int right, int up,
+                      int *n) const
+{
+  if (right < left) { int tmp = left; left = right; right = tmp; }
+  if (up < low) { int tmp = low; low = up; up = tmp; }
+  int x1, y1, x2, y2;
+  if (xp > p.xp)
+  {
+    x1 = p.xp;
+    x2 = xp;
+    y1 = p.yp;
+    y2 = yp;
+  }
+  else
+  {
+    x1 = xp;
+    x2 = p.xp;
+    y1 = yp;
+    y2 = p.yp;
+  }
+  int dx = x2 - x1;
+  int dy = y2 - y1;
+  int e, i = 0;
+  Pt2i *pts;
+
+  if (dy > 0)
+  {
+    // Octant 1
+    if (dx >= dy)
+    {
+      *n = dx + 1;
+      pts = new Pt2i[dx + 1];
+      if (x2 >= left && y2 >= low)
+      {
+        e = dx - 1; // middle point lies below the line
+        dx *= 2;
+        dy *= 2;
+        while (x1 < x2 && x1 <= right && y1 <= up)
+        {
+          if (x1 >= left && y1 >= low) pts[i++].set (x1, y1);
+          x1 ++;
+          e -= dy;
+          if (e < 0)
+          {
+            y1 ++;
+            e += dx;
+          }
+        }
+        if (x2 <= right && y2 <= up) pts[i++].set (x2, y2);
+      }
+    }
+
+    // Octant 2
+    else
+    {
+      *n = dy + 1;
+      pts = new Pt2i[dy + 1];
+      if (x2 >= left && y2 >= low)
+      {
+        e = dy; // middle point lies to the right of the line
+        dx *= 2;
+        dy *= 2;
+        while (y1 < y2 && x1 <= right && y1 <= up)
+        {
+          if (x1 >= left && y1 >= low) pts[i++].set (x1, y1);
+          y1 ++;
+          e -= dx;
+          if (e < 0)
+          {
+            x1 ++;
+            e += dy;
+          }
+        }
+        if (x2 <= right && y2 <= up) pts[i++].set (x2, y2);
+      }
+    }
+  }
+
+  else
+  {
+    // Octant 8
+    if (dx >= -dy)
+    {
+      *n = 1 + dx;
+      pts = new Pt2i[dx + 1];
+      if (x2 >= left && y2 <= up)
+      {
+        e = dx - 1; // middle point lies below the line
+        dx *= 2;
+        dy *= 2;
+        while (x1 < x2 && x1 <= right && y1 >= low)
+        {
+          if (x1 >= left && y1 <= up) pts[i++].set (x1, y1);
+          x1 ++;
+          e += dy;
+          if (e < 0)
+          {
+            y1 --;
+            e += dx;
+          }
+        }
+        if (x2 <= right && y2 >= low) pts[i++].set (x2, y2);
+      }
+    }
+
+    // Octant 7
+    else
+    {
+      *n = 1 - dy;
+      pts = new Pt2i[1 - dy];
+      if (x2 >= left && y2 <= up)
+      {
+        e = - dy; // middle point lies to the left of the line
+        dx *= 2;
+        dy *= 2;
+        while (y1 > y2 && x1 <= right && y1 >= low)
+        {
+          if (x1 >= left && y1 <= up) pts[i++].set (x1, y1);
+          y1 --;
+          e -= dx;
+          if (e < 0)
+          {
+            x1 ++;
+            e -= dy;
+          }
+        }
+        if (x2 <= right && y2 >= low) pts[i].set (x2, y2);
+      }
+    }
+  }
+  *n = i;
+  return (pts);
+}
+
+
+void Pt2i::draw (std::vector<Pt2i> &line, Pt2i p) const
+{
+  int x1, y1, x2, y2;
+  if (xp > p.xp)
+  {
+    x1 = p.xp;
+    x2 = xp;
+    y1 = p.yp;
+    y2 = yp;
+  }
+  else
+  {
+    x1 = xp;
+    x2 = p.xp;
+    y1 = yp;
+    y2 = p.yp;
+  }
+  int dx = x2 - x1;
+  int dy = y2 - y1;
+  int e;
+
+  if (dy > 0)
+  {
+    // Octant 1
+    if (dx >= dy)
+    {
+      e = dx - 1; // middle point lies below the line
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        line.push_back (Pt2i (x1, y1));
+        x1 ++;
+        e -= dy;
+        if (e < 0)
+        {
+          y1 ++;
+          e += dx;
+        }
+      }
+      line.push_back (Pt2i (x1, y1));
+    }
+
+    // Octant 2
+    else
+    {
+      e = dy; // middle point lies to the right of the line
+      dx *= 2;
+      dy *= 2;
+      while (y1 < y2)
+      {
+        line.push_back (Pt2i (x1, y1));
+        y1 ++;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e += dy;
+        }
+      }
+      line.push_back (Pt2i (x1, y1));
+    }
+  }
+
+  else
+  {
+    // Octant 8
+    if (dx >= -dy)
+    {
+      e = dx - 1; // middle point lies below the line
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        line.push_back (Pt2i (x1, y1));
+        x1 ++;
+        e += dy;
+        if (e < 0)
+        {
+          y1 --;
+          e += dx;
+        }
+      }
+      line.push_back (Pt2i (x1, y1));
+    }
+
+    // Octant 7
+    else
+    {
+      e = - dy; // middle point lies to the left of the line
+      dx *= 2;
+      dy *= 2;
+      while (y1 > y2)
+      {
+        line.push_back (Pt2i (x1, y1));
+        y1 --;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e -= dy;
+        }
+      }
+      line.push_back (Pt2i (x1, y1));
+    }
+  }
+}
+
+
+Pt2i *Pt2i::pathTo (Pt2i p, int *n) const
+{
+  int x1, y1, x2, y2, delta;
+  if (xp > p.xp)
+  {
+    x1 = p.xp;
+    x2 = xp;
+    y1 = p.yp;
+    y2 = yp;
+    delta = -1;
+  }
+  else
+  {
+    x1 = xp;
+    x2 = p.xp;
+    y1 = yp;
+    y2 = p.yp;
+    delta = 1;
+  }
+  int dx = x2 - x1;
+  int dy = y2 - y1;
+  int e, i = 0;
+  Pt2i *pts;
+
+  if (dy > 0)
+  {
+    // Octant 1
+    if (dx >= dy)
+    {
+      *n = dx;
+      pts = new Pt2i[dx];
+      e = dx - 1; // middle point lies below the line
+      if (delta < 0) e++; // ... above
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        x1 ++;
+        e -= dy;
+        if (e < 0)
+        {
+          y1 ++;
+          e += dx;
+          pts[i++].set (delta, delta);
+        }
+        else pts[i++].set (delta, 0);
+      }
+    }
+
+    // Octant 2
+    else
+    {
+      *n = dy;
+      pts = new Pt2i[dy];
+      e = dy; // middle point lies to the right of the line
+      if (delta < 0) e--; // ... to the left
+      dx *= 2;
+      dy *= 2;
+      while (y1 < y2)
+      {
+        y1 ++;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e += dy;
+          pts[i++].set (delta, delta);
+        }
+        else pts[i++].set (0, delta);
+      }
+    }
+  }
+
+  else
+  {
+    // Octant 8
+    if (dx >= -dy)
+    {
+      *n = dx;
+      pts = new Pt2i[dx];
+      e = dx - 1; // middle point lies below the line
+      if (delta < 0) e++; // ... above
+      dx *= 2;
+      dy *= 2;
+      while (x1 < x2)
+      {
+        x1 ++;
+        e += dy;
+        if (e < 0)
+        {
+          y1 --;
+          e += dx;
+          pts[i++].set (delta, -delta);
+        }
+        else pts[i++].set (delta, 0);
+      }
+    }
+    // Octant 7
+    else
+    {
+      *n = -dy;
+      pts = new Pt2i[-dy];
+      e = - dy; // middle point lies to the left of the line
+      if (delta < 0) e--; // ... to the right
+      dx *= 2;
+      dy *= 2;
+      while (y1 > y2)
+      {
+        y1 --;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e -= dy;
+          pts[i++].set (delta, -delta);
+        }
+        else pts[i++].set (0, -delta);
+      }
+    }
+  }
+  return (pts);
+}
+
+
+bool *Pt2i::stepsTo (Pt2i p, int *n) const
+{
+  bool negx = p.xp < xp;
+  bool negy = p.yp < yp;
+  int x2 = (xp > p.xp) ? xp - p.xp : p.xp - xp;
+  int y2 = (yp > p.yp) ? yp - p.yp : p.yp - yp;
+  int dx = x2, dy = y2, e = 0;
+  if (y2 > x2)
+  {
+    dx = y2;
+    dy = x2;
+    x2 = y2;
+    if (negx == negy) e++;
+  }
+  else if (negx != negy) e++;
+  e += dx - 1;
+  dx *= 2;
+  dy *= 2;
+
+  int x = 0;
+  *n = x2;
+  bool *paliers = new bool[x2];
+  while (x < x2)
+  {
+    e -= dy;
+    if (e < 0)
+    {
+      e += dx;
+      paliers[x++] = true;
+    }
+    else paliers[x++] = false;
+  }
+  return (paliers); 
+}
+
+
+std::vector<Pt2i> Pt2i::drawOrtho (const Pt2i p2, int offset) const
+{
+  std::vector<Pt2i> pts;
+
+  int x1 = xp;
+  int y1 = yp;
+  int x2 = p2.x ();
+  int y2 = p2.y ();
+  int dx = x2 - x1;
+  int dy = y2 - y1;
+  int e;
+
+  int num = dx * dy;
+  if (num < 0) num = - num;
+  int den = dx * dx + dy * dy;
+  int nabs = (offset < 0 ? -offset : offset);
+  int steps = (offset * num) / den;
+  if ((nabs * num) % den >= den / 2) steps += (offset < 0 ? -1 : 1);
+  int floors;
+
+  if (dx > 0 && dy > 0)   // Quadrant 1
+  {
+    if (dx >= dy) // Octant 1
+    {
+      e = dx - 1;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (steps * dy - e) / dx;
+      else floors = (e - 1 + steps * dy) / dx;
+      e += floors * dx - steps * dy;
+      x1 += steps;
+      y1 -= offset - floors;
+      x2 += steps;
+      // y2 -= offset - floors;   // useless
+      while (x1 < x2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        x1 ++;
+        e = e - dy;
+        if (e < 0)
+        {
+          y1 ++;
+          e = e + dx;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+    else if (dx < dy) // Octant 2
+    {
+      e = dy;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (1 - e + steps * dx) / dy;
+      else floors = (e + steps * dx) / dy;
+      e -= floors * dy - steps * dx;
+      x1 += offset - floors;
+      y1 -= steps;
+      // x2 += offset - floors;  // useless
+      y2 -= steps;  // useless
+      while (y1 < y2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        y1 ++;
+        e -= dx;
+        if (e < 0)
+        {
+          x1 ++;
+          e += dy;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+  }
+
+  else if (dx > 0 && dy < 0) // Quadrant 4
+  {
+    if (dx >= -dy) // Octant 8
+    {
+      e = dx - 1;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (e - 1 + steps * dy) / dx;
+      else floors = (steps * dy - e) / dx;   // < 0
+      e += floors * dx - steps * dy;
+      x1 -= steps;
+      y1 -= offset + floors;
+      x2 -= steps;
+      // y2 -= offset + floors;  // useless
+      while (x1 < x2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        x1 ++;
+        e += dy;
+        if (e < 0)
+        {
+          y1 --;
+          e += dx;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+    else // Octant 7
+    {
+      e = dy;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = - (e + steps * dx) / dy;
+      else floors = (e + 1 - steps * dx) / dy;
+      e += floors * dy + steps * dx;
+      x1 -= offset - floors;
+      y1 -= steps;
+      // x2 -= offset - floors;  // useless
+      y2 -= steps;
+      while (y1 > y2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        y1 --;
+        e += dx;
+        if (e > 0)
+        {
+          x1 ++;
+          e += dy;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+  }
+  else if (dy == 0 && dx > 0)
+    while (x1 <= x2) pts.push_back (Pt2i (x1++, y1 - offset));
+
+  if (dx < 0 && dy > 0)    // Quadrant 2
+  {
+    if (-dx >= dy) // Octant 4
+    {
+      e = dx - 1;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = - (steps * dy + e) / dx;
+      else floors = (e + 1 - steps * dy) / dx;  // > 0
+      e -= steps * dy + floors * dx;
+      x1 += steps;
+      y1 += offset - floors;
+      x2 += steps;
+      // y2 += offset - floors;   // useless
+      while (x1 > x2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        x1 --;
+        e += dy;
+        if (e >= 0)
+        {
+          y1 ++;
+          e += dx;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+    else if (-dx < dy) // Octant 3
+    {
+      e = dy;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (1 - e - steps * dx) / dy;
+      else floors = (e - steps * dx) / dy;
+      e += floors * dy + steps * dx;
+      x1 += offset - floors;
+      y1 += steps;
+      // x2 += offset - floors;   // useless
+      y2 += steps;
+      while (y1 < y2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        y1 ++;
+        e += dx;
+        if (e <= 0)
+        {
+          x1 --;
+          e += dy;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+  }
+
+  else if (dx < 0 && dy < 0)    // Quadrant 3
+  {
+    if (dx <= dy) // Octant 5
+    {
+      e = dx - 1;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (steps * dy - e - 1) / dx;
+      else floors = (steps * dy + e) / dx;
+      e += floors * dx - steps * dy;
+      x1 -= steps;
+      y1 += offset - floors;
+      x2 -= steps;
+      // y2 += offset - floors;  // useless
+      while (x1 > x2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        x1 --;
+        e -= dy;
+        if (e >= 0)
+        {
+          y1 --;
+          e += dx;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+    else // Octant 6
+    {
+      e = dy;
+      dx = dx * 2;
+      dy = dy * 2;
+      if (offset < 0) floors = (e - steps * dx) / dy;  // > 0
+      else floors = - (steps * dx + e + 1) / dy;
+      e += floors * dy + steps * dx;
+      x1 -= offset + floors;
+      y1 += steps;
+      y2 += steps;
+     // x2 -= offset - floors;  // useless
+      while (y1 > y2)
+      {
+        pts.push_back (Pt2i (x1, y1));
+        y1 --;
+        e -= dx;
+        if (e >= 0)
+        {
+          x1 --;
+          e += dy;
+        }
+      }
+      pts.push_back (Pt2i (x1, y1));
+    }
+  }
+  else if (dy == 0 && dx < 0)
+    while (x1 >= x2) pts.push_back (Pt2i (x1--, y1 + offset));
+  else if (dx == 0 && dy > 0)
+    while (y1 <= y2) pts.push_back (Pt2i (x1 + offset, y1++));
+  else if (dx == 0 && dy < 0)
+    while(y1 >= y2) pts.push_back (Pt2i (x1 - offset, y1--));
+  return pts;
+}
diff --git a/Expes/Testers/TestLines/ImageTools/pt2i.h b/Expes/Testers/TestLines/ImageTools/pt2i.h
new file mode 100644
index 0000000..57ac7ce
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/pt2i.h
@@ -0,0 +1,195 @@
+#ifndef PT2I_H
+#define PT2I_H
+
+#include "vr2i.h"
+#include <vector>
+
+
+/** 
+ * @class Pt2i pt2i.h
+ * \brief Point in the digital plane.
+ */
+class Pt2i
+{
+public:
+
+  /**
+   * \brief Creates a point at origin.
+   */
+  Pt2i ();
+
+  /**
+   * \brief Creates a point from coordinate values.
+   * @param x X-coordinate value.
+   * @param y Y-coordinate value.
+   */
+  Pt2i (int x, int y);
+
+  /**
+   * \brief Creates a point, coincident to given point.
+   * @param p Given point.
+   */
+  Pt2i (const Pt2i &p);
+
+  /**
+   * \brief Deletes the point.
+   */
+  ~Pt2i () { }
+
+  /**
+   * \brief Returns the X-coordinate value.
+   */
+  inline int x () const { return xp; }
+
+  /**
+   * \brief Returns the Y-coordinate value.
+   */
+  inline int y () const { return yp; }
+
+  /**
+   * \brief Returns the nth coordinate value.
+   * @param n Coordinate index.
+   */
+  inline int get (int n) const { return (n ? yp : xp); }
+
+  /**
+   * \brief Sets the point coordinates.
+   * @param x New X-coordinate value.
+   * @param y New Y-coordinate value.
+   */
+  inline void set (int x, int y) { xp = x; yp = y; }
+
+  /**
+   * \brief Sets the point coordinates.
+   * @param p Point to copy.
+   */
+  inline void set (const Pt2i &p) { xp = p.xp; yp = p.yp; }
+
+  /**
+   * \brief Checks equivalence to a reference point.
+   * @param p Reference point.
+   */
+  inline bool equals (Pt2i p) const { return (p.xp == xp && p.yp == yp); }
+
+  /**
+   * \brief Returns the manhattan distance to another point.
+   * @param p Distant point.
+   */
+  inline int manhattan (Pt2i p) const {
+    return (((p.xp > xp) ? p.xp - xp : xp - p.xp)
+            + ((p.yp > yp) ? p.yp - yp : yp - p.yp)); }
+
+  /**
+   * \brief Returns the chessboard distance to another point.
+   * @param p Distant point.
+   */
+  inline int chessboard (Pt2i p) const {
+    int dx = (p.xp > xp ? p.xp - xp : xp - p.xp);
+    int dy = (p.yp > yp ? p.yp - yp : yp - p.yp);
+    return (dx > dy ? dx : dy); }
+
+  /**
+   * \brief Checks whether the point is connected (chessboard) to the given one.
+   * @param p the given point.
+   */
+  inline bool isConnectedTo (Pt2i p) const {
+    return ((p.xp - xp <= 1) && (xp - p.xp <= 1)
+            && (p.yp - yp <= 1) && (yp - p.yp <= 1)); }
+
+  /**
+   * Checks whether the point is colinear to two other points.
+   * @param p1 First distinct point.
+   * @param p2 Second distinct point.
+   */
+  inline bool colinearTo (const Pt2i &p1, const Pt2i &p2) const {
+    return ((p1.xp - xp) * (p2.yp - yp) == (p2.xp - xp) * (p1.yp - yp)); }
+
+  /**
+   * Checks whether the point is to the left of the segment (p1p2).
+   * @param p1 Segment start point.
+   * @param p2 Segment end point.
+   */
+  inline bool toLeft (const Pt2i &p1, const Pt2i &p2) const {
+    return ((p1.xp - xp) * (p2.yp - yp) > (p2.xp - xp) * (p1.yp - yp)); }
+
+  /**
+   * Checks whether the point is to the left or on the segment (p1p2).
+   * @param p1 Segment start point.
+   * @param p2 Segment end point.
+   */
+  inline bool toLeftOrOn (const Pt2i &p1, const Pt2i &p2) const {
+    return ((p1.xp - xp) * (p2.yp - yp) >= (p2.xp - xp) * (p1.yp - yp)); }
+
+  /**
+   * \brief Check if the point belongs to the triangle with given vertices.
+   * @param p1 First triangle vertex.
+   * @param p2 Second triangle vertex.
+   * @param p3 Third triangle vertex.
+   */
+  bool inTriangle (Pt2i p1, Pt2i p2, Pt2i p3) const;
+
+  /**
+   * \brief Returns the vector to given point.
+   * @param p Given point.
+   */
+  Vr2i vectorTo (Pt2i p) const;
+
+  /**
+   * \brief Returns the straight segment to given point as a point array.
+   * @param p Given point.
+   * @param n Size of returned array.
+   */
+  Pt2i *drawing (const Pt2i p, int *n) const;
+
+  /**
+   * \brief Returns the clipped straight segment to given point.
+   *   NB: Always returns a non-null array.
+   * @param p Given point.
+   * @param left Position of left clip bound.
+   * @param low Position of lower clip bound.
+   * @param right Position of right clip bound.
+   * @param up Position of upper clip bound.
+   * @param n Size of returned array.
+   */
+  Pt2i *clipLine (const Pt2i p, int left, int low, int right, int up,
+                  int *n) const;
+
+  /**
+   * \brief Adds points of segment to a distant point to given vector.
+   * @param line Vector of points to complete.
+   * @param p Distant point.
+   */
+  void draw (std::vector<Pt2i> &line, Pt2i p) const;
+
+  /**
+   * \brief Returns the path of the straight segment to given point.
+   *   The path is composed of relative position between adjacent points.
+   * @param p Given point.
+   * @param n Size of returned array.
+   */
+  Pt2i *pathTo (Pt2i p, int *n) const;
+
+  /**
+   * \brief Returns steps location of the straight segment to given point.
+   * @param p Given point.
+   * @param n Size of returned array.
+   */
+  bool *stepsTo (Pt2i p, int *n) const;
+
+  /**
+   * \brief Returns an orthogonal segment to the segment to given point.
+   * @param p2 Given point.
+   * @param offset Orthogonal shift.
+   */
+  std::vector<Pt2i> drawOrtho (const Pt2i p2, int shift) const;
+
+
+protected:
+
+  /** Point abscissae. */
+  int xp;
+  /** Point ordinate. */
+  int yp;
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/rechanged b/Expes/Testers/TestLines/ImageTools/rechanged
new file mode 100644
index 0000000..b3cfe00
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/rechanged
@@ -0,0 +1,13 @@
+cmp absrat.h ~/tmp/ASD/ImageTools/absrat.h
+cmp digitalstraightline.cpp ~/tmp/ASD/ImageTools/digitalstraightline.cpp
+cmp digitalstraightline.h ~/tmp/ASD/ImageTools/digitalstraightline.h
+cmp digitalstraightsegment.cpp ~/tmp/ASD/ImageTools/digitalstraightsegment.cpp
+cmp digitalstraightsegment.h ~/tmp/ASD/ImageTools/digitalstraightsegment.h
+cmp edist.cpp ~/tmp/ASD/ImageTools/edist.cpp
+cmp edist.h ~/tmp/ASD/ImageTools/edist.h
+cmp pt2i.cpp ~/tmp/ASD/ImageTools/pt2i.cpp
+cmp pt2i.h ~/tmp/ASD/ImageTools/pt2i.h
+cmp vmap.cpp ~/tmp/ASD/ImageTools/vmap.cpp
+cmp vmap.h ~/tmp/ASD/ImageTools/vmap.h
+cmp vr2i.cpp ~/tmp/ASD/ImageTools/vr2i.cpp
+cmp vr2i.h ~/tmp/ASD/ImageTools/vr2i.h
diff --git a/Expes/Testers/TestLines/ImageTools/vmap.cpp b/Expes/Testers/TestLines/ImageTools/vmap.cpp
new file mode 100644
index 0000000..25861d0
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/vmap.cpp
@@ -0,0 +1,769 @@
+#include "vmap.h"
+#include <cmath>
+#include <inttypes.h>
+
+
+const int VMap::TYPE_UNKNOWN = -1;
+const int VMap::TYPE_SOBEL_3X3 = 0;
+const int VMap::TYPE_SOBEL_5X5 = 1;
+
+const int VMap::NEAR_SQ_ANGLE = 80;  // 80% (roughly 25 degrees)
+const int VMap::DEFAULT_GRADIENT_THRESHOLD = 20;
+const int VMap::DEFAULT_GRADIENT_RESOLUTION = 100;
+
+const int VMap::MAX_BOWL = 20;
+const int VMap::NB_DILATIONS = 5;
+const int VMap::DEFAULT_DILATION = 4;
+
+
+
+VMap::VMap (int width, int height, unsigned char *data, int type)
+{
+  this->width = width;
+  this->height = height;
+  this->gtype = type;
+  init ();
+  imap = new int[width * height];
+  if (type == TYPE_SOBEL_5X5)
+  {
+    buildSobel5x5Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+  else if (type == TYPE_SOBEL_3X3)
+  {
+    buildSobel3x3Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+}
+
+
+VMap::VMap (int width, int height, int *data, int type)
+{
+  this->width = width;
+  this->height = height;
+  this->gtype = type;
+  init ();
+  imap = new int[width * height];
+  if (type == TYPE_SOBEL_5X5)
+  {
+    buildSobel5x5Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+  else if (type == TYPE_SOBEL_3X3)
+  {
+    buildSobel3x3Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+}
+
+
+VMap::VMap (int width, int height, int **data, int type)
+{
+  this->width = width;
+  this->height = height;
+  this->gtype = type;
+  init ();
+  imap = new int[width * height];
+  if (type == TYPE_SOBEL_5X5)
+  {
+    buildSobel5x5Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+  else if (type == TYPE_SOBEL_3X3)
+  {
+    buildSobel3x3Map (data);
+    for (int i = 0; i < width * height; i++)
+      imap[i] = (int) sqrt (map[i].norm2 ());
+    gmagThreshold *= gradientThreshold;
+  }
+}
+
+
+VMap::VMap (int width, int height, Vr2i *map)
+{
+  this->width = width;
+  this->height = height;
+  this->gtype = TYPE_UNKNOWN;
+  this->map = map;
+  init ();
+  imap = new int[width * height];
+  for (int i = 0; i < width * height; i++)
+    imap[i] = (int) sqrt (map[i].norm2 ());
+  gmagThreshold *= gradientThreshold;
+}
+
+
+VMap::~VMap ()
+{
+  delete [] map;
+  delete [] imap;
+  delete [] mask;
+  delete [] dilations;
+  delete [] bowl;
+}
+
+
+void VMap::init ()
+{
+  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
+  gmagThreshold = gradientThreshold;
+  gradres = DEFAULT_GRADIENT_RESOLUTION;
+  mask = new bool[width * height];
+  for (int i = 0; i < width * height; i++) mask[i] = false;
+  masking = false;
+  angleThreshold = NEAR_SQ_ANGLE;
+  orientedGradient = true;
+  bowl = new Vr2i[MAX_BOWL];
+  bowl[0].set (1, 0);
+  bowl[1].set (0, 1);
+  bowl[2].set (-1, 0);
+  bowl[3].set (0, -1);
+  bowl[4].set (1, 1);
+  bowl[5].set (1, -1);
+  bowl[6].set (-1, -1);
+  bowl[7].set (-1, 1);
+  bowl[8].set (2, 0);
+  bowl[9].set (0, 2);
+  bowl[10].set (-2, 0);
+  bowl[11].set (0, -2);
+  bowl[12].set (2, 1);
+  bowl[13].set (1, 2);
+  bowl[14].set (-1, 2);
+  bowl[15].set (-2, 1);
+  bowl[16].set (-2, -1);
+  bowl[17].set (-1, -2);
+  bowl[18].set (1, -2);
+  bowl[19].set (2, -1);
+  dilations = new int[NB_DILATIONS];
+  dilations[0] = 0;
+  dilations[1] = 4;
+  dilations[2] = 8;
+  dilations[3] = 12;
+  dilations[4] = 20;
+  maskDilation = DEFAULT_DILATION;
+}
+
+
+void VMap::buildSobel3x3Map (unsigned char *data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 1; i < height - 1; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    for (int j = 1; j < width - 1; j++)
+    {
+      gm->set (data[(i - 1) * width + j + 1]
+               + 2 * data[i * width + j + 1]
+               + data[(i + 1) * width + j + 1]
+               - data[(i - 1) * width + j - 1]
+               - 2 * data[i * width + j - 1]
+               - data[(i + 1) * width + j - 1],
+               data[(i + 1) * width + j - 1]
+               + 2 * data[(i + 1) * width + j]
+               + data[(i + 1) * width + j + 1]
+               - data[(i - 1) * width + j - 1]
+               - 2 * data[(i - 1) * width + j]
+               - data[(i - 1) * width + j + 1]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+void VMap::buildSobel3x3Map (int *data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 1; i < height - 1; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    for (int j = 1; j < width - 1; j++)
+    {
+      gm->set (data[(i - 1) * width + j + 1]
+               + 2 * data[i * width + j + 1]
+               + data[(i + 1) * width + j + 1]
+               - data[(i - 1) * width + j - 1]
+               - 2 * data[i * width + j - 1]
+               - data[(i + 1) * width + j - 1],
+               data[(i + 1) * width + j - 1]
+               + 2 * data[(i + 1) * width + j]
+               + data[(i + 1) * width + j + 1]
+               - data[(i - 1) * width + j - 1]
+               - 2 * data[(i - 1) * width + j]
+               - data[(i - 1) * width + j + 1]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+void VMap::buildSobel3x3Map (int **data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 1; i < height - 1; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    for (int j = 1; j < width - 1; j++)
+    {
+      gm->set (data[i-1][j+1] + 2 * data[i][j+1] + data[i+1][j+1]
+               - data[i-1][j-1] - 2 * data[i][j-1] - data[i+1][j-1],
+               data[i+1][j-1] + 2 * data[i+1][j] + data[i+1][j+1]
+               - data[i-1][j-1] - 2 * data[i-1][j] - data[i-1][j+1]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+void VMap::buildSobel5x5Map (unsigned char *data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 2; i < height - 2; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+    for (int j = 2; j < width - 2; j++)
+    {
+      gm->set (5 * data[(i - 2) * width + j + 2]
+                 + 8 * data[(i - 1) * width + j + 2]
+                 + 10 * data[i * width + j + 2]
+                 + 8 * data[(i + 1) * width + j + 2]
+                 + 5 * data[(i + 2) * width + j + 2]
+               + 4 * data[(i - 2) * width + j + 1]
+                 + 10 * data[(i - 1) * width + j + 1]
+                 + 20 * data[i * width + j + 1]
+                 + 10 * data[(i + 1) * width + j + 1]
+                 + 4 * data[(i + 2) * width + j + 1]
+               - 4 * data[(i - 2) * width + j - 1]
+                 - 10 * data[(i - 1) * width + j - 1]
+                 - 20 * data[i * width + j - 1]
+                 - 10 * data[(i + 1) * width + j - 1]
+                 - 4 * data[(i + 2) * width + j - 1] 
+               - 5 * data[(i - 2) * width + j - 2]
+                 - 8 * data[(i - 1) * width + j - 2]
+                 - 10 * data[i * width + j - 2]
+                 - 8 * data[(i + 1) * width + j - 2]
+                 - 5 * data[(i + 2) * width + j - 2],
+               5 * data[(i + 2) * width + j - 2]
+                 + 8 * data[(i + 2) * width + j - 1]
+                 + 10 * data[(i + 2) * width + j]
+                 + 8 * data[(i + 2) * width + j + 1]
+                 + 5 * data[(i + 2) * width + j + 2]
+               + 4 * data[(i + 1) * width + j - 2]
+                 + 10 * data[(i + 1) * width + j - 1]
+                 + 20 * data[(i + 1) * width + j]
+                 + 10 * data[(i + 1) * width + j + 1]
+                 + 4 * data[(i + 1) * width + j + 2]
+               - 4 * data[(i - 1) * width + j - 2]
+                 - 10 * data[(i - 1) * width + j - 1]
+                 - 20 * data[(i - 1) * width + j]
+                 - 10 * data[(i - 1) * width + j + 1]
+                 - 4 * data[(i - 1) * width + j + 2]
+               - 5 * data[(i - 2) * width + j - 2]
+                 - 8 * data[(i - 2) * width + j - 1]
+                 - 10 * data[(i - 2) * width + j]
+                 - 8 * data[(i - 2) * width + j + 1]
+                 - 5 * data[(i - 2) * width + j + 2]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+void VMap::buildSobel5x5Map (int *data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 2; i < height - 2; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+    for (int j = 2; j < width - 2; j++)
+    {
+      gm->set (5 * data[(i - 2) * width + j + 2]
+                 + 8 * data[(i - 1) * width + j + 2]
+                 + 10 * data[i * width + j + 2]
+                 + 8 * data[(i + 1) * width + j + 2]
+                 + 5 * data[(i + 2) * width + j + 2]
+               + 4 * data[(i - 2) * width + j + 1]
+                 + 10 * data[(i - 1) * width + j + 1]
+                 + 20 * data[i * width + j + 1]
+                 + 10 * data[(i + 1) * width + j + 1]
+                 + 4 * data[(i + 2) * width + j + 1]
+               - 4 * data[(i - 2) * width + j - 1]
+                 - 10 * data[(i - 1) * width + j - 1]
+                 - 20 * data[i * width + j - 1]
+                 - 10 * data[(i + 1) * width + j - 1]
+                 - 4 * data[(i + 2) * width + j - 1] 
+               - 5 * data[(i - 2) * width + j - 2]
+                 - 8 * data[(i - 1) * width + j - 2]
+                 - 10 * data[i * width + j - 2]
+                 - 8 * data[(i + 1) * width + j - 2]
+                 - 5 * data[(i + 2) * width + j - 2],
+               5 * data[(i + 2) * width + j - 2]
+                 + 8 * data[(i + 2) * width + j - 1]
+                 + 10 * data[(i + 2) * width + j]
+                 + 8 * data[(i + 2) * width + j + 1]
+                 + 5 * data[(i + 2) * width + j + 2]
+               + 4 * data[(i + 1) * width + j - 2]
+                 + 10 * data[(i + 1) * width + j - 1]
+                 + 20 * data[(i + 1) * width + j]
+                 + 10 * data[(i + 1) * width + j + 1]
+                 + 4 * data[(i + 1) * width + j + 2]
+               - 4 * data[(i - 1) * width + j - 2]
+                 - 10 * data[(i - 1) * width + j - 1]
+                 - 20 * data[(i - 1) * width + j]
+                 - 10 * data[(i - 1) * width + j + 1]
+                 - 4 * data[(i - 1) * width + j + 2]
+               - 5 * data[(i - 2) * width + j - 2]
+                 - 8 * data[(i - 2) * width + j - 1]
+                 - 10 * data[(i - 2) * width + j]
+                 - 8 * data[(i - 2) * width + j + 1]
+                 - 5 * data[(i - 2) * width + j + 2]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+void VMap::buildSobel5x5Map (int **data)
+{
+  map = new Vr2i[width * height];
+  Vr2i *gm = map;
+
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int i = 2; i < height - 2; i++)
+  {
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+    for (int j = 2; j < width - 2; j++)
+    {
+      gm->set (
+        5 * data[i-2][j+2] + 8 * data[i-1][j+2] + 10 * data[i][j+2]
+                           + 8 * data[i+1][j+2] + 5 * data[i+2][j+2]
+        + 4 * data[i-2][j+1] + 10 * data[i-1][j+1] + 20 * data[i][j+1]
+                           + 10 * data[i+1][j+1] + 4 * data[i+2][j+1]
+        - 4 * data[i-2][j-1] - 10 * data[i-1][j-1] - 20 * data[i][j-1]
+                           - 10 * data[i+1][j-1] - 4 * data[i+2][j-1]
+        - 5 * data[i-2][j-2] - 8 * data[i-1][j-2] - 10 * data[i][j-2]
+                           - 8 * data[i+1][j-2] - 5 * data[i+2][j-2],
+        5 * data[i+2][j-2] + 8 * data[i+2][j-1] + 10 * data[i+2][j]
+                           + 8 * data[i+2][j+1] + 5 * data[i+2][j+2]
+        + 4 * data[i+1][j-2] + 10 * data[i+1][j-1] + 20 * data[i+1][j]
+                           + 10 * data[i+1][j+1] + 4 * data[i+1][j+2]
+        - 4 * data[i-1][j-2] - 10 * data[i-1][j-1] - 20 * data[i-1][j]
+                           - 10 * data[i-1][j+1] - 4 * data[i-1][j+2]
+        - 5 * data[i-2][j-2] - 8 * data[i-2][j-1] - 10 * data[i-2][j]
+                           - 8 * data[i-2][j+1] - 5 * data[i-2][j+2]);
+      gm++;
+    }
+    gm->set (0, 0);
+    gm++;
+    gm->set (0, 0);
+    gm++;
+  }
+  for (int j = 0; j < 2 * width; j++)
+  {
+    gm->set (0, 0);
+    gm++;
+  }
+}
+
+
+int VMap::sqNorm (int i, int j) const
+{
+  return (map[j * width + i].norm2 ());
+}
+
+
+int VMap::sqNorm (Pt2i p) const
+{
+  return (map[p.y () * width + p.x ()].norm2 ());
+}
+
+
+int VMap::largestIn (const std::vector<Pt2i> &pix) const
+{
+  if (pix.empty ()) return (-1);
+
+  int imax = -1;
+  std::vector<Pt2i>::const_iterator pt = pix.begin ();
+  int gmax = imap[pt->y() * width + pt->x()];
+  if (gmax < gmagThreshold) gmax = gmagThreshold;
+
+  int i = 0;
+  while (pt != pix.end ())
+  {
+    int g = imap[pt->y() * width + pt->x()];
+    if (g > gmax)
+    {
+      gmax = g;
+      imax = i;
+    }
+    pt ++;
+    i ++;
+  }
+  return (imax == i - 1 ? -1 : imax);
+}
+
+
+int VMap::keepFreeElementsIn (const std::vector<Pt2i> &pix,
+                              int n, int *ind) const
+{
+  int i = 0;
+  while (i < n)
+  {
+    if (mask[pix[ind[i]].y () * width + pix[ind[i]].x ()]) ind[i] = ind[--n];
+    else i++;
+  }
+  return (n);
+}
+
+
+int VMap::keepContrastedMax (int *lmax, int n, int *in) const
+{
+  if (n == 0) return 0;
+  int *min = new int[n-1];
+  bool *fired = new bool[n];
+  int nbfired = 0;
+  int sleft = 0;
+
+  // Clears the list of fired max
+  for (int i = 0; i < n; i++) fired[i] = false;
+
+  // Computes the ponds depth
+  for (int i = 0; i < n - 1; i++)
+  {
+    min[i] = in[lmax[i]];
+    for (int j = lmax[i] + 1; j < lmax[i+1]; j++)
+      if (in[j] < min[i]) min[i] = in[j];
+  }
+  // For each ponds
+  for (int i = 0; i < n - 1; i++)
+  {
+    // if the right summit is lower
+    if (in[lmax[i+1]] < in[lmax[sleft]])
+    {
+      if (in[lmax[i+1]] - min[i] < gradres) // gradient resolution
+      {
+        fired[i+1] = true;
+        nbfired ++;
+        if (i < n - 2) if (min[i+1] < min[i]) min[i+1] = min[i];
+      }
+    }
+    // if the left summit is lower
+    else
+    {
+      if (in[lmax[sleft]] - min[i] < gradres) // gradient resolution
+      {
+        fired[sleft] = true;
+        nbfired ++;
+        sleft = i + 1;
+      }
+    }
+  }
+  // Pruning
+  int i = 0, j = 0;
+  while (i < n && ! fired[i++]) j++;
+  while (i < n)
+  {
+    while (i < n && fired[i]) i++;
+    if (i < n) lmax[j++] = lmax[i++];
+  }
+  return (n - nbfired);
+}
+
+
+int VMap::keepDirectedElementsAs (const std::vector<Pt2i> &pix,
+                                  int n, int *ind, const Vr2i &ref) const
+{
+  int vx = ref.x ();
+  int vy = ref.y ();
+  int i = 0;
+  while (i < n)
+  {
+    Vr2i gr = map[pix[ind[i]].y () * width + pix[ind[i]].x ()];
+    if (vx * gr.x () + vy * gr.y () <= 0) ind[i] = ind[--n];
+    else i++;
+  }
+  return (n);
+}
+
+
+int VMap::keepOrientedElementsAs (const std::vector<Pt2i> &pix,
+                                  int n, int *ind, const Vr2i &ref) const
+{
+  int64_t vx = (int64_t) ref.x ();
+  int64_t vy = (int64_t) ref.y ();
+  int64_t vn2 = (int64_t) vx * (int64_t) vx + (int64_t) vy * (int64_t) vy;
+
+  int i = 0;
+  while (i < n)
+  {
+    Pt2i p = pix.at (ind[i]);
+    Vr2i gr = map[p.y () * width + p.x ()];
+    int64_t gx = (int64_t) gr.x ();
+    int64_t gy = (int64_t) gr.y ();
+    if ((vx * vx * gx * gx + vy * vy * gy * gy + 2 * vx * vy * gx * gy) * 100
+        < vn2 * (gx * gx + gy * gy) * angleThreshold)
+      ind[i] = ind[--n];
+    else i++;
+  }
+  return (n);
+}
+
+
+int VMap::localMax (int *lmax, const std::vector<Pt2i> &pix) const
+{
+  // Builds the gradient norm signal
+  int n = (int) pix.size ();
+  int *gn = new int[n];
+  int i = 0;
+  std::vector<Pt2i>::const_iterator it = pix.begin ();
+  while (it != pix.end ()) gn[i++] = magn (*it++);
+
+  // Gets the local maxima
+  int count = searchLocalMax (lmax, n, gn);
+
+  // Prunes the low contrasted local maxima
+  count = keepContrastedMax (lmax, count, gn);
+
+  // Prunes the already selected candidates
+  count = keepFreeElementsIn (pix, count, lmax);
+
+  // Sorts candidates by gradient magnitude
+  sortMax (lmax, count, gn);
+
+  delete gn;
+  return count;
+}
+
+
+int VMap::localMax (int *lmax, const std::vector<Pt2i> &pix,
+                    const Vr2i &gref) const
+{
+  // Builds the gradient norm signal
+  int n = (int) pix.size ();
+  int *gn = new int[n];
+  int i = 0;
+  std::vector<Pt2i>::const_iterator it = pix.begin ();
+  while (it != pix.end ()) gn[i++] = magn (*it++);
+
+  // Gets the local maxima
+  int count = searchLocalMax (lmax, n, gn);
+
+  // Prunes the already selected candidates
+  if (masking)
+    count = keepFreeElementsIn (pix, count, lmax);
+
+  // Prunes the candidates with opposite gradient
+  if (orientedGradient)
+    count = keepDirectedElementsAs (pix, count, lmax, gref);
+
+  // Prunes the candidates wrongly oriented
+  count = keepOrientedElementsAs (pix, count, lmax, gref);
+
+  // Sorts candidates by gradient magnitude
+  sortMax (lmax, count, gn);
+
+  delete gn;
+  return count;
+}
+
+
+void VMap::incGradientThreshold (int inc)
+{
+  gradientThreshold += inc;
+  if (gradientThreshold < 0) gradientThreshold = 0;
+  if (gradientThreshold > 255) gradientThreshold = 255;
+  gmagThreshold = gradientThreshold;
+  if (gtype <= TYPE_SOBEL_5X5) gmagThreshold *= gmagThreshold;
+}
+
+
+void VMap::incLocalMaxGradientResolution (int inc)
+{
+  gradres += inc * 5;
+  if (gradres < 0) gradres = 0;
+}
+
+
+int VMap::searchLocalMax (int *lmax, int n, int *in) const
+{
+  int offset = 0;
+  int count = 0;
+  bool up = true;
+
+  // Gets the first distinct value from start
+  while (offset < n - 1 && in[offset] == in[0])
+  {
+    if (in[offset] - in[offset + 1] < 0)
+    {
+      up = true;
+      break;
+    }
+    if (in[offset] - in[offset + 1] > 0)
+    {
+      up = false;
+      break;
+    }
+    offset++;
+  }
+
+  for(int i = offset; i < n - 1; i++)
+  {
+    if (up)
+    {
+      if ((in[i + 1] - in[i]) < 0)
+      {
+        up = false;
+        int k = i;
+        while (in[k - 1] == in[i]) k--;
+        if (in[k + (i - k) / 2] > gmagThreshold)
+          lmax[count++] = k + (i - k) / 2;
+      }
+    }
+    else
+      if (in[i + 1] - in[i] > 0) up = true;
+  }
+  return count;
+}
+
+
+void VMap::sortMax (int *lmax, int n, int *val) const
+{
+  for (int i = 1; i < n; i ++)
+  {
+    int j = i, tmp = lmax[i];
+    bool on = true;
+    while (on && j > 0)
+    {
+      if (val[tmp] > val[lmax[j-1]])
+      {
+        lmax[j] = lmax[j-1];
+        j --;
+      }
+      else on = false;
+    }
+    lmax[j] = tmp;
+  }
+}
+
+
+void VMap::clearMask ()
+{
+  for (int i = 0; i < width * height; i++) mask[i] = false;
+}
+
+
+void VMap::setMask (const std::vector<Pt2i> &pts)
+{
+  std::vector<Pt2i>::const_iterator it = pts.begin ();
+  while (it != pts.end ())
+  {
+    Pt2i pt = *it++;
+    mask[pt.y () * width + pt.x ()] = true;
+    for (int i = 0; i < dilations[maskDilation]; i++)
+    {
+      int x = pt.x () + bowl[i].x ();
+      int y = pt.y () + bowl[i].y ();
+      if (x >= 0 && x < width && y >= 0 && y < height)
+        mask[y * width + x] = true;
+    }
+  }
+}
diff --git a/Expes/Testers/TestLines/ImageTools/vmap.h b/Expes/Testers/TestLines/ImageTools/vmap.h
new file mode 100644
index 0000000..a94c2e5
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/vmap.h
@@ -0,0 +1,393 @@
+#ifndef VMAP_H
+#define VMAP_H
+
+#include "pt2i.h"
+
+
+/** 
+ * @class VMap vmap.h
+ * \brief Map of 2D vectors.
+ */
+class VMap
+{
+public:
+
+  /** Gradient extraction method : Undeterminated. */
+  static const int TYPE_UNKNOWN;
+  /** Gradient extraction method : Sobel with 3x3 kernel. */
+  static const int TYPE_SOBEL_3X3;
+  /** Gradient extraction method : Sobel with 5x5 kernel. */
+  static const int TYPE_SOBEL_5X5;
+
+
+  /** 
+   * \brief Creates a gradient map from scalar data.
+   * @param width Map width.
+   * @param height Map height.
+   * @param data Scalar data array.
+   * @param type Gradient extraction method (default is Sobel with 3x3 kernel).
+   */
+  VMap (int width, int height, unsigned char *data, int type = 0);
+
+  /** 
+   * \brief Creates a gradient map from scalar data.
+   * @param width Map width.
+   * @param height Map height.
+   * @param data Scalar data array.
+   * @param type Gradient extraction method (default is Sobel with 3x3 kernel).
+   */
+  VMap (int width, int height, int *data, int type = 0);
+
+  /** 
+   * \brief Creates a gradient map from scalar data.
+   * @param width Map width.
+   * @param height Map height.
+   * @param data Scalar data bi-dimensional array.
+   */
+  VMap (int width, int height, int **data, int type = 0);
+
+  /** 
+   * \brief Creates a gradient map from given vector map.
+   * @param width Map width.
+   * @param height Map height.
+   * @param map Vector map.
+   */
+  VMap (int width, int height, Vr2i *map);
+
+  /** 
+   * \brief Deletes the vector map.
+   */
+  ~VMap ();
+
+  /** 
+   * \brief Returns the map width.
+   */
+  inline int getWidth () const { return width; }
+
+  /** 
+   * \brief Returns the map height.
+   */
+  inline int getHeight () const { return height; }
+
+  /** 
+   * \brief Returns the maximal value between map width or height.
+   */
+  inline int getHeightWidthMax () const {
+    return (height > width ? height : width); }
+
+  /**
+   * \brief Checks whether given pixel lies within the map bounds.
+   * @param i Column index of the pixel.
+   * @param j Raw index of the pixel.
+   */
+  inline bool contains (int i, int j)
+  {
+    return (i >= 0 && i < width && j >= 0 && j < height);
+  }
+
+  /**
+   * \brief Returns a pointer to the vectors of the map.
+   */
+  inline Vr2i *getVectorMap () const { return (map); }
+
+  /**
+   * \brief Returns the vector at pixel (i,j).
+   * @param i Column index of the pixel.
+   * @param j Raw index of the pixel.
+   */
+  inline Vr2i getValue (int i, int j) const { return (map[j * width + i]); }
+
+  /**
+   * \brief Returns the vector at given position.
+   * @param p Pixel position.
+   */
+  inline Vr2i getValue (Pt2i p) const { return (map[p.y () * width + p.x ()]); }
+
+  /**
+   * \brief Returns the squared norm of the vector magnitude at pixel (i,j).
+   * @param i Column index of the pixel.
+   * @param j Raw index of the pixel.
+   */
+  int sqNorm (int i, int j) const;
+
+  /**
+   * \brief Returns the squared norm of the vector magnitude at given position.
+   * @param p Pixel position.
+   */
+  int sqNorm (Pt2i p) const;
+
+  /**
+   * \brief Returns comparable norm of the vector magnitude at pixel (i,j).
+   * @param i Column index of the pixel.
+   * @param j Raw index of the pixel.
+   */
+  inline int magn (int i, int j) const { return (imap[j * width + i]); }
+
+  /**
+   * \brief Returns comparable norm of the vector magnitude at given position.
+   * @param p Pixel position.
+   */
+  inline int magn (Pt2i p) const { return (imap[p.y () * width + p.x ()]); }
+
+  /** 
+   * \brief Returns the index of the largest vector at given positions.
+   *   First and last points of the list are not accepted.
+   *   A gradient minimal threshold is set for the test.
+   * Returns -1 if no max is found.
+   * @param pix List of pixels.
+   */
+  int largestIn (const std::vector<Pt2i> &pix) const;
+
+  /**
+   * \brief Keeps elements that are not already selected (in the mask array).
+   * Returns the number of remaining elements in the selection.
+   * @param pix Input array of scanned pixels.
+   * @param n Initial size of the selection of pixels.
+   * @param ind Selection of pixels.
+   */
+  int keepFreeElementsIn (const std::vector<Pt2i> &pix, int n, int *ind) const;
+
+  /**
+   * \brief Searches local gradient maxima values.
+   * Returns the count of perceptible local maxima found.
+   * @param lmax Local max index array.
+   * @param n Count of input max values.
+   * @param in Array of input values.
+   */
+  int keepContrastedMax (int *lmax, int n, int *in) const;
+
+  /**
+   * \brief Keeps elements with a reference direction.
+   * Keeps elements with the same direction as a reference vector
+   *   in a selection of pixels (positive scalar product).
+   * Returns the number of remaining elements in the selection.
+   * @param pix Input array of scanned pixels.
+   * @param n Initial size of the selection of pixels.
+   * @param ind Selection of pixels.
+   * @param ref Reference vector for direction test.
+   */
+  int keepDirectedElementsAs (const std::vector<Pt2i> &pix,
+                              int n, int *ind, const Vr2i &ref) const;
+
+  /**
+   * \brief Keeps elements with reference gradient magnitude.
+   * Keeps elements with gradient value near a reference vector
+   *   in a selection of pixels.
+   * Relies on angleThreshold value for the test.
+   * Returns the number of remaining elements in the selection.
+   * @param pix Input array of scanned points.
+   * @param n Initial size of the selection of pixels.
+   * @param ind Selection of pixels.
+   * @param ref Reference vector for magnitude test.
+   */
+  int keepOrientedElementsAs (const std::vector<Pt2i> &pix,
+                              int n, int *ind, const Vr2i &ref) const;
+
+  /**
+   * \brief Gets filtered and sorted local gradient maxima in a set of pixels.
+   * Local max already used are pruned.
+   * Returns the count of found gradient maxima.
+   * @param lmax Ouput local max index array.
+   * @param pix Input set of pixels to process.
+   */
+  int localMax (int *lmax, const std::vector<Pt2i> &pix) const;
+
+  /**
+   * \brief Gets filtered and sorted local oriented gradient maxima.
+   * Local maxima are filtered according to the gradient direction and sorted.
+   * Returns the count of found gradient maxima.
+   * @param lmax Local max index array.
+   * @param pix Input set of pixels to process.
+   * @param gref Gradient vector reference.
+   */
+  int localMax (int *lmax, const std::vector<Pt2i> &pix, const Vr2i &gref) const;
+
+  /**
+   * \brief Returns the gradient threshold value used for maxima detection.
+   */
+  inline int getGradientThreshold () const { return (gradientThreshold); }
+
+  /**
+   * \brief Increments the gradient threshold value used for maxima detection.
+   * @param inc Increment value.
+   */
+  void incGradientThreshold (int inc);
+
+  /**
+   * \brief Returns the gradient resolution value used for maxima filtering.
+   */
+  inline int getLocalMaxGradientResolution () const { return (gradres); }
+
+  /**
+   * \brief Increments the gradient resolution value used for maxima filtering.
+   * @param inc Increment direction (-1 or +1).
+   */
+  void incLocalMaxGradientResolution (int inc);
+
+  /**
+   * \brief Switches the direction constraint for local maxima selection.
+   */
+  inline void switchOrientationConstraint () {
+    orientedGradient = ! orientedGradient; }
+
+  /**
+   * \brief Switches the direction constraint for local maxima selection.
+   */
+  inline bool isOrientationConstraintOn () const { return orientedGradient; }
+
+  /**
+   * \brief Returns the occupancy mask contents.
+   */
+  inline bool *getMask () const { return (mask); }
+
+  /**
+   * \brief Clears the occupancy mask.
+   */
+  void clearMask ();
+
+  /**
+   * \brief Adds pixels to the occupancy mask.
+   * @param pts Vector of pixels.
+   */
+  void setMask (const std::vector<Pt2i> &pts);
+
+  /**
+   * \brief Sets mask activation on or off.
+   * @param status New activation status.
+   */
+  inline void setMasking (bool status) { masking = status; }
+
+  /**
+   * \brief Retuns the mask dilation size.
+   */
+  inline int getMaskDilation () const { return (dilations[maskDilation]); }
+
+  /**
+   * \brief Toggles the mask dilation size.
+   */
+  inline void toggleMaskDilation () {
+    if (++maskDilation == NB_DILATIONS) maskDilation = 0; }
+
+  /**
+   * \brief Tests the occupancy of a mask cell.
+   * @param pix Pixel to test in the mask.
+   */
+  inline bool isFree (const Pt2i &pix) const {
+    return (! mask[pix.y () * width + pix.x ()]); }
+
+
+private:
+
+  /** Default value for near angular deviation tests. */
+  static const int NEAR_SQ_ANGLE;
+  /** Default threshold value for the gradient selection. */
+  static const int DEFAULT_GRADIENT_THRESHOLD;
+  /** Default threshold value for the gradient resolution (filtering). */
+  static const int DEFAULT_GRADIENT_RESOLUTION;
+  /** Size of the maximal dilation bowl. */
+  static const int MAX_BOWL;
+  /** Number of dilation types. */
+  static const int NB_DILATIONS;
+  /** Default dilation for the points added to the mask. */
+  static const int DEFAULT_DILATION;
+
+  /** Image width. */
+  int width;
+  /** Image height. */
+  int height;
+  /** Gradient type. */
+  int gtype;
+  /** Vector map. */
+  Vr2i *map;
+  /** Magnitude map (squared norm). */
+  int *imap;
+
+  /** Effective value for the angular deviation test. */
+  int angleThreshold;
+  /** Standardized gradient threshold for highest value detection. */
+  int gradientThreshold;
+  /** Gradient magnitude threshold for highest value detection. */
+  int gmagThreshold;
+  /** Gradient resolution threshold for local max filtering. */
+  int gradres;
+  /** Direction constraint status for local gradient maxima. */
+  bool orientedGradient;
+
+  /** Occupancy mask. */
+  bool *mask;
+  /** Flag indicating whether the occupancy mask is in use. */
+  bool masking;
+  /** Type of dilation applied to the points added to the mask. */
+  int maskDilation;
+  /** Number of neighbours in the applied dilation. */
+  int *dilations;
+  /** Dilation bowl. */
+  Vr2i *bowl;
+
+
+  /** 
+   * \brief Initializes the internal data of the vector map.
+   */
+  void init ();
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 3x3 kernel by default.
+   * @param data Initial scalar data.
+   */
+  void buildSobel3x3Map (unsigned char *data);
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 3x3 kernel by default.
+   * @param data Initial scalar data.
+   */
+  void buildSobel3x3Map (int *data);
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 3x3 kernel by default.
+   * @param data Initial bi-dimensional scalar data.
+   */
+  void buildSobel3x3Map (int **data);
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 5x5 kernel.
+   * @param data Initial scalar data.
+   */
+  void buildSobel5x5Map (unsigned char *data);
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 5x5 kernel.
+   * @param data Initial scalar data.
+   */
+  void buildSobel5x5Map (int *data);
+
+  /** 
+   * \brief Builds the vector map as a gradient map from provided data.
+   * Uses a Sobel 5x5 kernel.
+   * @param data Initial bi-dimensional scalar data.
+   */
+  void buildSobel5x5Map (int **data);
+
+  /**
+   * \brief Searches local gradient maxima values.
+   * Returns the count of local maxima found.
+   * @param lmax Local max index array.
+   * @param n Count of input values.
+   * @param in Array of input values.
+   */
+  int searchLocalMax (int *lmax, int n, int *in) const;
+
+  /**
+   * \brief Sorts the candidates array by highest magnitude.
+   * @param lmax Local max index array.
+   * @param n Size of index array.
+   * @param val Input values.
+   */
+  void sortMax (int *lmax, int n, int *val) const;
+
+};
+#endif
diff --git a/Expes/Testers/TestLines/ImageTools/vr2i.cpp b/Expes/Testers/TestLines/ImageTools/vr2i.cpp
new file mode 100644
index 0000000..18f4258
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/vr2i.cpp
@@ -0,0 +1,70 @@
+#include "vr2i.h"
+
+
+Vr2i::Vr2i ()
+{
+  xv = 1;
+  yv = 0;
+}
+
+
+Vr2i::Vr2i (int x, int y)
+{
+  xv = x;
+  yv = y;
+}
+
+
+Vr2i::Vr2i (const Vr2i &v)
+{
+  xv = v.xv;
+  yv = v.yv;
+}
+
+
+Vr2i Vr2i::orthog () const
+{
+  return (Vr2i (-yv, xv));
+}
+
+
+bool Vr2i::orientedAs (const Vr2i &ref) const
+{
+  int ps = xv * ref.xv + yv * ref.yv;
+  return (4 * ps * ps > 3 * (xv * xv + yv * yv)
+                          * (ref.xv * ref.xv + ref.yv * ref.yv));
+}
+
+
+bool *Vr2i::steps (int *n) const
+{
+  int x2 = (xv > 0 ? xv : - xv);
+  int y2 = (yv > 0 ? yv : - yv);
+  int dx = x2, dy = y2;
+  if (y2 > x2)
+  {
+    dx = y2;
+    dy = x2;
+    x2 = y2;
+  }
+  int e, x = 0, i = 0;
+  *n = x2;
+  bool *vecsteps = new bool[x2];
+
+  e = dx;
+  dx *= 2;
+  dy *= 2;
+
+  while (x < x2)
+  {
+    x ++;
+    e -= dy;
+    if (e < 0)
+    {
+      e += dx;
+      vecsteps[i++] = true;
+    }
+    else vecsteps[i++] = false;
+  }
+  return (vecsteps); 
+}
diff --git a/Expes/Testers/TestLines/ImageTools/vr2i.h b/Expes/Testers/TestLines/ImageTools/vr2i.h
new file mode 100644
index 0000000..09f675e
--- /dev/null
+++ b/Expes/Testers/TestLines/ImageTools/vr2i.h
@@ -0,0 +1,156 @@
+#ifndef VR2I_H
+#define VR2I_H
+
+
+/** 
+ * @class Vr2i vr2i.h
+ * \brief Vector in the digital plane.
+ */
+class Vr2i
+{
+public:
+
+  /**
+   * \brief Creates a unit vector on X axis: (1,0).
+   */
+  Vr2i ();
+
+  /**
+   * \brief Creates a vector using coordinate values.
+   * @param x X-coordinate value.
+   * @param y Y-coordinate value.
+   */
+  Vr2i (int x, int y);
+
+  /**
+   * \brief Creates a copy from a given vector.
+   * @param v Original vector to copy.
+   */
+  Vr2i (const Vr2i &v);
+
+  /**
+   * \brief Returns the X-coordinate value.
+   */
+  inline int x () const { return xv; }
+
+  /**
+   * \brief Returns the Y-coordinate value.
+   */
+  inline int y () const { return yv; }
+
+  /**
+   * \brief Sets the vector coordinate values.
+   * @param x New value for X-coordinate.
+   * @param y New value for Y-coordinate.
+   */
+  inline void set (int x, int y) { xv = x; yv = y; }
+
+  /**
+   * \brief Sets vector value on another vector.
+   * @param vec Vector to copy.
+   */
+  inline void set (const Vr2i &vec) { xv = vec.xv; yv = vec.yv; }
+
+  /**
+   * \brief Returns the squared norm of the vector.
+   * If intensity value holds on a byte, gradient holds on a short
+   *   and gradient squared norm holds on an int.
+   */
+  inline int norm2 () const { return (xv * xv + yv * yv); }
+
+  /**
+   * \brief Returns the scalar product with given vector.
+   * If intensity value holds on a byte, scalar product (SP) holds on a short
+   *   and squared SP holds on a int.
+   * @param vec Given vector.
+   */
+  inline int scalarProduct (Vr2i vec) const {
+    return (xv * vec.xv + yv * vec.yv); }
+
+  /**
+   * \brief Returns the squared scalar product with given vector.
+   * @param vec The given vector.
+   */
+  inline int squaredScalarProduct (Vr2i vec) const {
+    return ((xv * vec.xv + yv * vec.yv)
+            * (xv * vec.xv + yv * vec.yv)); }
+
+  /**
+   * \brief Returns if a given vector is on the left side of this vector.
+   * @param vec Given vector.
+   */
+  inline bool leftside (Vr2i vec) const {
+    return (xv * vec.yv > yv * vec.xv); }
+
+  /**
+   * \brief Returns the squared norm of the vector product with given vector.
+   * @param vec Given vector.
+   */
+  inline int squaredVectorProduct (Vr2i vec) const {
+    return ((xv * vec.yv - yv * vec.xv) * (xv * vec.yv - yv * vec.xv)); }
+
+  /**
+   * \brief Checks equivalence to the given vector.
+   * @param v Given vector.
+   */
+  inline bool equals (Vr2i v) const {
+    return (v.xv == xv && v.yv == yv); }
+
+  /**
+   * \brief Returns the manhattan length of the vector.
+   */
+  inline int manhattan () const {
+    return ((xv > 0 ? xv : - xv) + (yv > 0 ? yv : - yv)); }
+
+  /**
+   * \brief Returns the chessboard length of the vector.
+   */
+  inline int chessboard () const {
+    int x = (xv < 0 ? -xv : xv), y = (yv < 0 ? -yv : yv);
+    return (x > y ? x : y); }
+
+  /**
+   * \brief Returns the CCW orthogonal vector.
+   */
+  Vr2i orthog () const;
+
+  /**
+   * \brief Sets the vector to the CCW orthogonal vector.
+   */
+  inline void setOrthog () { int tmp = xv; xv = - yv; yv = tmp; }
+
+  /**
+   * \brief Checks whether this vector has same direction as a reference vector.
+   * @param ref Reference vector.
+   */
+  inline bool directedAs (const Vr2i &ref) const {
+    return (xv * ref.xv + yv * ref.yv >= 0); }
+
+  /**
+   * \brief Checks whether this vector has the same orientation as a reference.
+   * @param ref Reference vector.
+   */
+  bool orientedAs (const Vr2i &ref) const;
+
+  /**
+   * \brief Sets the vector to its opposite.
+   */
+  inline void invert () { xv = -xv; yv = -yv; }
+
+  /**
+   * \brief Returns the location of the steps between the vector ends.
+   * DEPRECATED METHOD: DON'T USE ANY MORE. Use Pt2i::stepsTo (Pt2i) instead.
+   * @param n Size of the returned array.
+   */
+  bool *steps (int *n) const;
+
+
+private:
+
+  /** Vector X-coordinate value. */
+  int xv;
+  /** Vector Y-coordinate value. */
+  int yv;
+};
+
+#endif
diff --git a/Expes/Testers/TestLines/Images/couloir.gif b/Expes/Testers/TestLines/Images/couloir.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9489eff401ac290ddd0f796930b747a59ec43982
GIT binary patch
literal 113589
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
G0RTIuSIDFQ

literal 0
HcmV?d00001

diff --git a/Expes/Testers/TestLines/TestLines.pro b/Expes/Testers/TestLines/TestLines.pro
new file mode 100644
index 0000000..c9f19c8
--- /dev/null
+++ b/Expes/Testers/TestLines/TestLines.pro
@@ -0,0 +1,74 @@
+######################################################################
+# Automatically generated by qmake (3.0) mer. nov. 7 21:11:32 2018
+######################################################################
+
+QT+=widgets
+TEMPLATE = app
+TARGET = TestLines
+INCLUDEPATH += . \
+           BlurredSegment \
+           DirectionalScanner \
+           ConvexHull \
+           ImageTools
+OBJECTS_DIR = obj
+
+# Input
+HEADERS += BlurredSegment/biptlist.h \
+           BlurredSegment/bsdetector.h \
+           BlurredSegment/bsproto.h \
+           BlurredSegment/bstracker.h \
+           BlurredSegment/nfafilter.h \
+           ConvexHull/antipodal.h \
+           ConvexHull/chvertex.h \
+           ConvexHull/convexhull.h \
+           DirectionalScanner/adaptivescannero1.h \
+           DirectionalScanner/adaptivescannero2.h \
+           DirectionalScanner/adaptivescannero7.h \
+           DirectionalScanner/adaptivescannero8.h \
+           DirectionalScanner/directionalscanner.h \
+           DirectionalScanner/directionalscannero1.h \
+           DirectionalScanner/directionalscannero2.h \
+           DirectionalScanner/directionalscannero7.h \
+           DirectionalScanner/directionalscannero8.h \
+           DirectionalScanner/scannerprovider.h \
+           DirectionalScanner/vhscannero1.h \
+           DirectionalScanner/vhscannero2.h \
+           DirectionalScanner/vhscannero7.h \
+           DirectionalScanner/vhscannero8.h \
+           ImageTools/absrat.h \
+           ImageTools/digitalstraightline.h \
+           ImageTools/digitalstraightsegment.h \
+           ImageTools/edist.h \
+           ImageTools/pt2i.h \
+           ImageTools/vmap.h \
+           ImageTools/vr2i.h
+SOURCES += main.cpp \
+           BlurredSegment/biptlist.cpp \
+           BlurredSegment/blurredsegment.cpp \
+           BlurredSegment/bsdetector.cpp \
+           BlurredSegment/bsproto.cpp \
+           BlurredSegment/bstracker.cpp \
+           BlurredSegment/nfafilter.cpp \
+           ConvexHull/antipodal.cpp \
+           ConvexHull/chvertex.cpp \
+           ConvexHull/convexhull.cpp \
+           DirectionalScanner/adaptivescannero1.cpp \
+           DirectionalScanner/adaptivescannero2.cpp \
+           DirectionalScanner/adaptivescannero7.cpp \
+           DirectionalScanner/adaptivescannero8.cpp \
+           DirectionalScanner/directionalscanner.cpp \
+           DirectionalScanner/directionalscannero1.cpp \
+           DirectionalScanner/directionalscannero2.cpp \
+           DirectionalScanner/directionalscannero7.cpp \
+           DirectionalScanner/directionalscannero8.cpp \
+           DirectionalScanner/scannerprovider.cpp \
+           DirectionalScanner/vhscannero1.cpp \
+           DirectionalScanner/vhscannero2.cpp \
+           DirectionalScanner/vhscannero7.cpp \
+           DirectionalScanner/vhscannero8.cpp \
+           ImageTools/digitalstraightline.cpp \
+           ImageTools/digitalstraightsegment.cpp \
+           ImageTools/edist.cpp \
+           ImageTools/pt2i.cpp \
+           ImageTools/vmap.cpp \
+           ImageTools/vr2i.cpp
diff --git a/Expes/Testers/TestLines/main.cpp b/Expes/Testers/TestLines/main.cpp
new file mode 100644
index 0000000..82a01e5
--- /dev/null
+++ b/Expes/Testers/TestLines/main.cpp
@@ -0,0 +1,305 @@
+#include <QImage>
+#include <QString>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <ctime>
+#include <cmath>
+#include "bsdetector.h"
+
+#define DBG 0
+#define REPETITIONS 100
+#define MIN_LENGTH 10
+
+using namespace std;
+
+
+int genDssFromLines (vector<DigitalStraightSegment> &dss, double &cl,
+                     int height, int minl, string name, int nbi)
+{
+  double val[nbi];
+  int i = 0;
+
+  cl = 0.0;
+  ifstream input (name.c_str (), ios::in);
+  if (! input.is_open ()) return 0;
+
+  bool reading = true;
+  while (reading)
+  {
+    input >> val[i];
+    if (input.eof ()) reading = false;
+    else
+    {
+      if (++i == nbi)
+      {
+        Pt2i p1 ((int) (val[0] + 0.5), height - 1 - (int) (val[1] + 0.5));
+        Pt2i p2 ((int) (val[2] + 0.5), height - 1 - (int) (val[3] + 0.5));
+//        Pt2i p1 ((int) val[0], height - 1 - (int) val[1]);
+//        Pt2i p2 ((int) val[2], height - 1 - (int) val[3]);
+        if (p1.equals (p2)) cout << "LIGNE NULLE !!!" << endl;
+        else
+        {
+          cl += sqrt (p1.vectorTo(p2).norm2 ());
+          if (minl == 0 || cl >= minl)
+            dss.push_back (DigitalStraightSegment (p1, p2, 1));
+        }
+        i = 0;
+      }
+    }
+  }
+  input.close ();
+  return ((int) (dss.size ()));
+}
+
+
+int genDssFromImage (std::vector<DigitalStraightSegment> &dss, double &cl,
+                     QImage &im, int minl, bool isNaive)
+{
+  BSDetector detector;
+  int width = im.width ();
+  int height = im.height ();
+  int **tabImage = new int*[height];
+  for (int i = 0; i < height; i++)
+  {
+    tabImage[i] = new int[width];
+    for(int j = 0; j < width; j++)
+    {
+      QColor c = QColor (im.pixel (j, height - i - 1));
+      tabImage[i][j] = c.value ();
+    }
+  }
+  detector.setGradientMap (new VMap (width, height, tabImage,
+                                     VMap::TYPE_SOBEL_5X5));
+  if (minl != 0)
+  {
+    if (! detector.isFinalSizeTestOn ()) detector.switchFinalSizeTest ();
+    detector.setFinalSizeMinValue (minl);
+  }
+  else
+    if (detector.isFinalSizeTestOn ()) detector.switchFinalSizeTest ();
+  detector.detectAll ();
+  std::vector<BlurredSegment *> bss;
+  if (detector.isNFA ()) bss = detector.getValidSegments ();
+  else bss = detector.getBlurredSegments ();
+  std::vector<BlurredSegment *>::iterator it = bss.begin ();
+  cl = 0.0;
+  while (it != bss.end ())
+  {
+    cl += sqrt ((*it)->getSquarredLength ());
+    DigitalStraightSegment ds ((*it)->getSegment ());
+    if (isNaive) ds.setNaive ();
+    dss.push_back (ds);
+    it ++;
+  }
+  return (((int) (dss.size ())));
+}
+
+
+int cardinal (const vector<DigitalStraightSegment> &dss, int w, int h)
+{
+  int nb = 0;
+  bool cmap[w * h];
+  for (int i = 0; i < w * h; i++) cmap[i] = false;
+  vector<DigitalStraightSegment>::const_iterator it = dss.begin ();
+  while (it != dss.end ())
+  {
+    vector<Pt2i> pts;
+    it->getPoints (pts);
+    vector<Pt2i>::iterator pit = pts.begin ();
+    while (pit != pts.end ())
+    {
+      if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h
+          && ! cmap[pit->x() + pit->y() * w])
+      {
+        nb ++;
+        cmap[pit->x() + pit->y() * w] = true;
+      }
+      pit++;
+    }
+    it++;
+  }
+  return nb;
+}
+
+
+int cover (const vector<DigitalStraightSegment> &bck,
+           const vector<DigitalStraightSegment> &frt, int w, int h)
+{
+  bool cmap[w * h];
+  for (int i = 0; i < w * h; i++) cmap[i] = false;
+  vector<DigitalStraightSegment>::const_iterator it = bck.begin ();
+  while (it != bck.end ())
+  {
+    DigitalStraightSegment *ds = it->dilation (1 * it->standard ());
+    vector<Pt2i> pts;
+    ds->getPoints (pts);
+    vector<Pt2i>::iterator pit = pts.begin ();
+    while (pit != pts.end ())
+    {
+      if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h)
+        cmap[pit->x() + pit->y() * w] = true;
+      pit++;
+    }
+    delete ds;
+    it++;
+  }
+
+  int nb = 0;
+  it = frt.begin ();
+  while (it != frt.end ())
+  {
+    vector<Pt2i> pts;
+    it->getPoints (pts);
+    vector<Pt2i>::iterator pit = pts.begin ();
+    while (pit != pts.end ())
+    {
+      if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h
+          && cmap[pit->x() + pit->y() * w])
+      {
+        nb++;
+        cmap[pit->x() + pit->y() * w] = false;  // To avoid counting twice
+      }
+      pit ++;
+    }
+    it ++;
+  }
+  return nb;
+}
+
+
+void create (QString name, const vector<DigitalStraightSegment> &bck,
+             const vector<DigitalStraightSegment> &frt, int w, int h)
+{
+  QImage im (w, h, QImage::Format_RGB32);
+  for (int j = 0; j < h; j++)
+    for (int i = 0; i < w; i++)
+      im.setPixel (i, j, 255 * 256 * 256 + 255 * 256 + 255);
+  vector<DigitalStraightSegment>::const_iterator it = bck.begin ();
+  while (it != bck.end ())
+  {
+    DigitalStraightSegment *ds = it->dilation (it->standard ());
+    vector<Pt2i> pts;
+    ds->getPoints (pts);
+    vector<Pt2i>::iterator pit = pts.begin ();
+    while (pit != pts.end ())
+    {
+      if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h)
+        im.setPixel (pit->x (), pit->y (), 255 * 256 * 256);
+      pit++;
+    }
+    delete ds;
+    it++;
+  }
+
+  it = frt.begin ();
+  while (it != frt.end ())
+  {
+    vector<Pt2i> pts;
+    it->getPoints (pts);
+    vector<Pt2i>::iterator pit = pts.begin ();
+    while (pit != pts.end ())
+    {
+      if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h)
+        im.setPixel (pit->x (), pit->y (),
+          ((im.pixelColor (pit->x (), pit->y ())).green () < 200 ?
+           0 : 255));
+      pit ++;
+    }
+    it ++;
+  }
+  im.save (name);
+}
+
+
+int main (int argc, char *argv[])
+{
+  QImage im;
+  if (! im.load (QString ("Data/image.jpg")))
+  {
+    cout << "No Data/image.png found" << endl;
+    return 0;
+  }
+  int w = im.width ();
+  int h = im.height ();
+
+  if (argc >= 2 && string (argv[1]) == string ("time"))
+  {
+    int repetitions = REPETITIONS;
+    if (argc == 3)
+    {
+      repetitions = atoi (argv[2]);
+      cout << "Repetitions set to " << repetitions << endl;
+    }
+    int **tabImage = new int*[h];
+    for (int i = 0; i < h; i++)
+    {
+      tabImage[i] = new int[w];
+      for(int j = 0; j < w; j++)
+      {
+        QColor c = QColor (im.pixel (j, h - i - 1));
+        tabImage[i][j] = c.value ();
+      }
+    }
+    BSDetector detector;
+    VMap *gMap = NULL;
+    clock_t start = clock ();
+    for (int i = 0; i < repetitions; i++)
+    {
+      if (gMap != NULL) delete gMap;
+      gMap = new VMap (w, h, tabImage, VMap::TYPE_SOBEL_5X5);
+      detector.setGradientMap (gMap);
+      detector.detectAll ();
+    }
+    double diff = (clock () - start) / (double) CLOCKS_PER_SEC;
+    ofstream outf ("Data/fbsdperf.txt", ios::out);
+    outf << diff << endl;
+    outf.close ();
+    return (EXIT_SUCCESS);
+  }
+
+  double cln = 0.0;  // cumulated length
+  vector<DigitalStraightSegment> dss;
+  int nbs = 0;
+  if (string (argv[1]) == string ("fbsd"))
+    nbs = genDssFromImage (dss, cln, im, MIN_LENGTH, false);
+  else if (string (argv[1]) == string ("naive"))
+    nbs = genDssFromImage (dss, cln, im, MIN_LENGTH, true);
+  else if (string (argv[1]) == string ("canny"))
+    nbs = genDssFromLines (dss, cln, h, MIN_LENGTH, "Data/detLines.txt", 5);
+  else if (string (argv[1]) == string ("ed"))
+    nbs = genDssFromLines (dss, cln, h, MIN_LENGTH, "Data/detLines.txt", 4);
+  else if (string (argv[1]) == string ("lsd"))
+    nbs = genDssFromLines (dss, cln, h, MIN_LENGTH, "Data/detLines.txt", 7);
+  if (nbs == 0)
+  {
+    cout << "No line extracted for " << argv[1] << endl;
+    return 0;
+  }
+
+  double gtl = 0.0;
+  int ngt = 0, nl = 0, nigt = 0, nil = 0;
+  vector<DigitalStraightSegment> gt;
+  if (genDssFromLines (gt, gtl, h, 0, "Data/gtLines.txt", 4) != 0)
+  {
+    ngt = cardinal (gt, w, h);
+    nl = cardinal (dss, w, h);
+    nigt = cover (dss, gt, w, h);  // R = nigt / ngt
+    nil = cover (gt, dss, w, h);   // P = nil / nl
+    if (DBG != 0)
+    {
+      create (QString ("Data/recall.png"), dss, gt, w, h);
+      create (QString ("Data/precision.png"), gt, dss, w, h);
+    }
+  }
+
+  ofstream outf ("Data/result.txt", ios::out);
+  if (outf.is_open ())
+  {
+    outf << nbs << " " << cln << " "
+         << nigt << " " << ngt << " " << nil << " " << nl << endl;
+    outf.close ();
+  }
+}
+
+
diff --git a/Expes/YorkUrbanDB/Scripts/precstat.sh b/Expes/YorkUrbanDB/Scripts/precstat.sh
new file mode 100644
index 0000000..7d67ad7
--- /dev/null
+++ b/Expes/YorkUrbanDB/Scripts/precstat.sh
@@ -0,0 +1,17 @@
+\cp /home/even/Expes/YorkUrbanDB/Images/$1/$1.jpg /home/even/Expes/Testers/TestLines/Data/image.jpg
+\cp /home/even/Expes/YorkUrbanDB/lines/yorklines/$1Lines.txt /home/even/Expes/Testers/TestLines/Data/gtLines.txt
+cd /home/even/Expes/Testers/TestLines
+./TestLines fbsd
+cat Data/result.txt >> /home/even/Expes/YorkUrbanDB/data/fbsdprec.txt
+./TestLines naive
+cat Data/result.txt >> /home/even/Expes/YorkUrbanDB/data/naiveprec.txt
+\cp /home/even/Expes/YorkUrbanDB/lines/cannylines/output/$1.txt /home/even/Expes/Testers/TestLines/Data/detLines.txt
+./TestLines canny
+cat Data/result.txt >> /home/even/Expes/YorkUrbanDB/data/cannyprec.txt
+\cp /home/even/Expes/YorkUrbanDB/lines/edlines/output/$1.txt /home/even/Expes/Testers/TestLines/Data/detLines.txt
+./TestLines ed
+cat Data/result.txt >> /home/even/Expes/YorkUrbanDB/data/edprec.txt
+\cp /home/even/Expes/YorkUrbanDB/lines/lsdlines/output/$1.txt /home/even/Expes/Testers/TestLines/Data/detLines.txt
+./TestLines lsd
+cat Data/result.txt >> /home/even/Expes/YorkUrbanDB/data/lsdprec.txt
+cd /home/even/Expes/YorkUrbanDB/data
diff --git a/Expes/YorkUrbanDB/Scripts/precstats.sh b/Expes/YorkUrbanDB/Scripts/precstats.sh
new file mode 100644
index 0000000..63b1ae8
--- /dev/null
+++ b/Expes/YorkUrbanDB/Scripts/precstats.sh
@@ -0,0 +1,112 @@
+\rm /home/even/Expes/YorkUrbanDB/data/lsdprec.txt
+\rm /home/even/Expes/YorkUrbanDB/data/edprec.txt
+\rm /home/even/Expes/YorkUrbanDB/data/cannyprec.txt
+\rm /home/even/Expes/YorkUrbanDB/data/naiveprec.txt
+\rm /home/even/Expes/YorkUrbanDB/data/fbsdprec.txt
+touch /home/even/Expes/YorkUrbanDB/data/lsdprec.txt
+touch /home/even/Expes/YorkUrbanDB/data/edprec.txt
+touch /home/even/Expes/YorkUrbanDB/data/cannyprec.txt
+touch /home/even/Expes/YorkUrbanDB/data/naiveprec.txt
+touch /home/even/Expes/YorkUrbanDB/data/fbsdprec.txt
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020171
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020177
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020816
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020817
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020819
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020822
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020824
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020825
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020826
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020828
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020829
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020830
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020831
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020833
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020838
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020839
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020841
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020845
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020847
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020848
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020854
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020856
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020860
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020861
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020867
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020871
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020872
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020887
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020912
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1020928
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1030001
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1030004
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040779
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040783
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040788
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040795
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040798
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040801
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040811
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040812
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040813
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040814
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040815
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040817
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040818
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040819
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040822
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040823
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040825
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040826
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040829
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040833
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040839
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040843
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040845
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040850
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040853
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040854
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040855
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040856
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040860
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040862
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040863
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1040870
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080005
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080008
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080011
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080015
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080018
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080020
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080021
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080023
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080025
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080031
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080032
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080033
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080036
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080045
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080047
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080049
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080053
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080055
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080056
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080057
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080062
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080063
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080074
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080077
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080078
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080079
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080084
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080091
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080092
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080093
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080096
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080100
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080104
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080106
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080111
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080113
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080116
+source /home/even/Expes/YorkUrbanDB/Scripts/precstat.sh P1080119
diff --git a/Expes/YorkUrbanDB/Scripts/ytimes.c b/Expes/YorkUrbanDB/Scripts/ytimes.c
new file mode 100644
index 0000000..3ebf161
--- /dev/null
+++ b/Expes/YorkUrbanDB/Scripts/ytimes.c
@@ -0,0 +1,159 @@
+// Compilation : cc -o ytimes ytimes.c
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+#define EXPES_DIR "/home/even/Expes/"
+#define FBSD_DIR "Testers/TestLines/"
+#define YORK_DIR "YorkUrbanDB/"
+#define DATA_DIR "data/"
+#define LSD_DIR "Timers/lsd/"
+#define ED_DIR "Timers/edlines/"
+#define CANNY_DIR "Timers/cannylines/"
+#define IMAGE_NAMES "yorkImages.txt"
+#define SCRIPT_NAME "exectimes.sh"
+#define NBMAX 200
+
+
+void tirage (int *ordre)
+{
+  int nb = 4, val;
+  int choix[] = {0, 1, 2, 3};
+  while (nb > 1)
+  {
+    val = rand () % nb;
+    *ordre++ = choix[val];
+    choix[val] = choix[--nb];
+  }
+  *ordre = choix[0];
+}
+
+int main (int argc, char *argv[])
+{
+  FILE *fim = NULL;
+  FILE *fcom = NULL;
+  char val[NBMAX];
+  char *ims[NBMAX];
+  int tir[4];
+  int w, h;
+  int nb = 0;
+  int nstart = 0, nend = 0;
+
+  srand (time (NULL));
+  if (argc != 3)
+  { 
+    fprintf (stdout, "Usage : yorktimes <num_start> <num_end>\n");
+    return (0);
+  }
+  sscanf (argv[1], "%d", &nstart);
+  sscanf (argv[2], "%d", &nend);
+  nstart --;
+  nend --;
+  if ((fim = fopen (IMAGE_NAMES, "r")) == NULL)
+  {
+    fprintf (stderr, "No file %s\n", IMAGE_NAMES);
+    return (0);
+  }
+  fscanf (fim, "%d", &w);
+  fscanf (fim, "%d", &h);
+  while (fscanf (fim, "%s", val) != -1)
+  {
+    ims[nb] = (char *) malloc (strlen (val) * sizeof (char) + 1);
+    strcpy (ims[nb++], val);
+  }
+  fclose (fim);
+  if ((fcom = fopen (SCRIPT_NAME, "w")) == NULL)
+  {
+    fprintf (stderr, "Unable to create %s\n", SCRIPT_NAME);
+    return (0);
+  }
+  sprintf (val, "cd %s%s", EXPES_DIR, YORK_DIR);
+  fprintf (fcom, "%s\n", val);
+  for (int i = nstart; i <= nend; i++)
+  {
+    tirage (tir);
+    for (int j = 0; j < 4; j++)
+    {
+      if (tir[j] == 0) // lsd
+      {
+        sprintf (val, "\\cp ImagesPGM/%s.pgm %s%stest.pgm",
+                 ims[i], EXPES_DIR, LSD_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, LSD_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "\\rm lsdperf.txt");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "echo 'TIMING %d (%s) on lsd'", (i+1), ims[i]);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "lsd");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cat lsdperf.txt >> %s%s%slsdtimes.txt",
+                 EXPES_DIR, YORK_DIR, DATA_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, YORK_DIR);
+        fprintf (fcom, "%s\n", val);
+      }
+      else if (tir[j] == 1) // ed
+      {
+        sprintf (val, "\\cp Images/%s/%s.jpg %s%stest.jpg",
+                 ims[i], ims[i], EXPES_DIR, ED_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, ED_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "\\rm edperf.txt");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "echo 'TIMING %d (%s) on ed'", (i+1), ims[i]);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "EDLines");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cat edperf.txt >> %s%s%sedtimes.txt",
+                 EXPES_DIR, YORK_DIR, DATA_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, YORK_DIR);
+        fprintf (fcom, "%s\n", val);
+      }
+      else if (tir[j] == 2) // canny
+      {
+        sprintf (val, "\\cp Images/%s/%s.jpg %s%stest.jpg",
+                 ims[i], ims[i], EXPES_DIR, CANNY_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, CANNY_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "\\rm cannyperf.txt");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "echo 'TIMING %d (%s) on canny'", (i+1), ims[i]);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "CannyLine");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cat cannyperf.txt >> %s%s%scannytimes.txt",
+                 EXPES_DIR, YORK_DIR, DATA_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, YORK_DIR);
+        fprintf (fcom, "%s\n", val);
+      }
+      else if (tir[j] == 3) // fbsd
+      {
+        sprintf (val, "\\cp Images/%s/%s.jpg %sData/image.jpg",
+                 ims[i], ims[i], FBSD_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s", FBSD_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "echo 'TIMING %d (%s) on fbsd'", (i+1), ims[i]);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "./TestLines time");
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cat Data/fbsdperf.txt >> %s%s%sfbsdtimes.txt",
+                 EXPES_DIR, YORK_DIR, DATA_DIR);
+        fprintf (fcom, "%s\n", val);
+        sprintf (val, "cd %s%s", EXPES_DIR, YORK_DIR);
+        fprintf (fcom, "%s\n", val);
+      }
+    }
+  }
+  sprintf (val, "cd %s", DATA_DIR);
+  fprintf (fcom, "%s\n", val);
+  fclose (fcom);
+  return (0);
+}
diff --git a/Expes/YorkUrbanDB/data/moyennes/mprec.c b/Expes/YorkUrbanDB/data/moyennes/mprec.c
new file mode 100644
index 0000000..627cf44
--- /dev/null
+++ b/Expes/YorkUrbanDB/data/moyennes/mprec.c
@@ -0,0 +1,136 @@
+// Compilation : cc -o mprec mprec.c -lm
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <math.h>
+
+#define YORK_NB 102
+#define NB_DATA 6
+#define NB_DETS 5
+#define LSD_NAME "LSD"
+#define ED_NAME "ED"
+#define CANNY_NAME "CANNY"
+#define NAIVE_NAME "NAIVE"
+#define FBSD_NAME "FBSD"
+#define LSD_LN "lsdprec.txt"
+#define ED_LN "edprec.txt"
+#define CANNY_LN "cannyprec.txt"
+#define NAIVE_LN "naiveprec.txt"
+#define FBSD_LN "fbsdprec.txt"
+
+
+int main (int argc, char *argv[])
+{
+  double nvals[NB_DETS][YORK_NB];
+  double lvals[NB_DETS][YORK_NB];
+  double rvals[NB_DETS][YORK_NB];
+  double trvals[NB_DETS][YORK_NB];
+  double pvals[NB_DETS][YORK_NB];
+  double tpvals[NB_DETS][YORK_NB];
+  double *val = NULL;
+  double nm[NB_DETS];   // Number of lines
+  double nsig[NB_DETS];
+  double lm[NB_DETS];   // Cumulated length per image
+  double lsig[NB_DETS];
+  double lnm[NB_DETS];  // Mean length
+  double lnsig[NB_DETS];
+  double rm[NB_DETS];   // Recall
+  double rsig[NB_DETS];
+  double pm[NB_DETS];   // Precision
+  double psig[NB_DETS];
+  double fm[NB_DETS];   // F-measure
+  double fsig[NB_DETS];
+  int nb = 0;
+  FILE *pf = NULL;
+
+  char *names[20] = {LSD_NAME, ED_NAME, CANNY_NAME, NAIVE_NAME, FBSD_NAME};
+  char *files[20] = {LSD_LN, ED_LN, CANNY_LN, NAIVE_LN, FBSD_LN};
+  
+  for (int j = 0; j < NB_DETS; j++)
+  {
+    nm[j] = 0.;
+    lm[j] = 0.;
+    lnm[j] = 0.;
+    rm[j] = 0.;
+    pm[j] = 0.;
+    fm[j] = 0.;
+    nsig[j] = 0.;
+    lsig[j] = 0.;
+    lnsig[j] = 0.;
+    rsig[j] = 0.;
+    psig[j] = 0.;
+    fsig[j] = 0.;
+
+    if ((pf = fopen (files[j], "r")) == NULL)
+    {
+      fprintf (stderr, "Pas de fichier %s\n", files[j]);
+      return (0);
+    }
+    val = nvals[j];
+    nb = 0;
+    for (int i = 0; i < YORK_NB; i ++);
+    while (fscanf (pf, "%lf", val) != -1)
+    {
+      nb ++;
+      if (nb % NB_DATA == 1) val = lvals[j] + nb / NB_DATA;
+      else if (nb % NB_DATA == 2) val = rvals[j] + nb / NB_DATA;
+      else if (nb % NB_DATA == 3) val = trvals[j] + nb / NB_DATA;
+      else if (nb % NB_DATA == 4) val = pvals[j] + nb / NB_DATA;
+      else if (nb % NB_DATA == 5) val = tpvals[j] + nb / NB_DATA;
+      else (val = nvals[j] + nb / NB_DATA);
+    }
+    fclose (pf);
+
+    // Computes means
+    for (int i = 0; i < YORK_NB; i ++)
+    {
+      nm[j] += nvals[j][i];
+      lm[j] += lvals[j][i];
+      lnm[j] += lvals[j][i] / nvals[j][i];
+      rm[j] += rvals[j][i] / trvals[j][i];
+      pm[j] += pvals[j][i] / tpvals[j][i];
+      fm[j] += 2 * rvals[j][i] * pvals[j][i]
+               / (rvals[j][i] * tpvals[j][i] + pvals[j][i] * trvals[j][i]);
+    }
+    nm[j] /= YORK_NB;
+    lm[j] /= YORK_NB;
+    lnm[j] /= YORK_NB;
+    rm[j] /= YORK_NB;
+    pm[j] /= YORK_NB;
+    fm[j] /= YORK_NB;
+
+    // Computes standard deviations
+    for (int i = 0; i < YORK_NB; i ++)
+    {
+      nsig[j] += (nvals[j][i] - nm[j]) * (nvals[j][i] - nm[j]);
+      lsig[j] += (lvals[j][i] - lm[j]) * (lvals[j][i] - lm[j]);
+      double term = lvals[j][i] / nvals[j][i] - lnm[j];
+      lnsig[j] += term * term;
+      term = rvals[j][i] / trvals[j][i] - rm[j];
+      rsig[j] += term * term;
+      term = pvals[j][i] / tpvals[j][i] - pm[j];
+      psig[j] += term * term;
+      term = 2 * rvals[j][i] * pvals[j][i]
+             / (rvals[j][i] * tpvals[j][i] + pvals[j][i] * trvals[j][i])
+             - fm[j];
+      fsig[j] += term * term;
+    }
+    nsig[j] = sqrt (nsig[j] / (YORK_NB - 1));
+    lsig[j] = sqrt (lsig[j] / (YORK_NB - 1));
+    lnsig[j] = sqrt (lnsig[j] / (YORK_NB - 1));
+    rsig[j] = sqrt (rsig[j] / (YORK_NB - 1));
+    psig[j] = sqrt (psig[j] / (YORK_NB - 1));
+    fsig[j] = sqrt (fsig[j] / (YORK_NB - 1));
+
+    fprintf (stdout, "Detecteur %s\n", names[j]);
+    fprintf (stdout, "  N   = %lf (%lf)\n", nm[j], nsig[j]);
+    fprintf (stdout, "  L   = %lf (%lf)\n", lm[j], lsig[j]);
+    fprintf (stdout, "  L/N = %lf (%lf)\n", lnm[j], lnsig[j]);
+    fprintf (stdout, "  R   = %lf (%lf)\n", rm[j], rsig[j]);
+    fprintf (stdout, "  P   = %lf (%lf)\n", pm[j], psig[j]);
+    fprintf (stdout, "  F   = %lf (%lf)\n", fm[j], fsig[j]);
+  }
+  return (1);
+}
diff --git a/Ipol/paper/Algos/algoAuto.tex b/Ipol/paper/Algos/algoAuto.tex
index f35772a..bc0a6ea 100644
--- a/Ipol/paper/Algos/algoAuto.tex
+++ b/Ipol/paper/Algos/algoAuto.tex
@@ -1,5 +1,5 @@
 \begin{algorithm}[!htbp]
-\caption{detectAuto}
+\caption{detectAll}
 
 \SetKwData{takes}{$\leftarrow$}
 \SetKwData{resol}{$\delta$}
diff --git a/Ipol/paper/Algos/algoInitial.tex b/Ipol/paper/Algos/algoInitial.tex
index aa1cafe..187bec5 100644
--- a/Ipol/paper/Algos/algoInitial.tex
+++ b/Ipol/paper/Algos/algoInitial.tex
@@ -4,6 +4,9 @@
 
 \SetKwData{takes}{$\leftarrow$}
 \SetKwData{is}{$P_1P_2$}
+\SetKwData{vis}{$\overrightarrow{P_1P_2}$}
+\SetKwData{scancenter}{$C$}
+\SetKwData{scanwidth}{$\omega$}
 \SetKwData{ath}{$\varepsilon$}
 %\SetKwData{on}{isExtending}
 \SetKwData{nb}{$n$}
@@ -29,12 +32,17 @@
 \SetKwFunction{addpt}{addPoint}
 
 \Input{gradient magnitude map \gmap, input segment \is,
-       maximal thickness \ath,
+       scan center \scancenter, scan width \scanwidth, maximal thickness \ath,
        maximal amount of successive detection fails \imax}
 \Output{a detected blurred segment \bs}
 
 \bs \takes $\emptyset$\;
-\ds \takes \getds (\is) \Comment*{Gets a DS from input segment.}
+\eIf{\scanwidth $=$ $0$}{
+  \ds \takes \getds (\is) \Comment*{Gets a DS from input segment.}
+}{
+  \ds \takes \getds (\scancenter, \vis, \scanwidth)
+  \Comment*{Gets a DS from center, direction and width.}
+}
 \scan \takes \fscan (\ds)\;
 \index \takes \largest (\scan, \gmap, \gmin)
 \Comment*{Gets index of pixel with max gradient.}
diff --git a/Ipol/paper/Algos/algoMulti.tex b/Ipol/paper/Algos/algoMulti.tex
index ed0a52c..590e6b0 100644
--- a/Ipol/paper/Algos/algoMulti.tex
+++ b/Ipol/paper/Algos/algoMulti.tex
@@ -36,7 +36,7 @@
 \BlankLine
 \For{\index \takes $0$ \KwTo \size(\lm)}{
   \If{\mask $[$ \lm $[$ \index $]]$ $=$ false}{ 
-    \bs \takes \detect (\gmap, \vmap, \lm[i], \ortho, \eps)
+    \bs \takes \detect (\gmap, \vmap, \ortho, \lm[i], \eps)
     \Comment*{Searches a segment at local max position.}
     \mask \takes \updatemask (\mask, \bs)
     \Comment*{Updates occupancy mask with dilated blurred segment.}
diff --git a/Ipol/paper/Algos/algoSingle.tex b/Ipol/paper/Algos/algoSingle.tex
index 381e92c..e178dca 100644
--- a/Ipol/paper/Algos/algoSingle.tex
+++ b/Ipol/paper/Algos/algoSingle.tex
@@ -4,6 +4,8 @@
 
 \SetKwData{takes}{$\leftarrow$}
 \SetKwData{is}{$P_1P_2$}
+\SetKwData{scancenter}{$C$}
+\SetKwData{scanwidth}{$\omega$}
 \SetKwData{ath}{$\varepsilon$}
 \SetKwData{minsize}{$S_{min}$}
 \SetKwData{crossang}{$\alpha_{min}$}
@@ -26,10 +28,11 @@
 \SetKwFunction{startpt}{startPoint}
 
 \Input{gradient magnitude map \gmap, gradient orientation map \vmap,
-       input segment \is, assigned thickness \ath}
+       input segment \is, scan center \scancenter, scan width \scanwidth
+       and assigned thickness \ath}
 \Output{a detected blurred segment \bs}
 
-\bs \takes \fasttrack (\gmap, \is, \ath)
+\bs \takes \fasttrack (\gmap, \is, \scancenter, \scanwidth, \ath)
 \Comment*{Gets rough initial solution.}
 \eIf{\sizebs $<$ \minsize}{
   \bs \takes $\emptyset$ \Comment*{Not enough points.}
diff --git a/Ipol/paper/algos.tex b/Ipol/paper/algos.tex
index 47ca152..b478813 100644
--- a/Ipol/paper/algos.tex
+++ b/Ipol/paper/algos.tex
@@ -17,24 +17,27 @@ supervised control tasks.
 
 \subsection{Initial detection step of single extraction}
 
-The input of this step is a line segment, the input stroke,
+The main input of this step is a line segment, the input stroke,
 and the output is a blurred segment crossed by the input stroke.
+The first scan can be initialized either directly by the input stroke,
+or by the scan center, direction and width. A null width must be
+specified in the first case.
 The process is detailed in algorithm~\ref{algo:initial}.
 Candidate points for blurred segment extension are selected on the basis
 of maximal gradient magnitude.
-Because the goal is to provide an initial incomplete solution, the blurred
-segment is bounded to a small size.
+Because the goal is to provide an initial rough solution, the blurred
+segment extension is bounded to a few scans.
 Further extension is considered as useless.
 On each side, the process stops after a fixed amount of successive extension
 fails.
 
+\input{Algos/algoInitial}
+
 Two parameters are used in this step:
 a minimal gradient magnitude $G_{min}$ to select candidates,
 a maximal extent $N_E$ of the blurred segment.
 Nominal values are proposed for them.
 
-\input{Algos/algoInitial}
-
 \subsection{Fine tracking step of single extraction}
 
 The input of this step is the direction of the rough blurred segment
@@ -50,6 +53,8 @@ center line at each step. This alignment is only performed after a
 predefined number of steps when the blurred segment direction gets
 stable enough.
 
+\input{Algos/algoFinal}
+
 Moreover when the growing segment stops thickenning, the assigned maximal
 thickness of the recognition algorithm is pinched to a near value to
 the observed thickness. This pinch procedure avoids further inclusion of
@@ -61,8 +66,6 @@ Finally, when any extension fail occurs, the amount of later successful
 extensions must coincide to the fail count to validate these points.
 This condition helps to detect more accurate segment ends.
 
-\input{Algos/algoFinal}
-
 Three parameters are used in this step:
 a gradient height $\delta_G$ to discriminate local gradient maxima,
 a minimal count $N_P$ of successive extents without blurred segment thickening,
@@ -71,9 +74,12 @@ Nominal values are proposed for all of them.
 
 \subsection{Single blurred segment extraction}
 
-The blurred segment extraction calls the initial detection, then the fine
-tracking steps and applies optional validation tests to the output segment.
-It is detailed in algorithm~\ref{algo:single}.
+The single blurred segment extraction calls the initial detection, then the
+fine tracking step and applies optional validation tests to the output
+segment.
+When extracting a single edge in interactive mode, the width input value is
+set to zero in order to directly use the input segment as first scan.
+The single extraction process is detailed in algorithm~\ref{algo:single}.
 
 \input{Algos/algoSingle}
 
@@ -113,3 +119,9 @@ algorithm~\ref{algo:auto}.
 
 \input{Algos/algoAuto}
 
+Only two parameters are left under user control: the sweeping step and the
+maximal thickess of extracted blurred segments. If the sweeping step is
+too large, many small segments may be missed. On the contrary, a too small
+value has no significant impact on the result because the occupancy mask
+avoids processing already extracted segments. It only coasts an extra search
+of local gradient magnitude maxima.
diff --git a/Methode/evals.tex b/Methode/evals.tex
index 83788bf..ed2f410 100755
--- a/Methode/evals.tex
+++ b/Methode/evals.tex
@@ -244,7 +244,35 @@ Comme il peut y avoir de grosses disparit\'es de longueurs de mise en
 correspondance, on calcule aussi un \'ecart angulaire global comme
 le rapport de la somme de tous les \'ecarts angulaires sur toutes les images 
 et de la longueur de toutes les longueurs de mise en correspondance sur
-toutes les images.
+toutes les images. \\
+
+{\bf Refonte pour IPOL (d\'ecembre 2020} \\
+Le script {\tt specstats.sh} charge successivement pour chaque image :
+\begin{itemize}
+\item l'image York dans {\tt FBSD/Data/image.jpg},
+\item les lignes York dans {\tt FBSD/Data/gtLines.txt},
+\item les lignes Canny, LSD ou ED dans {\tt FBSD/Data/detLines.txt},
+\end{itemize}
+puis appelle {\tt Testers/TestLines} qui charge la v\'erit\'e de terrain et
+lance les comparaisons.
+Les r\'esultats sont plac\'es dans {\tt YorkUrbanDB/data/} \`a
+l'int\'erieur de fichiers {\tt <det>prec.txt} qui contiennent pour chaque
+image
+\begin{itemize}
+\item le nombre de lignes,
+\item la longueur cumul\'ee sur l'image,
+\item le recall (bonnes d\'etections et nombre de pixels d\'etect\'es)
+\item et la pr\'ecision (bonnes d\'etections et nombre de pixels de la
+v\'erit\'e de terrain).
+\end{itemize}
+La moyenne sur ces mesures peut ensuite \^etre obtenue par le script
+{\tt data/moyennes/mprec}.
+
+L'ex\'ecutable {\tt ytimes} a le m\^eme r\^ole que {\tt yorktimes}, mais
+lance {\tt Testers/TestLines} au lieu de {\tt FBSD}. Dans ces 4 scripts,
+on appelle la fonction C {\tt clock} et non la classe C++ {\tt chrono},
+car LSD ne compile pas avec C++. Dans ces testeurs, il est possible de
+changer le nombre de r\'ep\'etitions par un argument en ligne de commande.
 
 \section{Tests sur images de synth\`ese}
 
-- 
GitLab