1## Copyright (C) 2021 David Legland
2## All rights reserved.
3##
4## Redistribution and use in source and binary forms, with or without
5## modification, are permitted provided that the following conditions are met:
6##
7##     1 Redistributions of source code must retain the above copyright notice,
8##       this list of conditions and the following disclaimer.
9##     2 Redistributions in binary form must reproduce the above copyright
10##       notice, this list of conditions and the following disclaimer in the
11##       documentation and/or other materials provided with the distribution.
12##
13## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
14## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
17## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23##
24## The views and conclusions contained in the software and documentation are
25## those of the authors and should not be interpreted as representing official
26## policies, either expressed or implied, of the copyright holders.
27
28function line = lineFit(varargin)
29%LINEFIT Fit a straight line to a set of points.
30%
31%   L = lineFit(X, Y)
32%   Computes parametric line minimizing square error of all points (X,Y).
33%   Result is a 4*1 array, containing coordinates of a point of the line,
34%   and the direction vector of the line, that is  L=[x0 y0 dx dy];
35%
36%   L = lineFit(PTS)
37%   Gives coordinats of points in a single array.
38%
39%   L = lineFit(PT0, PTS);
40%   L = lineFit(PT0, X, Y);
41%   with PT0 = [x0 y0], imposes the line to contain point PT0.
42%
43%   Requires:
44%   Optimiaztion toolbox
45%
46%   See also:
47%   lines2d, polyfit, polyfit2, lsqlin
48%
49%
50%   -----
51%   author : David Legland
52%   INRA - TPV URPOI - BIA IMASTE
53%   created the 30/04/2004.
54%
55
56%   HISTORY
57%   09/12/2004 : update implementation
58
59
60
61% ---------------------------------------------
62% extract input arguments
63
64if length(varargin)==1
65    % argument is an array of points
66    var = varargin{1};
67    x = var(:,1);
68    y = var(:,2);
69elseif length(varargin)==2
70    var = varargin{1};
71    if size(var, 1)==1
72        var = varargin{2};
73        x = var(:,1);
74        y = var(:,2);
75    else
76        % two arguments : x and y
77        x = var;
78        y = varargin{2};
79    end
80elseif length(varargin)==3
81    % three arguments : ref point, x and y
82    x = varargin{2};
83    y = varargin{3};
84end
85
86% ---------------------------------------------
87% Initializations :
88
89
90N = size(x, 1);
91
92% ---------------------------------------------
93% Main algorithm :
94
95
96% main matrix of the problem
97X = [x y ones(N,1)];
98
99% conditions initialisations
100A = zeros(0, 3);
101b = [];
102Aeq1 = [1 1 0];
103beq1 = 1;
104Aeq2 = [1 -1 0];
105beq2 = 1;
106
107% disable verbosity of optimisation
108opt = optimset('lsqlin');
109opt.LargeScale = 'off';
110opt.Display = 'off';
111
112% compute line coefficients [a;b;c] , in the form a*x + b*y + c = 0
113% using linear regression
114% Not very clean : I could not impose a*a+b*b=1, so I checked for both a=1
115% and b=1, and I kept the result with lowest residual error....
116[coef1, res1] = lsqlin(X, zeros(N, 1), A, b, Aeq1, beq1, [], [], [], opt);
117[coef2, res2] = lsqlin(X, zeros(N, 1), A, b, Aeq2, beq2, [], [], [], opt);
118
119% choose the best line
120if res1<res2
121    coef = coef1;
122else
123    coef = coef2;
124end
125
126line = cartesianLine(coef');
127