Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

Commit [133e1d] gsoc2011_onomou Maximize Restore History

Will not compile - help?

onomou onomou 2011-08-10

added src/hugin_base/panodata/ControlLine.h
changed src/hugin1/hugin/CMakeLists.txt
changed src/hugin1/hugin/CPEditorPanel.h
changed src/hugin_base/panodata/PanoramaData.h
copied src/hugin1/hugin/CPSharedStructs.h -> src/hugin_base/panodata/ControlLine.cpp
src/hugin_base/panodata/ControlLine.h Diff Switch to side-by-side view
Loading...
src/hugin1/hugin/CMakeLists.txt Diff Switch to side-by-side view
Loading...
src/hugin1/hugin/CPEditorPanel.h Diff Switch to side-by-side view
Loading...
src/hugin_base/panodata/PanoramaData.h Diff Switch to side-by-side view
Loading...
src/hugin1/hugin/CPSharedStructs.h to src/hugin_base/panodata/ControlLine.cpp
--- a/src/hugin1/hugin/CPSharedStructs.h
+++ b/src/hugin_base/panodata/ControlLine.cpp
@@ -20,396 +20,462 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-
-
-
-/* Notes to self regarding straight lines
-
-Straight lines in Hugin are used for two things:
-    Matching control points (and eventually being a separate class for image alignment)
-    Calibrating a lens
-    
-Straight line inputs are line points:
-    Start
-    Mid
-    End
-
-Straight line outputs are:
-    A list of control points
-    
-Straight line interactions are:
-    Mouse rolls over a line
-    Mouse clicks a line
-    Mouse clicks a point (from line inputs)
-    Deleting a point (from line inputs)
-    Mouse distance from:
-        The line path
-        A point (from line inputs)
-    
-Automated processes:
-    Find edges near line
-    Fine-tune line using:
-        Edges
-        Other feature detection
-        
-
-Overall straight line control:
-    Adding a new line
-        
-    Deleting an existing line
-    
-    Selecting a specific line (activating)
-        By index (from a list)
-        By proximity (get distance from mouse to each line)
-    Editing a specific line
-        By proximity (get distance from mouse to each point on each line)
-            Activate line closest to mouse
-                Activate point on active line
-                    Input:
-                        Click to select point
-                            Move selected point with mouse
-                                Click to place point (deselect)
-                        Keyboard arrows highlight point
-                        Keyboard Return selects highlighted point
-                            Keyboard arrows move point
-                             Keyboard Return places point (deselect)
-
-
-*/
-
-class StraightLine
-{
-    public:
-        /* Variables */
-    
-        // Note: be careful to not feed these rotated and scaled points - do those actions in the environment
-        hugin_utils::FDiff2D start, mid, end;
-        
-        hugin_utils::FDiff2D center;
-        double radius, thetaStart, thetaEnd;
-        unsigned int imageNr;
-        
-        /* Functions */
-        StraightLine(unsigned int);
-        bool operator==(const StraightLine &l) const {
-            return(    imageNr == l.imageNr    &&   center == l.center && radius == l.radius &&
-                    thetaStart == l.thetaStart && thetaEnd == l.thetaEnd                        );
-        }
-        
-        std::vector<ControlPoint> extractPathPoints(void);
-        bool addPoint(hugin_utils::FDiff2D);
-        void moveActivePoint(hugin_utils::FDiff2D);
-        double getDistance(hugin_utils::FDiff2D); // sets pointNear for future use
-        bool removePoint(int);
-        bool removeNearPoint(hugin_utils::FDiff2D);
-        void activateNearPoint(void);
-        
-    private:
-        /* Variables */
-        static const double tolerance;
-        double thetaMid;
-        bool isStraight;
-        bool startSet, midSet, endSet;
-        enum whichPoint {NONE=0, START, MID, END};
-        whichPoint pointActive, pointNear;
-        bool lineActive;
-        std::vector<hugin_utils::FDiff2D> points; // not implemented
-    
-        /* Functions */
-        void recalculate(void);
-};
-
-StraightLine::StraightLine(unsigned int nr):tolerance(3.e-10)
+#include "hugin_basic.h"
+#include <panotools/PanoToolsInterface.h>
+#include "ControlLine.h"
+
+#ifndef PI
+#define PI 3.14159
+#endif
+#define Point hugin_utils::FDiff2D
+
+StraightLine::StraightLine(unsigned int nr) : tolerance(3.e-10), selectionDistance(30)
 {
     imageNr = nr;
     isStraight = true;
+    isOverLine = false;
     
       startSet = false;
         midSet = false;
         endSet = false;
     
-    pointActive = 0;
-    pointNear   = 0;
-    
-    lineActive  = false;
-}
-
-std::vector<ControlPoint> StraightLine::extractPathPoints(void)
-{
-    std::vector<ControlPoint> cpoints;
-    
-    
-    //double prevx = radius * cos( thetaStart ) + center.x;
-    //double prevy = radius * sin( thetaStart ) + center.y;
-    hugin_utils::FDiff2D dropPoint( radius * cos( thetaStart ) + center.x,
-                                    radius * sin( thetaStart ) + center.y );
-
-    newLine.points.clear();
-    cpoints.points.push_back(ControlPoint(dropPoint.x, dropPoint.y);
-    for( int i = 0; i <= 10; i++ ) {
-        // todo: change circle color for selected CPs
-        dropPoint.x = radius * cos( thetaStart + i*step ) + center.x;
-        dropPoint.y = radius * sin( thetaStart + i*step ) + center.y;
-        newLine.points.push_back(applyRotInv(invScale(dropPoint)));
-        //drawPoint(dc, invScale(applyRotInv(dropPoint)), 0, false);
-        dc.DrawLine( hugin_utils::roundi(prevx),       hugin_utils::roundi(prevy),
-                     hugin_utils::roundi(dropPoint.x), hugin_utils::roundi(dropPoint.y) );
-        dc.DrawCircle(roundP(dropPoint), 5);
-        prevx = dropPoint.x;
-        prevy = dropPoint.y;
-    }
-    
-    
-    
-    
-    
-    cpoints.push_back
-}
-
-bool StraightLine::addPoint(hugin_utils::FDiff2D point)
-{
-    if( isUnique(point) ) {
-        if( startSet ) {
-            if( midSet ) {
-                if( endSet ) {
-                    return false;
+    pointSelected = NONE;
+    pointNear     = NONE;
+    
+    lineSelected  = false;
+    
+    numpoints = 10;
+}
+
+std::vector<Point> StraightLine::extractPathPoints(void)
+{
+    std::vector<Point> cpoints;
+    Point dropPoint;
+    
+    switch( pointsAdded )
+    {
+        case NONE:
+            break;
+        case START:
+            cpoints.push_back(Point(start.x, start.y));
+            break;
+        case MID:
+            for( double i = 0; i <= 10; i++ ) {
+                dropPoint.x = start.x + (mid.x - start.x) * i / 10;
+                dropPoint.y = start.y + (mid.y - start.y) * i / 10;
+                cpoints.push_back(dropPoint);
+            }
+            break;
+        case END:
+            double step = (thetaEnd - thetaStart) / numpoints;
+            for( double i = 0; i <= 10; i++ ) {
+                dropPoint.x = radius * cos( thetaStart + i*step ) + center.x;
+                dropPoint.y = radius * sin( thetaStart + i*step ) + center.y;
+                cpoints.push_back(dropPoint);
+            }
+            break;
+    }
+    
+    return cpoints;
+}
+
+bool StraightLine::addPoint(Point point)
+{
+    // todo:
+    //if( !isUnique(point) )
+    //    return false;
+    switch( pointsAdded )
+    {
+        case NONE:  start = point; pointsAdded = START; break;
+        case START:   mid = point; pointsAdded = MID;   break;
+        case MID:     end = point; pointsAdded = END;   break;
+        case END:                  return false;
     }
     recalculate();
-}
-
-void moveActivePoint(hugin_utils::FDiff2D point)
-{
-    switch( pointActive )
-    {
-        case NONE: break;
-            //return false;
-        case START:
-            start = point; break;
-        case MID:
-              mid = point; break;
-        case END:
-              end = point; break;
-    }
-    //return true;
-}
-
-double StraightLine::getDistance(hugin_utils::FDiff2D point)
-{
-    
-    pointNear = NONE;
-}
-
-bool StraightLine::removePoint(int whichPoint)
-{
-    if( whichPoint < 1 || whichPoint > 3 ) {
+    return true;
+}
+
+void StraightLine::moveActivePoint(Point destination)
+{
+    switch( pointSelected )
+    {
+        case NONE:                       break;
+        case START: start = destination; break;
+        case MID:     mid = destination; break;
+        case END:     end = destination; break;
+    }
+}
+
+double StraightLine::getNearestPointDistance(Point point)
+{
+    double nearest, tmp;
+    pointNear = START;
+    nearest = point.squareDistance(start);
+    tmp = point.squareDistance(mid);
+    if( tmp < nearest ) {
+        nearest = tmp;
+        pointNear = MID;
+    }
+    tmp = point.squareDistance(end);
+    if( tmp < nearest ) {
+        nearest = tmp;
+        pointNear = END;
+    }
+    if( selectionDistance * selectionDistance < nearest )
+        pointNear = NONE;
+    return nearest;
+}
+
+double StraightLine::getLineDistance(Point point)
+{
+    switch( pointsAdded )
+    {
+        case NONE:  return 0;
+        case START: return point.squareDistance(start);
+        case MID:   return abs((mid.x-start.x)*(start.y-point.y)-(start.x-point.x)*(mid.y-start.y))/
+                            sqrt((mid.x-start.x)*(mid.x-start.x)+(mid.y-start.y)*(mid.y-start.y));
+        case END:   return abs(point.squareDistance(start) - radius);
+    }
+}
+/*
+bool StraightLine::removePoint(int point)
+{
+    if( point < 1 || point > 3 ) {
         return false;
     } else {
-        if( whichPoint == 1 ) {
+        if( point == 1 ) {
           startSet = false;
-        } else if( whichPoint == 2 ) {
+        } else if( point == 2 ) {
             midSet = false;
-        } else if( whichPoint == 3 ) {
+        } else if( point == 3 ) {
             endSet = false;
         }
         return true;
     }
 }
-
-bool StraightLine::removeNearPoint(hugin_utils::FDiff2D point)
-{
-    getDistance( point );
+*/
+
+bool StraightLine::removeLastPoint(void)
+{
+    switch(pointsAdded)
+    {
+        case NONE:                       return false;
+        case START: pointsAdded = NONE;  return true;
+        case MID:   pointsAdded = START; return true;
+        case END:   pointsAdded = MID;   return true;
+    }
+    
+}
+
+// todo: the current structure does not allow deleting the middle point intuitively
+//         ... perhaps reconfigure to use startSet, midSet, endSet instead of pointsAdded?
+bool StraightLine::removeNearPoint(Point point)
+{
+    if( pointsAdded != END )
+        return false;
+    getNearestPointDistance( point );
     switch( pointNear )
     {
         case NONE:
             return false;
         case START:
-          startSet = false; break;
+            start = end;
+            removeLastPoint();
+            return true;
         case MID:
-            midSet = false; break;
+            start = end;
+            pointsAdded = MID;
+            return true;
         case END:
-            endSet = false; break;
-    }
+            pointsAdded = MID;
+            return true;
+    }
+}
+
+inline void StraightLine::selectLastNearPoint(void)
+{
+    pointSelected = pointNear;
+    //if( pointSelected != NONE )?
+        lineSelected = true;
+}
+
+inline void StraightLine::deselectPoint(void)
+{ pointSelected = NONE; }
+
+inline void StraightLine::selectLine(void)
+{ lineSelected = true; }
+
+inline void StraightLine::deselectLine(void)
+{ lineSelected = false; }
+
+/*
+void StraightLine::update(Point location)
+{
+    double ldist = getLineDistance(location);
+    if( dist < selectionDistance ) {
+        isOverLine = true;
+        double pdist = getNearestPointDistance(location);
+        if( pdist < selectionDistance ) {
+            isOverPoint = pointNear; // probably redundant use of pointNear
+        }
+    } else {
+        isOverLine = false;
+        isOverPoint = NONE;
+    }
+}
+*/
+
+void StraightLine::recalculate(void)
+{
+    /* Fit a circle to the points set */
+    numpoints = 10;
+    switch( pointsAdded )
+    {
+        case NONE:
+            center.x = 0;   center.y = 0;
+            radius = 0;
+            isStraight = true;
+            break;
+        case START:
+            center = start;
+            radius = 0;
+            isStraight = true;
+            break;
+        case MID:
+            center = (start - mid) / 2;
+            radius = 0;
+            isStraight = true;
+            break;
+        case END:
+            Matrix3 matA, matD, matE, matF;
+            matA.m[0][0] = start.x;      matA.m[0][1] = start.y;      matA.m[0][2] = 1;
+            matA.m[1][0] =   mid.x;      matA.m[1][1] =   mid.y;      matA.m[1][2] = 1;
+            matA.m[2][0] =   end.x;      matA.m[2][1] =   end.y;      matA.m[2][2] = 1;
+            double a = matA.Determinant();
+            if( abs(a) < tolerance ) { // approximately straight line
+                center = (start - mid) / 2;
+                radius = 0;
+                isStraight = true;
+            } else {
+                /* Calculate center, radius */
+                isStraight = false;
+                matD.m[0][0] = (start.x * start.x) + (start.y * start.y);   matD.m[0][1] = start.y;   matD.m[0][2] = 1;
+                matD.m[1][0] = (  mid.x *   mid.x) + (  mid.y *   mid.y);   matD.m[1][1] =   mid.y;   matD.m[1][2] = 1;
+                matD.m[2][0] = (  end.x *   end.x) + (  end.y *   end.y);   matD.m[2][1] =   end.y;   matD.m[2][2] = 1;
+
+                matE.m[0][0] = (start.x * start.x) + (start.y * start.y);   matE.m[0][1] = start.x;   matE.m[0][2] = 1;
+                matE.m[1][0] = (  mid.x *   mid.x) + (  mid.y *   mid.y);   matE.m[1][1] =   mid.x;   matE.m[1][2] = 1;
+                matE.m[2][0] = (  end.x *   end.x) + (  end.y *   end.y);   matE.m[2][1] =   end.x;   matE.m[2][2] = 1;
+
+                matF.m[0][0] = (start.x * start.x) + (start.y * start.y);   matF.m[0][1] = start.x;   matF.m[0][2] = start.y;
+                matF.m[1][0] = (  mid.x *   mid.x) + (  mid.y *   mid.y);   matF.m[1][1] =   mid.x;   matF.m[1][2] =   mid.y;
+                matF.m[2][0] = (  end.x *   end.x) + (  end.y *   end.y);   matF.m[2][1] =   end.x;   matF.m[2][2] =   end.y;
+
+                double d = -matD.Determinant();
+                double e =  matE.Determinant();
+                double f = -matF.Determinant();
+
+                center.x = -d / ( 2 * a );
+                center.y = -e / ( 2 * a );
+                radius = sqrt((d*d+e*e)/(4*a*a)-f/a);
+                
+                /* Calculate angles and quadrant */
+                int quadStart, quadMid, quadEnd;
+                Point st = start - center, md = mid - center, ed = end - center;
+                findQuadrant(st, quadStart);
+                findQuadrant(md, quadMid  );
+                findQuadrant(ed, quadEnd  );
+                st.x = abs(st.x);     st.y = abs(st.y);
+                md.x = abs(md.x);     md.y = abs(md.y);
+                ed.x = abs(ed.x);     ed.y = abs(ed.y);
+                // should this skip the quadrant checks and use atan2 ?
+                thetaStart = atan(st.y/st.x);
+                thetaEnd   = atan(ed.y/ed.x);
+                double thetaMid = atan(md.y/md.x);
+                correctAngle(thetaStart, quadStart);
+                correctAngle(thetaMid,   quadMid  );
+                correctAngle(thetaEnd,   quadEnd  );
+                if( thetaStart < thetaMid && thetaStart < thetaEnd && thetaMid < thetaEnd ); // nothing to do
+                if( thetaStart < thetaMid && thetaStart < thetaEnd && thetaMid > thetaEnd ) {thetaStart += 2 * PI;}
+              //if( thetaStart < thetaMid && thetaStart > thetaEnd && thetaMid < thetaEnd ); // not possible
+                if( thetaStart < thetaMid && thetaStart > thetaEnd && thetaMid > thetaEnd ) {thetaEnd += 2 * PI;}
+                if( thetaStart > thetaMid && thetaStart < thetaEnd && thetaMid < thetaEnd ) {thetaEnd -= 2 * PI;}
+              //if( thetaStart > thetaMid && thetaStart < thetaEnd && thetaMid > thetaEnd ); // not possible
+                if( thetaStart > thetaMid && thetaStart > thetaEnd && thetaMid < thetaEnd ) {thetaEnd += 2 * PI;}
+                if( thetaStart > thetaMid && thetaStart > thetaEnd && thetaMid > thetaEnd ); // nothing to do
+                
+                numpoints = int( 2.7 * abs(thetaEnd - thetaStart) + 3 ); // range: 3 ... 20?
+            }
+            break;
+    }
+
+}
+
+void StraightLine::findQuadrant(Point pt, int &quad)
+{
+         if( pt.x >= 0 && pt.y >= 0 )
+        quad = 0; // first
+    else if( pt.x <  0 && pt.y >= 0 )
+        quad = 1; // second
+    else if( pt.x <  0 && pt.y <  0 )
+        quad = 2; // third
+    else if( pt.x >= 0 && pt.y <  0 )
+        quad = 3; // fourth
+}
+void StraightLine::correctAngle(double &theta, int quad)
+{
+         if( quad == 1 ) // quadrant 2
+             theta = -theta + PI;
+    else if( quad == 2 ) // quadrant 3
+        theta =  theta + PI;
+    else if( quad == 3 ) // quadrant 4
+        theta = -theta + PI * 2;
+    while( theta >= 0 )
+        theta -= 2 * PI;
+    theta += 2 * PI;
+}
+
+/* ------------------------------------------------------------- */
+
+LineCollection::LineCollection(void)
+{
+    selectionDistance = 30;
+}
+
+bool LineCollection::addPair(linePair p)
+{
+    // should check if line is a duplicate?
+    allLines.push_back(p);
     return true;
 }
 
-inline void StraightLine::activateNearPoint(void)
-{
-    pointActive = pointNear;
-}
-
-void StraightLine::recalculate(void)
-{
-    /* Fit a circle to the points in this structure */
-    Matrix3 matA, matD, matE, matF;
-    matA.m[0][0] = startx;                                     matA.m[0][1] = starty;      matA.m[0][2] = 1;
-    matA.m[1][0] =   midx;                                     matA.m[1][1] =   midy;      matA.m[1][2] = 1;
-    matA.m[2][0] =   endx;                                     matA.m[2][1] =   endy;      matA.m[2][2] = 1;
-    double a = matA.Determinant();
-    if( abs(a) < tolerance ) { // approximately straight line
-        isStraight = true;
+bool LineCollection::addPair(StraightLine l1, StraightLine l2)
+{
+    // should check if line is a duplicate?
+    linePair lp;
+    lp.first = l1;
+    lp.second = l2;
+    allLines.push_back(lp);
+    return true;
+}
+
+bool LineCollection::removePair(int index)
+{
+    // should check if line exists?
+    allLines.erase(allLines.begin() + index);
+    return true;
+}
+
+bool LineCollection::removePair(int index, int src, int dest)
+{
+    int i = 0;
+    while( i <= index ) {
+        if( allLines[i].first.imageNr == src && allLines[i].second.imageNr == dest )
+            i++;
+        else if( allLines[i].second.imageNr == src && allLines[i].first.imageNr == dest )
+            i++;
+    }
+    i--;
+    allLines.erase(allLines.begin() + i);
+}
+
+int LineCollection::findLine(Point point, int src, int dest)
+{
+    selectNearest(point);
+    return selectedLine;
+}
+
+bool LineCollection::selectNearest(Point point, int src, int dest)
+{
+    std::vector<StraightLine*> lines(extractLinesPointer(src,dest));
+    if( lines.size() == 0 )
+        return false;
+    int index = 0;
+    double shortest = lines[0]->getLineDistance(point);
+    double tmp;
+    for( int i = 1; i < lines.size(); i++ ) {
+        tmp = lines[i]->getLineDistance(point);
+        if( tmp < shortest ) {
+            shortest = tmp;
+            index = i;
+        }
+    }
+    if( shortest < selectionDistance )
+    {
+        selectedLine = index;
+        lines[index]->selectLastNearPoint();
+        return true;
+    }
+}
+
+void LineCollection::moveActiveLine(Point destination)
+{
+    if( selectedLine < 0 )
+        return;
+    allLines[selectedLine].moveActivePoint(destination);
+}
+
+void LineCollection::update(Point location, int src, int dest)
+{
+    deselectAll();
+    double dist;
+    int nearestIndex = -1;
+    std::vector<StraightLine*> lines(extractLinesPointer(src,dest));
+    double nearestDist = selectionDistance;
+    for( int i = 0; i < lines.size(); i++ ) {
+        dist = lines[i]->getNearestPointDistance(location);
+        if( dist < nearestDist ) {
+            nearestIndex = i;
+            nearestDist = selectionDistance;
+        }
+    }
+    if( nearestIndex < 0 ) { // no points close enough
+        for( int i = 0; i < lines.size(); i++ ) {
+            dist = lines[i]->getLineDistance(location);
+            if( dist < nearestDist ) {
+                nearestIndex = i;
+                nearestDist = selectionDistance;
+            }
+        }
+        if( nearestIndex < 0 ) { // no line close enough
+            return;
+        } else {
+            selectedLine = nearestIndex;
+            lines[selectedLine]->selectLine();
+        }
     } else {
-        isStraight = false;
-        matD.m[0][0] = (startx * startx) + (starty * starty);      matD.m[0][1] = starty;      matD.m[0][2] = 1;
-        matD.m[1][0] = (  midx *   midx) + (  midy *   midy);      matD.m[1][1] =   midy;      matD.m[1][2] = 1;
-        matD.m[2][0] = (  endx *   endx) + (  endy *   endy);      matD.m[2][1] =   endy;      matD.m[2][2] = 1;
-                                                                       
-        matE.m[0][0] = (startx * startx) + (starty * starty);      matE.m[0][1] = startx;      matE.m[0][2] = 1;
-        matE.m[1][0] = (  midx *   midx) + (  midy *   midy);      matE.m[1][1] =   midx;      matE.m[1][2] = 1;
-        matE.m[2][0] = (  endx *   endx) + (  endy *   endy);      matE.m[2][1] =   endx;      matE.m[2][2] = 1;
-                                                                       
-        matF.m[0][0] = (startx * startx) + (starty * starty);      matF.m[0][1] = startx;      matF.m[0][2] = starty;
-        matF.m[1][0] = (  midx *   midx) + (  midy *   midy);      matF.m[1][1] =   midx;      matF.m[1][2] =   midy;
-        matF.m[2][0] = (  endx *   endx) + (  endy *   endy);      matF.m[2][1] =   endx;      matF.m[2][2] =   endy;
-        
-
-        double d = -matD.Determinant();
-        double e =  matE.Determinant();
-        double f = -matF.Determinant();
-
-        center.x = -d / ( 2 * a );
-        center.y = -e / ( 2 * a );
-        radius = hugin_utils::sqrt((d*d+e*e)/(4*a*a)-f/a);
-    }
-    
-    
-    
-    findCircle(lstartx, lstarty, lmidx, lmidy, lendx, lendy, center, radius) ) {
-        center = scale(center);
-        radius = scale(radius);
-
-        double arcLength = sqrt(hugin_utils::sqr(lmidx-lstartx)+hugin_utils::sqr(lmidy-lstarty)) +
-                           sqrt(hugin_utils::sqr(lmidx-lendx)  +hugin_utils::sqr(lmidy-lendy)); // approximate
-        // todo: make this user-selectable
-        int linePointNr = int(arcLength / 100.0);
-        if( linePointNr < 10 )
-            linePointNr = 10;
-
-        double stx = scale(lstartx) - center.x;
-        double sty = scale(lstarty) - center.y;
-        double mdx = scale(lmidx  ) - center.x;
-        double mdy = scale(lmidy  ) - center.y;
-        double edx = scale(lendx  ) - center.x;
-        double edy = scale(lendy  ) - center.y;
-        //enum Quadrant {FIRST, SECOND, THIRD, FOURTH};
-        int quadStart, quadMid, quadEnd;
-
-        findQuadrant(stx, sty, quadStart);
-        findQuadrant(mdx, mdy, quadMid  );
-        findQuadrant(edx, edy, quadEnd  );
-
-        stx = abs(stx);     sty = abs(sty);
-        mdx = abs(mdx);     mdy = abs(mdy);
-        edx = abs(edx);     edy = abs(edy);
-
-        // should this skip the quadrant checks and use atan2 ?
-        double thetaStart = atan(sty/stx);
-        double thetaMid   = atan(mdy/mdx);
-        double thetaEnd   = atan(edy/edx);
-
-        correctAngle( thetaStart, quadStart );
-        correctAngle( thetaMid,   quadMid   );
-        correctAngle( thetaEnd,   quadEnd   );
-
-        if( thetaStart < thetaMid && thetaStart < thetaEnd && thetaMid < thetaEnd ); // nothing to do
-        if( thetaStart < thetaMid && thetaStart < thetaEnd && thetaMid > thetaEnd ) {thetaStart += 2 * 3.14159;}
-      //if( thetaStart < thetaMid && thetaStart > thetaEnd && thetaMid < thetaEnd ); // not possible
-        if( thetaStart < thetaMid && thetaStart > thetaEnd && thetaMid > thetaEnd ) {thetaEnd += 2 * 3.14159;}
-        if( thetaStart > thetaMid && thetaStart < thetaEnd && thetaMid < thetaEnd ) {thetaEnd -= 2 * 3.14159;}
-      //if( thetaStart > thetaMid && thetaStart < thetaEnd && thetaMid > thetaEnd ); // not possible
-        if( thetaStart > thetaMid && thetaStart > thetaEnd && thetaMid < thetaEnd ) {thetaEnd += 2 * 3.14159;}
-        if( thetaStart > thetaMid && thetaStart > thetaEnd && thetaMid > thetaEnd ); // nothing to do
-
-        double thetaSpan = thetaEnd - thetaStart;
-        double step = thetaSpan / 10; // todo: make this adaptive and user-selectable
-
-}
-
-void CPImageCtrl::findQuadrant(double x, double y, int &quad)
-{
-         if( x >= 0 && y >= 0 )
-        quad = 0; // first
-    else if( x <  0 && y >= 0 )
-        quad = 1; // second
-    else if( x <  0 && y <  0 )
-        quad = 2; // third
-    else if( x >= 0 && y <  0 )
-        quad = 3; // fourth
-}
-void CPImageCtrl::correctAngle(double &theta, int quad)
-{
-         if( quad == 1 ) // quadrant 2
-             theta = -theta + 3.14159;
-    else if( quad == 2 ) // quadrant 3
-        theta =  theta + 3.14159;
-    else if( quad == 3 ) // quadrant 4
-        theta = -theta + 3.14159 * 2;
-    while( theta >= 0 )
-        theta -= 2 * 3.14159;
-    theta += 2 * 3.14159;
-}
-
-bool CPImageCtrl::findCircle(double startx, double starty, double midx, double midy, double endx, double endy, FDiff2D &center, double &radius)
-{
-    Matrix3 matA, matD, matE, matF;
-    matA.m[0][0] = startx;                                     matA.m[0][1] = starty;      matA.m[0][2] = 1;
-    matA.m[1][0] =   midx;                                     matA.m[1][1] =   midy;      matA.m[1][2] = 1;
-    matA.m[2][0] =   endx;                                     matA.m[2][1] =   endy;      matA.m[2][2] = 1;
-                                                                   
-    matD.m[0][0] = (startx * startx) + (starty * starty);      matD.m[0][1] = starty;      matD.m[0][2] = 1;
-    matD.m[1][0] = (  midx *   midx) + (  midy *   midy);      matD.m[1][1] =   midy;      matD.m[1][2] = 1;
-    matD.m[2][0] = (  endx *   endx) + (  endy *   endy);      matD.m[2][1] =   endy;      matD.m[2][2] = 1;
-                                                                   
-    matE.m[0][0] = (startx * startx) + (starty * starty);      matE.m[0][1] = startx;      matE.m[0][2] = 1;
-    matE.m[1][0] = (  midx *   midx) + (  midy *   midy);      matE.m[1][1] =   midx;      matE.m[1][2] = 1;
-    matE.m[2][0] = (  endx *   endx) + (  endy *   endy);      matE.m[2][1] =   endx;      matE.m[2][2] = 1;
-                                                                   
-    matF.m[0][0] = (startx * startx) + (starty * starty);      matF.m[0][1] = startx;      matF.m[0][2] = starty;
-    matF.m[1][0] = (  midx *   midx) + (  midy *   midy);      matF.m[1][1] =   midx;      matF.m[1][2] =   midy;
-    matF.m[2][0] = (  endx *   endx) + (  endy *   endy);      matF.m[2][1] =   endx;      matF.m[2][2] =   endy;
-    
-    double a = matA.Determinant();
-    //if( a == 0 )
-    //    return false;
-
-    double d = -matD.Determinant();
-    double e =  matE.Determinant();
-    double f = -matF.Determinant();
-
-    center.x = -d / ( 2 * a );
-    center.y = -e / ( 2 * a );
-    radius = hugin_utils::sqrt((d*d+e*e)/(4*a*a)-f/a);
-    return true;
-}
-
-bool CPImageCtrl::isCollinear(StraightLine l)
-{
-    // todo: add tolerance for nearly-straight lines
-    if ((l.start.x == l.mid.x && l.start.y == l.mid.y)||
-        (l.start.x == l.end.x && l.start.y == l.end.y)||
-        (  l.mid.x == l.end.x &&   l.mid.x == l.end.y))
-        return true;
-
-    if( determinant(l.start.x, l.start.y, 1,
-                      l.mid.x,   l.mid.y, 1,
-                      l.end.x,   l.end.y, 1) == 0 )
-        return true;
-
-    double slope1, slope2;
-
-    slope1 = double(l.mid.y-l.start.y)/double(l.mid.x-l.start.x);
-    slope2 = double(l.mid.y - l.end.y)/double(l.mid.x - l.end.x);
-    if( slope1 == slope2 )
-        return true;
-    else
-        return false;
-}
-
-class LineCollection
-{
-    public:
-        bool addLine(StraightLine);
-        bool removeLine(int);
-        int findLine(hugin_utils::FDiff2D);
-    private:
-        std::vector<StraightLine> allLines;
-}
+        selectedLine = nearestIndex;
+        lines[selectedLine]->selectLastNearPoint();
+    }
+}
+
+std::vector<StraightLine> LineCollection::extractLines(int src, int dest)
+{
+    std::vector<StraightLine> lines;
+    for( int i = 0; i < allLines.size(); i++ ) {
+        if( allLines[i].first.imageNr == src && allLines[i].second.imageNr == dest )
+            lines.push_back(allLines[i].first);
+        else if( allLines[i].second.imageNr == src && allLines[i].first.imageNr == dest )
+            lines.push_back(allLines[i].second);
+    }
+    return lines;
+}
+
+void LineCollection::deselectAll(void)
+{
+    for( int i = 0; i < allLines.size(); i++ ) {
+        allLines[i].deselectLine();
+    }
+}
+
+std::vector<StraightLine*> LineCollection::extractLinesPointer(int src, int dest)
+{
+    std::vector<StraightLine*> lines;
+    for( int i = 0; i < allLines.size(); i++ ) {
+        if( allLines[i].first.imageNr == src && allLines[i].second.imageNr == dest )
+            lines.push_back(&(allLines[i].first));
+        else if( allLines[i].second.imageNr == src && allLines[i].first.imageNr == dest )
+            lines.push_back(&(allLines[i].second));
+    }
+    return lines;
+}