summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Laboissiere <rafael@laboissiere.net>2012-06-10 08:04:00 +0000
committerRafael Laboissiere <rafael@laboissiere.net>2012-06-10 08:04:00 +0000
commit24a8d839d5a45b6b38ec6704d96af8cfad55123f (patch)
treedffe8c6d8eab8cbc82269009cd612fb240a69405
parent1ba9420dac11ebcd5ef87843f1322b518d2d1071 (diff)
Imported Upstream version 1.5.0
-rw-r--r--DESCRIPTION8
-rw-r--r--INDEX27
-rw-r--r--NEWS45
-rw-r--r--PKG_ADD39
-rw-r--r--PKG_DEL39
-rw-r--r--inst/geom2d/beltproblem.m136
-rw-r--r--inst/geom2d/closed_path.m105
-rw-r--r--inst/geom2d/cov2ellipse.m71
-rw-r--r--inst/geom2d/distancePointEdge.m112
-rw-r--r--inst/geom2d/ellipse2cov.m92
-rw-r--r--inst/geom2d/geometry_Contents.m224
-rw-r--r--inst/io/data2geo.m3
-rw-r--r--inst/io/private/SVGstrPath2SVGpath.m103
-rw-r--r--inst/io/private/_parsePath.py64
-rw-r--r--inst/io/private/formatSVGstr.m24
-rw-r--r--inst/io/private/getSVGPaths_py.m113
-rw-r--r--inst/io/private/getSVGdata.m33
-rw-r--r--inst/io/private/parsePath.py64
-rw-r--r--inst/io/svgload.m62
-rw-r--r--inst/io/svgnormalize.m68
-rw-r--r--inst/io/svgpath2polygon.m60
-rw-r--r--inst/octclip/oc_polybool.m2
-rw-r--r--inst/octclip/src/_oc_polybool.cc2
-rw-r--r--inst/polygons2d/curvature.m177
-rwxr-xr-xinst/polygons2d/distancePointPolygon.m51
-rwxr-xr-xinst/polygons2d/distancePointPolyline.m71
-rwxr-xr-xinst/polygons2d/distancePolygons.m43
-rwxr-xr-xinst/polygons2d/expandPolygon.m85
-rwxr-xr-xinst/polygons2d/medialAxisConvex.m153
-rw-r--r--inst/polygons2d/parametrize.m96
-rwxr-xr-xinst/polygons2d/polygonLoops.m143
-rwxr-xr-xinst/polygons2d/polygonSelfIntersections.m87
-rwxr-xr-xinst/polygons2d/polylineSelfIntersections.m153
-rw-r--r--inst/polygons2d/reversePolygon.m44
-rw-r--r--inst/polygons2d/reversePolyline.m43
-rw-r--r--inst/polygons2d/simplifypolygon.m31
-rw-r--r--inst/polygons2d/simplifypolyline.m156
-rw-r--r--inst/polygons2d/splitPolygons.m64
-rw-r--r--inst/polygons2d/supportFunction.m72
-rw-r--r--inst/shape2d/curve2polyline.m141
-rw-r--r--inst/shape2d/curveval.m (renamed from inst/io/private/getSVGstrPath.m)20
-rw-r--r--inst/shape2d/shape2polygon.m49
-rw-r--r--inst/shape2d/shapecentroid.m5
-rw-r--r--inst/shape2d/shapeplot.m6
-rw-r--r--inst/shape2d/shapetransform.m6
45 files changed, 2259 insertions, 933 deletions
diff --git a/DESCRIPTION b/DESCRIPTION
index 42f0e16..bfeb0c9 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,11 +1,11 @@
Name: Geometry
-Version: 1.4.1
-Date: 2012-03-24
-Author: David Legland <david.legland@grignon.inra.fr>, José Luis García Pallero <jgpallero@gmail.com>, Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+Version: 1.5.0
+Date: 2012-06-05
+Author: David Legland <david.legland@grignon.inra.fr>, José Luis García Pallero <jgpallero@gmail.com>, Juan Pablo Carbajal <carbajal@ifi.uzh.ch>, Simeon Simeonov <sss41@cam.ac.uk>
Maintainer: Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
Title: Computational Geometry
Description: Library for geometric computing extending MatGeom functions. Useful to create, transform, manipulate and display geometric primitives.
-Depends: octave (>= 3.4.0)
+Depends: octave (>= 3.4.0), general (>= 1.3.0)
Autoload: yes
License: GPLv3+, FreeBSD
Url: http://octave.sf.net, http://matgeom.sf.net, http://davis.wpi.edu/~matt/courses/clipping/, https://bitbucket.org/jgpallero/octclip
diff --git a/INDEX b/INDEX
index 05e723f..34149dd 100644
--- a/INDEX
+++ b/INDEX
@@ -14,8 +14,10 @@ geometry >> Computational Geometry
polygons2d
2D Points
centroid
+ closed_path
distancePoints
drawPoint
+ isCounterClockwise
isPointOnRay
isPointInCircle
isPointOnCircle
@@ -96,9 +98,11 @@ geometry >> Computational Geometry
intersectLineCircle
radicalAxis
2D Ellipses
- ellipseAsPolygon
+ cov2ellipse
drawEllipseArc
drawEllipse
+ ellipseAsPolygon
+ ellipse2cov
inertiaEllipse
2D Transformations
transformLine
@@ -115,16 +119,34 @@ geometry >> Computational Geometry
drawBezierCurve
cbezier2poly
2D Polygons
+ curvature
+ distancePolygons
+ distancePointPolygon
+ distancePointPolyline
drawPolygon
- simplifypolygon
+ expandPolygon
+ medialAxisConvex
oc_polybool
+ parametrize
+ polygonLoops
+ polygonSelfIntersections
+ polylineSelfIntersections
+ reversePolyline
+ reversePolygon
+ simplifypolygon
+ simplifypolyline
+ splitPolygons
+ supportFunction
2D Piecewise polynomial shapes
polygon2shape
shape2polygon
shapecentroid
shapeplot
shapetransform
+ curveval
+ curve2polyline
2D Others
+ beltproblem
bisector
crackPattern2
crackPattern
@@ -133,7 +155,6 @@ geometry >> Computational Geometry
drawParabola
drawShape
hexagonalGrid
- isCounterClockwise
squareGrid
triangleGrid
Geometric graphs creation
diff --git a/NEWS b/NEWS
index c294711..3d3d6b6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,51 @@
Summary of important user-visible changes for releases of the geometry package
===============================================================================
+geometry-1.5.0 Release Date: 2012-06-05 Release Manager: Juan Pablo Carbajal
+===============================================================================
+
+* Added functions:
+ - cov2ellipse.m & ellipse2cov: transform between ellipses and covariances matrices.
+
+ - beltproblem.m : Finds the four lines tangent to two circles with given centers and
+ radii. This is the solution to the belt problem in 2D.
+
+ - curveval.m: Evaluates a polynomial curve defined as a 2-by-N matrix.
+
+ - curve2polyline.m: Converts a polynomial curve into a polyline by the adaptive
+ sampling method.
+
+ - simplifypolyline.m: Ramer-Douglas-Peucker algorithm to simplify polylines.
+
+ - parametrize.m: Estimate a parametrization of a polygon/line based on the distance
+ between the points.
+
+ - curvature.m: Estimation of the curvature of a polygon/line based on polynomial
+ approximation.
+
+ - reversePolygon.m and reversePolyline.m: reverse the orders of the points in
+ of polygon/line.
+
+ - supportFunction.m: Compute support function of a polygon.
+
+ - distancePointPolygon.m, distancePointPolyline.m, distancePolygons.m ,
+ expandPolygon.m, medialAxisConvex.m, polygonLoops.m, polygonSelfIntersections.m
+ polylineSelfIntersections.m, splitPolygons.m
+
+ - close_path.m : given a set of points in the plane calculate a piecewise linear
+ simple path that passes through all points.
+
+* Changed functions:
+ - distancePointEdge.m: Now the function computes the distance between all points
+ and all edges. A third optional argument provides
+ backward compatibility.
+
+* Solved bugs:
+ - simplifypolygon.m returned empty polygons when points are repeated, i.e when
+ the polygon is not correctly formed.
+ - Removed installation warnings.
+
+===============================================================================
geometry-1.4.1 Release Date: 2012-03-24 Release Manager: Juan Pablo Carbajal
===============================================================================
diff --git a/PKG_ADD b/PKG_ADD
index 4be7588..f98198e 100644
--- a/PKG_ADD
+++ b/PKG_ADD
@@ -2,21 +2,34 @@
dirlist = {"geom2d","io","polygons2d","shape2d","octclip", "graphs"};
dirname = fileparts (canonicalize_file_name (mfilename ("fullpath")));
pp = strsplit (dirname,filesep (), true);
-
-%% Check if prefix was used
-[pkg_folder dep_folder] = pkg ("prefix");
-pkg_folder = [pkg_folder filesep() strcat(filesep(),{pp{end-1:end}}){:} ];
-dep_folder = [dep_folder filesep() strcat(filesep(),{pp{end-1:end}}){:} ];
-
-%% If we are in Architecture dependent folder add from outside
arch = cstrcat (octave_config_info ("canonical_host_type"),
"-", octave_config_info ("api_version"));
-if strcmp (arch , pp{end})
- dirname = [strcat(filesep(),{pp{1:end-1}}){:}];
- pkg_folder = strsplit (pkg_folder,filesep (), true);
- pkg_folder = [strcat(filesep(),{pkg_folder{1:end-1}}){:}];
+
+%% Get the correct path
+% Search installed packages
+[local_packages, global_packages] = pkg("list");
+installed_pkgs_lst = {local_packages{:}, global_packages{:}};
+pkg_data = installed_pkgs_lst (cellfun(@(x) ismember (x.name, {"geometry"}), ...
+ installed_pkgs_lst, "unif", true));
+if isempty(pkg_data)
+ % The package is not installed yet
+ [pkg_folder dep_folder] = pkg ("prefix");
+ pkg_folder = [pkg_folder strcat(filesep(),{pp{end-1:end}}){:} ];
+% dep_folder = [dep_folder strcat(filesep(),{pp{end-1:end}}){:} ];
+ if strcmp (arch , pp{end})
+ %% If we are in Architecture dependent folder add from outside
+ pkg_folder = strsplit (pkg_folder,filesep (), true);
+ pkg_folder = [strcat(filesep(),{pkg_folder{1:end-1}}){:}];
+% dep_folder = strsplit (dep_folder,filesep (), true);
+% dep_folder = [strcat(filesep(),{dep_folder{1:end-1}}){:}];
+ end
+else
+ pkg_folder = pkg_data{1}.dir;
+% dep_folder = pkg_data{1}.archprefix;
end
+%dep_folder = [dep_folder filesep arch];
+
if (! exist (fullfile (dirname, "inst"), "dir"))
%% Installing
for ii=1:length (dirlist)
@@ -30,6 +43,8 @@ else
addpath ([ dirname "/inst/" dirlist{ii}])
endfor
endif
+%addpath (dep_folder)
warning('off', 'Octave:fopen-file-in-path');
-clear dirlist dirname pp
+clear dirlist dirname pp arch pkg_folder
+%dep_folder
diff --git a/PKG_DEL b/PKG_DEL
index 2bdeb33..153be46 100644
--- a/PKG_DEL
+++ b/PKG_DEL
@@ -2,22 +2,33 @@
dirlist = {"geom2d","io","polygons2d","shape2d","octclip","graphs"};
dirname = fileparts (canonicalize_file_name (mfilename ("fullpath")));
pp = strsplit (dirname,filesep (), true);
-
-%% Check if prefix was used
-[pkg_folder dep_folder] = pkg ("prefix");
-pkg_folder = [pkg_folder filesep() strcat(filesep(),{pp{end-1:end}}){:} ];
-dep_folder = [dep_folder filesep() strcat(filesep(),{pp{end-1:end}}){:} ];
-
-%% If we are not in Architecture dependent folder
arch = cstrcat (octave_config_info ("canonical_host_type"),
"-", octave_config_info ("api_version"));
-pp = strsplit (dirname,filesep (), true);
-if strcmp(arch , pp{end})
- dirname = [pkg("prefix") filesep() pp{end-1}];
- pkg_folder = strsplit (pkg_folder,filesep (), true);
- pkg_folder = [strcat(filesep(),{pkg_folder{1:end-1}}){:}];
+%% Get the correct path
+% Search installed packages
+[local_packages, global_packages] = pkg("list");
+installed_pkgs_lst = {local_packages{:}, global_packages{:}};
+pkg_data = installed_pkgs_lst (cellfun(@(x) ismember (x.name, {"geometry"}), ...
+ installed_pkgs_lst, "unif", true));
+if isempty(pkg_data)
+ % The package is not installed yet
+ [pkg_folder dep_folder] = pkg ("prefix");
+ pkg_folder = [pkg_folder strcat(filesep(),{pp{end-1:end}}){:} ];
+% dep_folder = [dep_folder strcat(filesep(),{pp{end-1:end}}){:} ];
+ if strcmp (arch , pp{end})
+ %% If we are in Architecture dependent folder add from outside
+ pkg_folder = strsplit (pkg_folder,filesep (), true);
+ pkg_folder = [strcat(filesep(),{pkg_folder{1:end-1}}){:}];
+% dep_folder = strsplit (dep_folder,filesep (), true);
+% dep_folder = [strcat(filesep(),{dep_folder{1:end-1}}){:}];
+ end
+else
+ pkg_folder = pkg_data{1}.dir;
+% dep_folder = pkg_data{1}.archprefix;
end
+%dep_folder = [dep_folder filesep arch];
+
if (! exist (fullfile (dirname, "inst"), "dir"))
## Run this if the package is installed
for ii=1:length (dirlist)
@@ -29,5 +40,7 @@ else
rmpath ([ dirname "/inst/" dirlist{ii}])
endfor
endif
+%rmpath (dep_folder);
-clear dirlist dirname pp
+clear dirlist dirname pp arch pkg_folder
+%dep_folder
diff --git a/inst/geom2d/beltproblem.m b/inst/geom2d/beltproblem.m
new file mode 100644
index 0000000..d3207bd
--- /dev/null
+++ b/inst/geom2d/beltproblem.m
@@ -0,0 +1,136 @@
+%% Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%%
+%% This program is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {[@var{tangent},@var{inner}] = } beltproblem (@var{c}, @var{r})
+%% Finds the four lines tangent to two circles with given centers and radii.
+%%
+%% The function solves the belt problem in 2D for circles with center @var{c} and
+%% radii @var{r}.
+%%
+%% @strong{INPUT}
+%% @table @var
+%% @item c
+%% 2-by-2 matrix containig coordinates of the centers of the circles; one row per circle.
+%% @item r
+%% 2-by-1 vector with the radii of the circles.
+%%@end table
+%%
+%% @strong{OUPUT}
+%% @table @var
+%% @item tangent
+%% 4-by-4 matrix with the points of tangency. Each row describes a segment(edge).
+%% @item inner
+%% 4-by-2 vector with the point of intersection of the inner tangents (crossed belts)
+%% with the segment that joins the centers of the two circles. If
+%% the i-th edge is not an inner tangent then @code{inner(i,:)=[NaN,NaN]}.
+%% @end table
+%%
+%% Example:
+%%
+%% @example
+%% c = [0 0;1 3];
+%% r = [1 0.5];
+%% [T inner] = beltproblem(c,r)
+%% @result{} T =
+%% -0.68516 0.72839 1.34258 2.63581
+%% 0.98516 0.17161 0.50742 2.91419
+%% 0.98675 -0.16225 1.49338 2.91888
+%% -0.88675 0.46225 0.55663 3.23112
+%%
+%% @result{} inner =
+%% 0.66667 2.00000
+%% 0.66667 2.00000
+%% NaN NaN
+%% NaN NaN
+%%
+%% @end example
+%%
+%% @seealso{edges2d}
+%% @end deftypefn
+
+function [edgeTan inner] = beltproblem(c,r)
+
+ x0 = [c(1,1) c(1,2) c(2,1) c(2,2)];
+ r0 = r([1 1 2 2]);
+
+ middleEdge = createEdge(c(1,:),c(2,:));
+
+ ind0 = [1 0 1 0; 0 1 1 0; 1 1 1 0; -1 0 1 0; 0 -1 1 0; -1 -1 1 0;...
+ 1 0 0 1; 0 1 0 1; 1 1 0 1; -1 0 0 1; 0 -1 0 1; -1 -1 0 1;...
+ 1 0 1 1; 0 1 1 1; 1 1 1 1; -1 0 1 1; 0 -1 1 1; -1 -1 1 1;...
+ 1 0 -1 0; 0 1 -1 0; 1 1 -1 0; -1 0 -1 0; 0 -1 -1 0; -1 -1 -1 0;...
+ 1 0 0 -1; 0 1 0 -1; 1 1 0 -1; -1 0 0 -1; 0 -1 0 -1; -1 -1 0 -1;...
+ 1 0 -1 -1; 0 1 -1 -1; 1 1 -1 -1; -1 0 -1 -1; 0 -1 -1 -1; -1 -1 -1 -1];
+ nInit = size(ind0,1);
+ ir = randperm(nInit);
+ edgeTan = zeros(4,4);
+ inner = zeros(4,2);
+ nSol = 0;
+ i=1;
+
+ %% Solve for 2 different lines
+ while nSol<4 && i<nInit
+ ind = find(ind0(ir(i),:)~=0);
+ x = x0;
+ x(ind)=x(ind)+r0(ind);
+ [sol f0 nev]= fsolve(@(x)belt(x,c,r),x);
+ if nev~=1
+ perror('fsolve',nev)
+ end
+
+ for j=1:4
+ notequal(j) = all(abs(edgeTan(j,:)-sol) > 1e-6);
+ end
+ if all(notequal)
+ nSol = nSol+1;
+ edgeTan(nSol,:) = createEdge(sol(1:2),sol(3:4));
+ % Find innerTangent
+ inner(nSol,:) = intersectEdges(middleEdge,edgeTan(nSol,:));
+ end
+
+ i = i+1;
+ end
+
+endfunction
+
+function res = belt(x,c,r)
+ res = zeros(4,1);
+
+ res(1,1) = (x(3:4) - c(2,1:2))*(x(3:4) - x(1:2))';
+ res(2,1) = (x(1:2) - c(1,1:2))*(x(3:4) - x(1:2))';
+ res(3,1) = sumsq(x(1:2) - c(1,1:2)) - r(1)^2;
+ res(4,1) = sumsq(x(3:4) - c(2,1:2)) - r(2)^2;
+
+end
+
+%!demo
+%! c = [0 0;1 3];
+%! r = [1 0.5];
+%! [T inner] = beltproblem(c,r)
+%!
+%! figure(1)
+%! clf
+%! h = drawEdge(T);
+%! set(h(find(~isnan(inner(:,1)))),'color','r');
+%! set(h,'linewidth',2);
+%! hold on
+%! drawCircle([c(1,:) r(1); c(2,:) r(2)],'linewidth',2);
+%! axis tight
+%! axis equal
+%!
+%! % -------------------------------------------------------------------
+%! % The circles with the tangents edges are plotted. The solution with
+%! % crossed belts (inner tangets) is shown in red.
diff --git a/inst/geom2d/closed_path.m b/inst/geom2d/closed_path.m
new file mode 100644
index 0000000..4ea3839
--- /dev/null
+++ b/inst/geom2d/closed_path.m
@@ -0,0 +1,105 @@
+%% Copyright (C) 2012 Simeon Simeonov <simeon.simeonov.s@gmail.com>
+%%
+%% This program is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{y} =} polygon (@var{x})
+%% Returns a simple closed path that passes through all the points in @var{x}.
+%% @var{x} is a vector containing 2D coordinates of the points.
+%%
+%% @end deftypefn
+
+%% Author: Simeon Simeonov <simeon.simeonov.s@gmail.com>
+
+function y = closed_path(x)
+
+ if(size(x,1) > 1 && size(x,1) < size(x,2))
+ x = x';
+ end
+
+ N = size(x,1); % Number of points
+ idx = zeros(N, 1); % ind contains the indices of the sorted coordinates
+
+ a = find(x(:,2)==min(x(:,2)));
+
+ if(size(a,1) > 1)
+ [~, i] = sort(x(a,1));
+ a = a(i(1));
+ end
+
+ x_1 = x(x(:,2)==x(a,2),:); % find all x with the same y coordinate
+
+ if(x(a,1) == min(x(:,1)))
+ x_2 = x(x(:,1)==x(a,1),:); % find all x with the same x coordinate
+ else
+ x_2 = x(a,:);
+ end
+
+ if(size(x_1,1) > 1 || size(x_2,1) > 1)
+ if(size(x_1,1) > 1)
+ x_1 = sort(x_1); % Sort by x coordinate
+ y(1,:) = x(a,:); % original starting point
+ end
+
+ if (size(x_2,1) > 1)
+ x_2 = sort(x_2, 'descend');
+ end
+
+ x_not = [x_1; x_2];
+ i = ismember(x,x_not,'rows');
+ x(i, :) = [];
+ x = [x_1(size(x_1,1),:); x];
+ x_1(size(x_1, 1),:) = [];
+ N = size(x,1);
+ a = 1;
+ else
+ x_1 = [];
+ x_2 = x(a,:);
+ end
+ d = x - repmat(x(a,:), N, 1);
+ th = d(:,2)./(d(:,1) + d(:,2));
+
+ [~, idx0] = ismember(sort(th(th==0)), th);
+ [~, idx1] = ismember(sort(th(th>0)), th);
+ [~, idx2] = ismember(sort(th(th<0)), th);
+
+ idx = [a; idx0; idx1; idx2];
+ % I contains the indices of idx in a sorted order. [v i] = sort(idx) then
+ % i==I.
+ [~,I,J]= unique(idx);
+ if(size(I,1) ~= size(J,1))
+ R = histc(J, 1:size(I,1)); % R(1) will always be 1?
+ idx_sorted = idx(I);
+ r = find(R>1);
+ for ri = r'
+ idx_repeated = idx_sorted(ri);
+ idx(idx==idx_repeated) = find(th==th(idx_sorted(ri)));
+ end
+ end
+
+ y = [x_1; x(idx,:); x_2;];
+
+endfunction
+
+%!demo
+%! maxInt = 100;
+%! N = 25;
+%!
+%! for i = 1:5
+%! x = randi(maxInt, N, 2);
+%! y = closed_path(x);
+%! plot(y(:,1), y(:,2), '*');
+%! hold on;
+%! plot(y(:,1), y(:,2));
+%! end
diff --git a/inst/geom2d/cov2ellipse.m b/inst/geom2d/cov2ellipse.m
new file mode 100644
index 0000000..214381a
--- /dev/null
+++ b/inst/geom2d/cov2ellipse.m
@@ -0,0 +1,71 @@
+## Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{ellipse} = } cov2ellipse (@var{K})
+%% @deftypefnx {Function File} {[@var{ra} @var{rb} @var{theta}] = } cov2ellipse (@var{K})
+%% @deftypefnx {Function File} {@dots{} = } cov2ellipse (@dots{}, @samp{tol},@var{tol})
+%% Calculates ellipse parameters from covariance matrix.
+%%
+%% @var{K} must be symmetric positive (semi)definite. The optional argument
+%% @samp{tol} sets the tolerance for the verification of the
+%% positive-(semi)definiteness of the matrix @var{K} (see @command{isdefinite}).
+%%
+%% If only one output argument is supplied a vector defining a ellipse is returned
+%% as defined in @command{ellipses2d}. Otherwise the angle @var{theta} is given
+%% in radians.
+%%
+%% Run @code{demo cov2ellipse} to see an example.
+%%
+%% @seealso{ellipses2d, cov2ellipse, drawEllipse}
+%% @end deftypefn
+
+function varargout = cov2ellipse (K, varargin);
+
+ parser = inputParser ();
+ parser.FunctionName = "cov2ellipse";
+ parser = addParamValue (parser,'Tol', 100*eps*norm (K, "fro"), @(x)x>0);
+ parser = parse(parser,varargin{:});
+
+ if isdefinite (K,parser.Results.Tol) == -1
+ print_usage
+ end
+ [R S W] = svd (K);
+ theta = atan (R(1,1)/R(2,2));
+ v = sort (diag(S), 'ascend')';
+
+ if nargout == 1
+ varargout{1} = [0 0 v theta*180/pi];
+ elseif nargout == 3
+ varargout{1} = v(1);
+ varargout{2} = v(2);
+ varargout{3} = theta;
+ end
+
+endfunction
+
+%!demo
+%! K = [2 1; 1 2];
+%! L = chol(K,'lower');
+%! u = randn(1e3,2)*L';
+%!
+%! elli = cov2ellipse (K)
+%!
+%! figure(1)
+%! plot(u(:,1),u(:,2),'.r');
+%! hold on;
+%! drawEllipse(elli,'linewidth',2);
+%! hold off
+%! axis tight
diff --git a/inst/geom2d/distancePointEdge.m b/inst/geom2d/distancePointEdge.m
index 1a689db..709a2bf 100644
--- a/inst/geom2d/distancePointEdge.m
+++ b/inst/geom2d/distancePointEdge.m
@@ -1,6 +1,5 @@
-%% Copyright (c) 2011, INRA
-%% 2007-2011, David Legland <david.legland@grignon.inra.fr>
-%% 2011 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% Copyright (c) 2007-2011, David Legland <david.legland@grignon.inra.fr>
+%% Copyright (c) 2012, Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
%%
%% All rights reserved.
%% (simplified BSD License)
@@ -10,8 +9,8 @@
%%
%% 1. Redistributions of source code must retain the above copyright notice, this
%% list of conditions and the following disclaimer.
-%%
-%% 2. Redistributions in binary form must reproduce the above copyright notice,
+%%
+%% 2. Redistributions in binary form must reproduce the above copyright notice,
%% this list of conditions and the following disclaimer in the documentation
%% and/or other materials provided with the distribution.
%%
@@ -19,9 +18,9 @@
%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
%% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
%% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
%% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
@@ -33,53 +32,102 @@
%% -*- texinfo -*-
%% @deftypefn {Function File} {@var{dist} = } distancePointEdge (@var{point}, @var{edge})
+%% @deftypefnx {Function File} {@var{dist} = } distancePointEdge (@dots{}, @var{opt})
+%% @deftypefnx {Function File} {[@var{dist} @var{pos}]= } distancePointEdge (@dots{})
%% Minimum distance between a point and an edge
%%
-%% DIST = distancePointEdge(POINT, EDGE);
-%% Return the euclidean distance between edge EDGE and point POINT.
-%% EDGE has the form: [x1 y1 x2 y2], and POINT is [x y].
+%% Return the euclidean distance between edge @var{edge} and point @var{point}.
+%% @var{edge} has the form: [x1 y1 x2 y2], and @var{point} is [x y].
+%% If @var{edge} is Ne-by-4 and @var{point} is Np-by-2, then @var{dist} is
+%% Np-by-Ne, where each row contains the distance of each point to all the edges.
%%
-%% If EDGE is N-by-4 array, result is N-by-1 array computed for each edge.
-%% If POINT is a N-by-2 array, the result is computed for each point.
-%% If both POINT and EDGE are array, they must have the same number of
-%% rows, and the result is computed for each couple point(i,:);edge(i,:).
+%% If @var{opt} is true (or equivalent), the optput is cmpatible with the original function:
+%% @table @samp
+%% @item 1
+%% If @var{point} is 1-by-2 array, the result is Ne-by-1 array computed for each edge.
+%% @item 2
+%% If @var{edge} is a 1-by-4 array, the result is Np-by-1 computed for each point.
+%% @item 3
+%% If both @var{point} and @var{edge} are array, they must have the same number of
+%% rows, and the result is computed for each couple @code{@var{point}(i,:),@var{edge}(i,:)}.
+%% @end table
%%
-%% [DIST POS] = distancePointEdge(POINT, EDGE);
-%% Also returns the position of closest point on the edge. POS is
-%% comprised between 0 (first point) and 1 (last point).
+%% If the the second output argument @var{pos} is requested, the function also
+%% returns the position of closest point on the edge. @var{pos} is comprised
+%% between 0 (first point) and 1 (last point).
%%
-%% @seealso{edges2d, points2d, distancePoints, distancePointLine}
+%% @seealso{edges2d, points2d, distancePoints, distancePointLine}
%% @end deftypefn
-function varargout = distancePointEdge(point, edge)
+%% Rewritten to accept different numbers of points and edges.
+%% 2012 - Juan Pablo Carbajal
+
+function [dist, tp] = distancePointEdge(point, edge, opt=[])
+
+ Np = size (point,1);
+ Ne = size (edge,1);
+ edge = edge.';
+
% direction vector of each edge
- dx = edge(:, 3) - edge(:,1);
- dy = edge(:, 4) - edge(:,2);
+ dx = edge(3,:) - edge(1,:);
+ dy = edge(4,:) - edge(2,:);
% compute position of points projected on the supporting line
% (Size of tp is the max number of edges or points)
- delta = dx .* dx + dy .* dy;
- tp = ((point(:, 1) - edge(:, 1)) .* dx + (point(:, 2) - edge(:, 2)) .* dy) ./ delta;
- % ensure degenerated edges are correclty processed (consider the first
- % vertex is the closest)
- tp(delta < eps) = 0;
+ delta = dx .* dx + dy .* dy;
+ mask = delta < eps;
+ delta(mask) = 1;
+ warning ('off', 'Octave:broadcast');
+ tp = ((point(:, 1) - edge(1, :)) .* dx + (point(:, 2) - edge(2, :)) .* dy) ./ delta;
+ tp(:,mask) = 0;
% change position to ensure projected point is located on the edge
tp(tp < 0) = 0;
tp(tp > 1) = 1;
% coordinates of projected point
- p0 = [edge(:,1) + tp .* dx, edge(:,2) + tp .* dy];
+ p0x = (edge(1,:) + tp .* dx);
+ p0y = (edge(2,:) + tp .* dy);
% compute distance between point and its projection on the edge
- dist = sqrt((point(:,1) - p0(:,1)) .^ 2 + (point(:,2) - p0(:,2)) .^ 2);
+ dist = sqrt((point(:,1) - p0x) .^ 2 + (point(:,2) - p0y) .^ 2);
+
+ warning ('on', 'Octave:broadcast');
- % process output arguments
- varargout{1} = dist;
- if nargout > 1
- varargout{2} = tp;
+ %% backwards compatibility
+ if opt
+ if Np != Ne && (Ne != 1 && Np !=1)
+ error ("geometry:InvalidArgument", ...
+ "Sizes must be equal or one of the inputs must be 1-by-N array.");
+ end
+ if Np == Ne
+ dist = diag(dist)(:);
+ tp = diag(tp)(:);
+ elseif Np == 1
+ dist = dist.';
+ tp = tp.';
+ end
end
endfunction
+%% Original code
+%%tp = ((point(:, 1) - edge(:, 1)) .* dx + (point(:, 2) - edge(:, 2)) .* dy) ./ delta;
+%%% ensure degenerated edges are correclty processed (consider the first
+%%% vertex is the closest)
+%%if Ne > 1
+%% tp(delta < eps) = 0;
+%%elseif delta < eps
+%% tp(:) = 0;
+%%end
+
+%%% change position to ensure projected point is located on the edge
+%%tp(tp < 0) = 0;
+%%tp(tp > 1) = 1;
+
+%%% coordinates of projected point
+%%p0 = [edge(:,1) + tp .* dx, edge(:,2) + tp .* dy];
+
+%%% compute distance between point and its projection on the edge
+%%dist = sqrt((point(:,1) - p0(:,1)) .^ 2 + (point(:,2) - p0(:,2)) .^ 2);
diff --git a/inst/geom2d/ellipse2cov.m b/inst/geom2d/ellipse2cov.m
new file mode 100644
index 0000000..276b411
--- /dev/null
+++ b/inst/geom2d/ellipse2cov.m
@@ -0,0 +1,92 @@
+## Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{K} = } ellipse2cov (@var{elli})
+%% @deftypefnx {Function File} {@var{K} = } ellipse2cov (@var{ra}, @var{rb})
+%% @deftypefnx {Function File} {@var{K} = } ellipse2cov (@dots{}, @var{theta})
+%% Calculates covariance matrix from ellipse.
+%%
+%% If only one input is given, @var{elli} must define an ellipse as described in
+%% @command{ellipses2d}.
+%% If two inputs are given, @var{ra} and @var{rb} define the half-lenght of the
+%% axes.
+%% If a third input is given, @var{theta} must be the angle of rotation of the
+%% ellipse in radians, and in counter-clockwise direction.
+%%
+%% The output @var{K} contains the covariance matrix define by the ellipse.
+%%
+%% Run @code{demo ellipse2cov} to see an example.
+%%
+%% @seealso{ellipses2d, cov2ellipse, drawEllipse}
+%% @end deftypefn
+
+function K = ellipse2cov (elli, varargin);
+
+ ra = 1;
+ rb = 1;
+ theta = 0;
+ switch numel (varargin)
+ case 0
+ %% ellipse format
+ if numel (elli) != 5
+ print_usage ();
+ end
+ ra = elli(1,3);
+ rb = elli(1,4);
+ theta = elli(1,5)*pi/180;
+
+ case 2
+ %% ra,rb
+ if numel (elli) != 1
+ print_usage ();
+ end
+ ra = elli;
+ rb = varargin{1};
+
+ case 3
+ %% ra,rb, theta
+ if numel (elli) != 1
+ print_usage ();
+ end
+ ra = elli;
+ rb = varargin{1};
+ theta = varargin{2};
+
+ otherwise
+ print_usage ();
+ end
+
+ T = createRotation (theta)(1:2,1:2);
+ K = T*diag([ra rb])*T';
+
+endfunction
+
+%!demo
+%! elli = [0 0 1 3 -45];
+%!
+%! % Create 2D normal random variables with covarinace defined by elli.
+%! K = ellipse2cov (elli)
+%! L = chol(K,'lower');
+%! u = randn(1e3,2)*L';
+%!
+%! Kn = cov (u)
+%!
+%! figure(1)
+%! plot(u(:,1),u(:,2),'.r');
+%! hold on;
+%! drawEllipse(elli,'linewidth',2);
+%! hold off
+%! axis tight
diff --git a/inst/geom2d/geometry_Contents.m b/inst/geom2d/geometry_Contents.m
deleted file mode 100644
index b87427f..0000000
--- a/inst/geom2d/geometry_Contents.m
+++ /dev/null
@@ -1,224 +0,0 @@
-%% Copyright (c) 2011, INRA
-%% 2007-2011, David Legland <david.legland@grignon.inra.fr>
-%% 2011 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% All rights reserved.
-%% (simplified BSD License)
-%%
-%% Redistribution and use in source and binary forms, with or without
-%% modification, are permitted provided that the following conditions are met:
-%%
-%% 1. Redistributions of source code must retain the above copyright notice, this
-%% list of conditions and the following disclaimer.
-%%
-%% 2. Redistributions in binary form must reproduce the above copyright notice,
-%% this list of conditions and the following disclaimer in the documentation
-%% and/or other materials provided with the distribution.
-%%
-%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-%% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-%% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-%% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-%% POSSIBILITY OF SUCH DAMAGE.
-%%
-%% The views and conclusions contained in the software and documentation are
-%% those of the authors and should not be interpreted as representing official
-%% policies, either expressed or implied, of copyright holder.
-
-%% -*- texinfo -*-
-%% @deftypefn {Function File} geometry_Contents ()
-%% Geometry 2D Toolbox
-%% Version 1.2.0 21-Oct-2011 .
-%%
-%% Library to handle and visualize geometric primitives such as points,
-%% lines, circles and ellipses, polygons...
-%%
-%% The goal is to provide a low-level library for manipulating geometrical
-%% primitives, making easier the development of more complex geometric
-%% algorithms.
-%%
-%% Most functions works for planar shapes, but some ones have been
-%% extended to 3D or to any dimension.
-%%
-%% Points
-%% points2d - Description of functions operating on points
-%% clipPoints - Clip a set of points by a box
-%% centroid - Compute centroid (center of mass) of a set of points
-%% midPoint - Middle point of two points or of an edge
-%% isCounterClockwise - Compute relative orientation of 3 points
-%% polarPoint - Create a point from polar coordinates (rho + theta)
-%% angle2Points - Compute horizontal angle between 2 points
-%% angle3Points - Compute oriented angle made by 3 points
-%% angleSort - Sort points in the plane according to their angle to origin
-%% distancePoints - Compute distance between two points
-%% minDistancePoints - Minimal distance between several points
-%% transformPoint - Transform a point with an affine transform
-%% drawPoint - Draw the point on the axis.
-%%
-%% Vectors
-%% vectors2d - Description of functions operating on plane vectors
-%% createVector - Create a vector from two points
-%% vectorNorm - Compute norm of a vector, or of a set of vectors
-%% vectorAngle - Angle of a vector, or between 2 vectors
-%% normalizeVector - Normalize a vector to have norm equal to 1
-%% isPerpendicular - Check orthogonality of two vectors
-%% isParallel - Check parallelism of two vectors
-%% transformVector - Transform a vector with an affine transform
-%% rotateVector - Rotate a vector by a given angle
-%%
-%% Straight lines
-%% lines2d - Description of functions operating on planar lines
-%% createLine - Create a straight line from 2 points, or from other inputs
-%% medianLine - Create a median line between two points
-%% cartesianLine - Create a straight line from cartesian equation coefficients
-%% orthogonalLine - Create a line orthogonal to another one.
-%% parallelLine - Create a line parallel to another one.
-%% intersectLines - Return all intersection points of N lines in 2D
-%% lineAngle - Computes angle between two straight lines
-%% linePosition - Position of a point on a line
-%% lineFit - Fit a straight line to a set of points
-%% clipLine - Clip a line with a box
-%% reverseLine - Return same line but with opposite orientation
-%% transformLine - Transform a line with an affine transform
-%% drawLine - Draw the line on the current axis
-%%
-%% Edges (line segments between 2 points)
-%% edges2d - Description of functions operating on planar edges
-%% createEdge - Create an edge between two points, or from a line
-%% edgeToLine - Convert an edge to a straight line
-%% edgeAngle - Return angle of edge
-%% edgeLength - Return length of an edge
-%% midPoint - Middle point of two points or of an edge
-%% edgePosition - Return position of a point on an edge
-%% clipEdge - Clip an edge with a rectangular box
-%% reverseEdge - Intervert the source and target vertices of edge
-%% intersectEdges - Return all intersections between two set of edges
-%% intersectLineEdge - Return intersection between a line and an edge
-%% transformEdge - Transform an edge with an affine transform
-%% drawEdge - Draw an edge given by 2 points
-%% drawCenteredEdge - Draw an edge centered on a point
-%%
-%% Rays
-%% rays2d - Description of functions operating on planar rays
-%% createRay - Create a ray (half-line), from various inputs
-%% bisector - Return the bisector of two lines, or 3 points
-%% clipRay - Clip a ray with a box
-%% drawRay - Draw a ray on the current axis
-%%
-%% Relations between points and lines
-%% distancePointEdge - Minimum distance between a point and an edge
-%% distancePointLine - Minimum distance between a point and a line
-%% projPointOnLine - Project of a point orthogonally onto a line
-%% pointOnLine - Create a point on a line at a given position on the line
-%% isPointOnLine - Test if a point belongs to a line
-%% isPointOnEdge - Test if a point belongs to an edge
-%% isPointOnRay - Test if a point belongs to a ray
-%% isLeftOriented - Test if a point is on the left side of a line
-%%
-%% Circles
-%% circles2d - Description of functions operating on circles
-%% createCircle - Create a circle from 2 or 3 points
-%% createDirectedCircle - Create a directed circle
-%% intersectCircles - Intersection points of two circles
-%% intersectLineCircle - Intersection point(s) of a line and a circle
-%% circleAsPolygon - Convert a circle into a series of points
-%% circleArcAsCurve - Convert a circle arc into a series of points
-%% isPointInCircle - Test if a point is located inside a given circle
-%% isPointOnCircle - Test if a point is located on a given circle.
-%% enclosingCircle - Find the minimum circle enclosing a set of points.
-%% radicalAxis - Compute the radical axis (or radical line) of 2 circles
-%% drawCircle - Draw a circle on the current axis
-%% drawCircleArc - Draw a circle arc on the current axis
-%%
-%% Ellipses
-%% ellipses2d - Description of functions operating on ellipses
-%% inertiaEllipse - Inertia ellipse of a set of points
-%% isPointInEllipse - Check if a point is located inside a given ellipse
-%% ellipseAsPolygon - Convert an ellipse into a series of points
-%% drawEllipse - Draw an ellipse on the current axis
-%% drawEllipseArc - Draw an ellipse arc on the current axis
-%%
-%% Geometric transforms
-%% transforms2d - Description of functions operating on transforms
-%% createTranslation - Create the 3*3 matrix of a translation
-%% createRotation - Create the 3*3 matrix of a rotation
-%% createScaling - Create the 3*3 matrix of a scaling in 2 dimensions
-%% createHomothecy - Create the the 3x3 matrix of an homothetic transform
-%% createBasisTransform - Compute matrix for transforming a basis into another basis
-%% createLineReflection - Create the the 3x3 matrix of a line reflection
-%% fitAffineTransform2d - Fit an affine transform using two point sets
-%%
-%% Angles
-%% angles2d - Description of functions for manipulating angles
-%% normalizeAngle - Normalize an angle value within a 2*PI interval
-%% angleAbsDiff - Absolute difference between two angles
-%% angleDiff - Difference between two angles
-%% deg2rad - Convert angle from degrees to radians
-%% rad2deg - Convert angle from radians to degrees
-%%
-%% Boxes
-%% boxes2d - Description of functions operating on bounding boxes
-%% intersectBoxes - Intersection of two bounding boxes
-%% mergeBoxes - Merge two boxes, by computing their greatest extent
-%% randomPointInBox - Generate random point within a box
-%% drawBox - Draw a box defined by coordinate extents
-%%
-%% Various drawing functions
-%% drawBezierCurve - Draw a cubic bezier curve defined by 4 control points
-%% drawParabola - Draw a parabola on the current axis
-%% drawOrientedBox - Draw centered oriented rectangle
-%% drawRect - Draw rectangle on the current axis
-%% drawArrow - Draw an arrow on the current axis
-%% drawLabels - Draw labels at specified positions
-%% drawShape - Draw various types of shapes (circles, polygons...)
-%%
-%% Other shapes
-%% squareGrid - Generate equally spaces points in plane.
-%% hexagonalGrid - Generate hexagonal grid of points in the plane.
-%% triangleGrid - Generate triangular grid of points in the plane.
-%% crackPattern - Create a (bounded) crack pattern tessellation
-%% crackPattern2 - Create a (bounded) crack pattern tessellation
-%%
-%%
-%% Credits:
-%% * function 'enclosingCircle' rewritten from a file from Yazan Ahed
-%% , available on Matlab File Exchange
-%%
-%% @end deftypefn
-
-function geometry_Contents ()
-
- help('Contents');
-
- %% Deprecated functions
-
- % createMedian - create a median line
- % minDistance - compute minimum distance between a point and a set of points
- % homothecy - create a homothecy as an affine transform
- % rotation - return 3*3 matrix of a rotation
- % translation - return 3*3 matrix of a translation
- % scaling - return 3*3 matrix of a scaling in 2 dimensions
- % lineSymmetry - create line symmetry as 2D affine transform
- % vecnorm - compute norm of vector or of set of vectors
- % normalize - normalize a vector
- % onCircle - test if a point is located on a given circle.
- % inCircle - test if a point is located inside a given circle.
- % onEdge - test if a point belongs to an edge
- % onLine - test if a point belongs to a line
- % onRay - test if a point belongs to a ray
- % invertLine - return same line but with opposite orientation
- % clipLineRect - clip a line with a polygon
- % formatAngle - Ensure an angle value is comprised between 0 and 2*PI
-
-
- %% Others...
- % drawRect2 - Draw centered rectangle on the current axis
-
-endfunction
-
diff --git a/inst/io/data2geo.m b/inst/io/data2geo.m
index 94ff611..d349a5e 100644
--- a/inst/io/data2geo.m
+++ b/inst/io/data2geo.m
@@ -16,7 +16,7 @@
%% -*- texinfo -*-
%% @deftypefn {Function File} {@var{fileStr} =} data2geo (@var{data}, @var{lc})
%% @deftypefnx {Function File} {@var{fileStr} =} data2geo (@dots{}, @var{param}, @var{value})
-%% Builds a file compatible with gmsh form data.
+%% Uses data to build a file compatible with Gmsh.
%%
%% @var{data} is assumed to describe a polygon in @code{polygon2d} format.
%% The argument @var{lc} specifies the edge size.
@@ -97,6 +97,7 @@ endfunction
%! ids = dc.pathid();
%! P = dc.path2polygon(ids{1},12)(1:end-1,:);
%! P = bsxfun(@minus, P, centroid(P));
+%! P = simplifypolygon(P,'tol',5e-1);
%! filename = tmpnam ();
%! meshsize = sqrt(mean(sumsq(diff(P,1,1),2)))/2;
%! data2geo (P, meshsize, 'output', [filename '.geo']);
diff --git a/inst/io/private/SVGstrPath2SVGpath.m b/inst/io/private/SVGstrPath2SVGpath.m
deleted file mode 100644
index 71c0dea..0000000
--- a/inst/io/private/SVGstrPath2SVGpath.m
+++ /dev/null
@@ -1,103 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-function SVGpath = SVGstrPath2SVGpath (SVGstrPath)
-
- nPaths = numel (SVGstrPath);
- SVGpath = repmat (struct('coord', [], 'closed', [], 'id', []), 1, nPaths);
-
- for ip = 1:nPaths
- path = SVGstrPath{ip};
-
- % Match data
- [s e te m] = regexpi (path, 'd="(?:(?!").)*');
- data=strtrim (m{1});
- % parse data
- d = parsePathData (data);
- SVGpath(ip).coord = d.coord;
- SVGpath(ip).closed = d.closed;
-
- % Match id
- [s e te m] = regexp (path, 'id="(?:(?!").)*');
- if ~isempty (m)
- SVGpath(ip).id = strtrim (m{1}(5:end));
- end
- end
-
-end
-
-function d = parsePathData (data)
-
- d = struct ('coord', [], 'closed', []);
-
- [s e te comm] = regexp (data, '[MmLlHhVvCcSsQqTtAaZz]{1}');
- % TODO
- % This info could be used to preallocate d
- [zcomm zpos] = ismember ({'Z','z'}, comm);
-
- if any (zcomm)
- d.closed = true;
- else
- d.closed = false;
- s(end+1) = length (data);
- end
- comm(zpos(zcomm)) = [];
- ncomm = size (comm, 2);
- for ic = 1:ncomm
-
- switch comm{ic}
- case {'M','L'}
- [x y] = strread (data(s(ic) + 1 : s(ic + 1) - 1), ...
- '%f%f', 'delimiter', ', ');
- coord = [x y];
-
- case 'm'
- [x y] = strread( data(s(ic) + 1 : s(ic + 1) - 1), ...
- '%f%f', 'delimiter', ', ');
- nc = size (x, 1);
- coord = [x y];
- if ic == 1
- % relative moveto at begining of data.
- % First coordinates are absolute, the rest are relative.
- coord = cumsum (coord);
- else
- % Relative moveto.
- % The coordinates are relative to the last one loaded
- coord(1,:) =coord(1,:) + d.coord(end,:);
- coord = cumsum(coord);
- warning('svg2octWarning',['Relative moveto in path data.'...
- ' May mean that the orginal path was not a simple polygon.' ...
- ' If that is the case, the path will not display equally.'])
- end
-
- case 'l'
- % Relative lineto, coordinates are relative to last point loaded.
- [x y] = strread( data(s(ic) + 1 : s(ic + 1) - 1), ...
- '%f%f', 'delimiter', ', ');
- nc = size (x, 1);
- coord = [x y]
- coord(1,:) =coord(1,:) + d.coord(end,:);
- coord = cumsum(coord);
-
- otherwise
- warning('svg2oct:Warning',...
- 'Path data command "%s" not implemented yet.',comm{ic});
- end
-
- nc = size(coord,1);
- d.coord(end+1:end+nc,:) = coord;
-
- end
-end
diff --git a/inst/io/private/_parsePath.py b/inst/io/private/_parsePath.py
deleted file mode 100644
index a6738ae..0000000
--- a/inst/io/private/_parsePath.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-
-import inkex, simplepath
-import sys
-#import getopt
-
-def parsePaths (filen=None):
-
- svg = inkex.Effect ()
- svg.parse (filen)
-
- paths = svg.document.xpath ('//svg:path', namespaces=inkex.NSS)
- for path in paths:
- D = simplepath.parsePath (path.attrib['d'])
- cmdlst = [];
- parlst = [];
- for cmd,params in D:
- cmdlst.append(cmd)
- parlst.append(params)
-
- print 'svgpath = struct("cmd","{0}","data",{{{1}}});' \
- .format(''.join(cmdlst),str(parlst).replace('[[','[').replace(']]',']'))
-
- print 'svgpathid = "{0}"; $'.format(path.attrib['id'])
-
-
-
-# ----------------------------
-
-if __name__=="__main__":
- '''
- try:
- optlist,args = getopt.getopt(sys.argv[1:],"thdp")
- except getopt.GetoptError:
- usage()
- sys.exit(2)
-
- doHelp = 0
- c = Context()
- c.doPrint = 1
- for opt in optlist:
- if opt[0] == "-d": c.debug = 1
- if opt[0] == "-p": c.plot = 1
- if opt[0] == "-t": c.triangulate = 1
- if opt[0] == "-h": doHelp = 1
-
- if not doHelp:
- pts = []
- fp = sys.stdin
- if len(args) > 0:
- fp = open(args[0],'r')
- for line in fp:
- fld = line.split()
- x = float(fld[0])
- y = float(fld[1])
- pts.append(Site(x,y))
- if len(args) > 0: fp.close()
-
- if doHelp or len(pts) == 0:
- usage()
- sys.exit(2)
- '''
- svg = sys.argv[1]
- parsePaths(svg)
diff --git a/inst/io/private/formatSVGstr.m b/inst/io/private/formatSVGstr.m
deleted file mode 100644
index a1310e6..0000000
--- a/inst/io/private/formatSVGstr.m
+++ /dev/null
@@ -1,24 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-function svgF = formatSVGstr(svg)
-
- % Remove all newlines and tabs
- svgF = strrep(svg,"\n",' ');
- svgF = strrep(svgF,"\t",' ');
- % Remove consecutive blanks
- svgF = regexprep(svgF,' +',' ');
-
-end
diff --git a/inst/io/private/getSVGPaths_py.m b/inst/io/private/getSVGPaths_py.m
deleted file mode 100644
index cca08ee..0000000
--- a/inst/io/private/getSVGPaths_py.m
+++ /dev/null
@@ -1,113 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-function Paths = getSVGPaths_py (svg, varargin)
-
- %% Call python script
- if exist (svg,'file')
- % read from file
- [st str]=system (sprintf ('python parsePath.py %s', svg));
-
- else
- % inline SVG
- [st str]=system (sprintf ('python parsePath.py < %s', svg));
- end
-
- %% Parse ouput
- strpath = strsplit (str(1:end-1), '$', true);
-
- npaths = numel (strpath);
-
- %% Convert path data to polygons
- for ip = 1:npaths
-
- eval (strpath{ip});
- %% FIXME: intialize struct with cell field
- svgpath2.cmd = svgpath(1).cmd;
- svgpath2.data = {svgpath.data};
-
- nD = length(svgpath2.cmd);
- pathdata = cell (nD-1,1);
-
- point_end=[];
- %% If the path is closed, last command is Z and we set initial point == final
- if svgpath2.cmd(end) == 'Z'
- nD -= 1;
- point_end = svgpath2.data{1};
- end
-
- %% Initial point
- points(1,:) = svgpath2.data{1};
-
- for jp = 2:nD
- switch svgpath2.cmd(jp)
- case 'L'
- %% Straigth segment to polygon
- points(2,:) = svgpath2.data{jp};
- pp = [(points(2,:)-points(1,:))' points(1,:)'];
- clear points
- points(1,:) = [polyval(pp(1,:),1) polyval(pp(2,:),1)];
-
- case 'C'
- %% Cubic bezier to polygon
- points(2:4,:) = reshape (svgpath2.data{jp}, 2, 3).';
- pp = cbezier2poly (points);
- clear points
- points(1,:) = [polyval(pp(1,:),1) polyval(pp(2,:),1)];
- end
-
- pathdata{jp-1} = pp;
- end
-
- if ~isempty(point_end)
- %% Straight segmet to close the path
- points(2,:) = point_end;
- pp = [(points(2,:)-points(1,:))' points(1,:)'];
-
- pathdata{end} = pp;
- end
-
- Paths.(svgpathid).data = pathdata;
- end
-endfunction
-
-%!test
-%! figure(1)
-%! hold on
-%! paths = getSVGPaths_py ('../drawing.svg');
-%!
-%! % Get path ids
-%! ids = fieldnames(paths);
-%! npath = numel(ids);
-%!
-%! t = linspace (0, 1, 64);
-%!
-%! for i = 1:npath
-%! x = []; y = [];
-%! data = paths.(ids(i)).data;
-%!
-%! for j = 1:numel(data)
-%! x = cat (2, x, polyval (data{j}(1,:),t));
-%! y = cat (2, y, polyval (data{j}(2,:),t));
-%! end
-%!
-%! plot(x,y,'-');
-%! end
-%! axis ij
-%! if strcmpi(input('You should see drawing.svg [y/n] ','s'),'n')
-%! error ("didn't get what was expected.");
-%! end
-%! close
-
diff --git a/inst/io/private/getSVGdata.m b/inst/io/private/getSVGdata.m
deleted file mode 100644
index 21a1dd8..0000000
--- a/inst/io/private/getSVGdata.m
+++ /dev/null
@@ -1,33 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-function svgData = getSVGdata(svg)
-
- svgData = struct('height',[],'width',[]);
- attr = fieldnames(svgData);
- nattr = numel(attr);
-
- [s e te data] = regexpi(svg,'<[ ]*svg(?:(?!>).)*>');
- data=strtrim(data{1});
-
- for a = 1:nattr
- pattr =sprintf('%s="(?:(?!").)*',attr{a});
- [s e te m] = regexpi(data,pattr);
- m=strtrim(m{1});
- [dummy value] = strread(m,'%s%f','delimiter','"');
- svgData.(attr{a}) = value;
- end
-
-end
diff --git a/inst/io/private/parsePath.py b/inst/io/private/parsePath.py
deleted file mode 100644
index a6738ae..0000000
--- a/inst/io/private/parsePath.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-
-import inkex, simplepath
-import sys
-#import getopt
-
-def parsePaths (filen=None):
-
- svg = inkex.Effect ()
- svg.parse (filen)
-
- paths = svg.document.xpath ('//svg:path', namespaces=inkex.NSS)
- for path in paths:
- D = simplepath.parsePath (path.attrib['d'])
- cmdlst = [];
- parlst = [];
- for cmd,params in D:
- cmdlst.append(cmd)
- parlst.append(params)
-
- print 'svgpath = struct("cmd","{0}","data",{{{1}}});' \
- .format(''.join(cmdlst),str(parlst).replace('[[','[').replace(']]',']'))
-
- print 'svgpathid = "{0}"; $'.format(path.attrib['id'])
-
-
-
-# ----------------------------
-
-if __name__=="__main__":
- '''
- try:
- optlist,args = getopt.getopt(sys.argv[1:],"thdp")
- except getopt.GetoptError:
- usage()
- sys.exit(2)
-
- doHelp = 0
- c = Context()
- c.doPrint = 1
- for opt in optlist:
- if opt[0] == "-d": c.debug = 1
- if opt[0] == "-p": c.plot = 1
- if opt[0] == "-t": c.triangulate = 1
- if opt[0] == "-h": doHelp = 1
-
- if not doHelp:
- pts = []
- fp = sys.stdin
- if len(args) > 0:
- fp = open(args[0],'r')
- for line in fp:
- fld = line.split()
- x = float(fld[0])
- y = float(fld[1])
- pts.append(Site(x,y))
- if len(args) > 0: fp.close()
-
- if doHelp or len(pts) == 0:
- usage()
- sys.exit(2)
- '''
- svg = sys.argv[1]
- parsePaths(svg)
diff --git a/inst/io/svgload.m b/inst/io/svgload.m
deleted file mode 100644
index a9e9963..0000000
--- a/inst/io/svgload.m
+++ /dev/null
@@ -1,62 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-%% -*- texinfo -*-
-%% @deftypefn {Function File} @var{SVG} = loadSVG (@var{filename})
-%% Reads the plain SVG file @var{filename} and returns an SVG structure.
-%%
-%% In the current version only SVG path elements are parsed and stored in the field
-%% path of the @var{SVG} structure.
-%% The coordinates of the path are not modified in anyway. This produces the path
-%% to be ploted vertically reflected.
-%%
-%% @seealso{svgnormalize, svgpath2polygon}
-%% @end deftypefn
-
-
-function SVG = svgload (filename)
-
- SVG = struct ('height', [], 'width', [], 'path', [], 'normalized', []);
-
- SVG.normalized = false;
-
- fid = fopen (filename);
- svg = char (fread (fid, "uchar")');
- fclose (fid);
- svgF = formatSVGstr (svg);
-
- % Get SVG Data
- data = getSVGdata (svgF);
- SVG.height = data.height;
- SVG.width = data.width;
-
- % Get SVG Paths
- SVGstrPath = getSVGstrPath (svgF);
- SVGpath = SVGstrPath2SVGpath (SVGstrPath);
- SVG.path = SVGpath;
-
-end
-
-%!demo
-%! file = 'tmp__.svg';
-%! fid = fopen (file,'w');
-%! svgfile = '<html><body><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="250" width="250"><path d="M150,0 75,200 225,200 Z" /></svg></body></html>';
-%! fprintf (fid,"%s\n",svgfile);
-%! fclose (fid);
-%! SVG = svgload (file);
-%! SVG
-%! plot([SVG.path.coord(:,1); SVG.path.coord(1,1)], ...
-%! [SVG.path.coord(:,2); SVG.path.coord(1,2)]);
-%! delete (file);
diff --git a/inst/io/svgnormalize.m b/inst/io/svgnormalize.m
deleted file mode 100644
index 381d29a..0000000
--- a/inst/io/svgnormalize.m
+++ /dev/null
@@ -1,68 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-%% -*- texinfo -*-
-%% @deftypefn {Function File} @var{SVGn} = loadSVG (@var{SVG})
-%% Scales and reflects the @var{SVG} structure and returns a modified @var{SVGn}
-%% structure.
-%%
-%% The height and width of the SVG are scaled such that the diagonal of the
-%% bounding box has length 1. Coordinates are trasnfomed such that a plot of the
-%% paths coincides with the visualization of the original SVG.
-%%
-%% @seealso{svgload, svgpath2polygon}
-%% @end deftypefn
-
-function SVGn = svgnormalize (SVG)
-
- SVGn = SVG;
- if ~SVG.normalized
- % Translate
- TransV = [0, SVG.height/2];
- % Scale
- Dnorm = sqrt (SVG.width ^ 2 + SVG.height ^ 2);
- S = (1 / Dnorm) * eye (2);
- for i = 1:numel (SVG.path)
- nc = size (SVG.path(i).coord, 1);
- % Translate to middle
- T = repmat (TransV,nc, 1);
- SVGn.path(i).coord = SVG.path(i).coord - T;
- % Reflect
- SVGn.path(i).coord(:, 2) = -SVGn.path(i).coord(:,2);
- T(:,2) = -T(:,2);
- % Translate to bottom
- SVGn.path(i).coord = SVGn.path(i).coord - T;
- %Scale
- SVGn.path(i).coord = SVGn.path(i).coord * S;
- end
- SVGn.height = SVG.height / Dnorm;
- SVGn.width = SVG.width / Dnorm;
- SVGn.normalized = true;
- end
-
-end
-
-%!demo
-%! file = 'tmp__.svg';
-%! fid = fopen (file,'w');
-%! svgfile = '<html><body><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="250" width="250"><path d="M150,0 75,200 225,200 Z" /></svg></body></html>';
-%! fprintf (fid,"%s\n",svgfile);
-%! fclose (fid);
-%! SVG = svgload (file);
-%! SVGn = svgnormalize (SVG);
-%! SVGn
-%! plot([SVGn.path.coord(:,1); SVGn.path.coord(1,1)], ...
-%! [SVGn.path.coord(:,2); SVGn.path.coord(1,2)]);
-%! delete (file);
diff --git a/inst/io/svgpath2polygon.m b/inst/io/svgpath2polygon.m
deleted file mode 100644
index e03a78f..0000000
--- a/inst/io/svgpath2polygon.m
+++ /dev/null
@@ -1,60 +0,0 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
-%% This program is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% any later version.
-%%
-%% This program is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-%% -*- texinfo -*-
-%% @deftypefn {Function File} @var{P} = svgpath2polygon (@var{SVGpath})
-%% Converts the SVG path structure @var{SVGpath} to an array of polygons
-%% compatible with the geometry package and matGeom (@url{http://matgeom.sf.net}).
-%%
-%% @var{SVGpath} is a substructure of the SVG structure output by loadSVG. This
-%% function extracts the field named "coord" if there is only one path. If there
-%% are more than oe path it puts the "coord" field of each path in the same
-%% array, separated by nans.
-%%
-%% @seealso{svgnormalize, svgload}
-%% @end deftypefn
-
-function P = svgpath2polygon (SVGpath)
-
- P = SVGpath(1).coord;
- for ip = 2:numel (SVGpath)
- P = [P; nan(1,2); SVGpath(ip).coord];
- end
-
-end
-
-%!demo
-%! file = 'tmp__.svg';
-%! fid = fopen (file,'w');
-%! svgfile = '<html><body><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="250" width="250"><path d="M150,0 75,200 225,200 Z" /></svg></body></html>';
-%! fprintf (fid,"%s\n",svgfile);
-%! fclose (fid);
-%! SVG = svgload (file);
-%! SVG = svgnormalize (SVG);
-%! P = svgpath2polygon (SVG.path);
-%! plot (P(:,1),P(:,2));
-%! delete (file);
-
-%!demo
-%! file = 'tmp__.svg';
-%! fid = fopen (file,'w');
-%! svgfile = '<html><body><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="250" width="250"><path d="M150,0 75,200 225,200 Z" /><path d="M0,0 100,0 100,100 0,100 Z" /></svg></body></html>';
-%! fprintf (fid,"%s\n",svgfile);
-%! fclose (fid);
-%! SVG = svgload (file);
-%! SVG = svgnormalize (SVG);
-%! P = svgpath2polygon (SVG.path);
-%! plot (P(:,1),P(:,2));
-%! delete (file);
diff --git a/inst/octclip/oc_polybool.m b/inst/octclip/oc_polybool.m
index 05c9f96..259f057 100644
--- a/inst/octclip/oc_polybool.m
+++ b/inst/octclip/oc_polybool.m
@@ -45,7 +45,7 @@
##
## For the matrices @var{sub} and @var{clip}, the first point is not needed to
## be repeated at the end (but is permitted). Pairs of (NaN,NaN) coordinates in
-## @var{sub} and/or @var{clip} are ommitted.
+## @var{sub} and/or @var{clip} are omitted.
##
## @var{X} is a column vector containing the X coordinates of the vertices for.
## resultant polygon(s).
diff --git a/inst/octclip/src/_oc_polybool.cc b/inst/octclip/src/_oc_polybool.cc
index b40e7e5..db696a5 100644
--- a/inst/octclip/src/_oc_polybool.cc
+++ b/inst/octclip/src/_oc_polybool.cc
@@ -49,7 +49,7 @@ Operation of @var{clip} - @var{sub}.\n\
\n\
For the matrices @var{sub} and @var{clip}, the first point is not needed to\n\
be repeated at the end (but is permitted). Pairs of (NaN,NaN) coordinates in\n\
-@var{sub} and/or @var{clip} are ommitted.\n\
+@var{sub} and/or @var{clip} are omitted.\n\
\n\
@var{X} is a column vector containing the X coordinates of the vertices for.\n\
resultant polygon(s).\n\n\
diff --git a/inst/polygons2d/curvature.m b/inst/polygons2d/curvature.m
new file mode 100644
index 0000000..e14b14c
--- /dev/null
+++ b/inst/polygons2d/curvature.m
@@ -0,0 +1,177 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{kappa} = } curvature (@var{t}, @var{px}, @var{py},@var{method},@var{degree})
+%% @deftypefnx {Function File} {@var{kappa} = } curvature (@var{t}, @var{poly},@var{method},@var{degree})
+%% @deftypefnx {Function File} {@var{kappa} = } curvature (@var{px}, @var{py},@var{method},@var{degree})
+%% @deftypefnx {Function File} {@var{kappa} = } curvature (@var{points},@var{method},@var{degree})
+%% @deftypefnx {Function File} {[@var{kappa} @var{poly} @var{t}] = } curvature (@dots{})
+%% Estimate curvature of a polyline defined by points.
+%%
+%% First compute an approximation of the curve given by PX and PY, with
+%% the parametrization @var{t}. Then compute the curvature of approximated curve
+%% for each point.
+%% @var{method} used for approximation can be only: 'polynom', with specified degree.
+%% Further methods will be provided in a future version.
+%% @var{t}, @var{px}, and @var{py} are N-by-1 array of the same length. The points
+%% can be specified as a single N-by-2 array.
+%%
+%% If the argument @var{t} is not given, the parametrization is estimated using
+%% function @code{parametrize}.
+%%
+%% If requested, @var{poly} contains the approximating polygon evlauted at the
+%% parametrization @var{t}.
+%%
+%% @seealso{parametrize, polygons2d}
+%% @end deftypefn
+
+function [kappa, varargout] = curvature(varargin)
+
+ % default values
+ degree = 5;
+ t=0; % parametrization of curve
+ tc=0; % indices of points wished for curvature
+
+
+ % =================================================================
+
+ % Extract method and degree ------------------------------
+
+ nargin = length(varargin);
+ varN = varargin{nargin};
+ varN2 = varargin{nargin-1};
+
+ if ischar(varN2)
+ % method and degree are specified
+ method = varN2;
+ degree = varN;
+ varargin = varargin(1:nargin-2);
+ elseif ischar(varN)
+ % only method is specified, use degree 6 as default
+ method = varN;
+ varargin = varargin{1:nargin-1};
+ else
+ % method and degree are implicit : use 'polynom' and 6
+ method = 'polynom';
+ end
+
+ % extract input parametrization and curve. -----------------------
+ nargin = length(varargin);
+ if nargin==1
+ % parameters are just the points -> compute caracterization.
+ var = varargin{1};
+ px = var(:,1);
+ py = var(:,2);
+ elseif nargin==2
+ var = varargin{2};
+ if size(var, 2)==2
+ % parameters are t and POINTS
+ px = var(:,1);
+ py = var(:,2);
+ t = varargin{1};
+ else
+ % parameters are px and py
+ px = varargin{1};
+ py = var;
+ end
+ elseif nargin==3
+ var = varargin{2};
+ if size(var, 2)==2
+ % parameters are t, POINTS, and tc
+ px = var(:,1);
+ py = var(:,2);
+ t = varargin{1};
+ else
+ % parameters are t, px and py
+ t = varargin{1};
+ px = var;
+ py = varargin{3};
+ end
+ elseif nargin==4
+ % parameters are t, px, py and tc
+ t = varargin{1};
+ px = varargin{2};
+ py = varargin{3};
+ tc = varargin{4};
+ end
+
+ % compute implicit parameters --------------------------
+
+ % if t and/or tc are not computed, use implicit definition
+ if t==0
+ t = parametrize(px, py, 'norm');
+ end
+
+ % if tc not defined, compute curvature for all points
+ if tc==0
+ tc = t;
+ else
+ % else convert from indices to parametrization values
+ tc = t(tc);
+ end
+
+
+ % =================================================================
+ % compute curvature for each point of the curve
+
+ if strcmp(method, 'polynom')
+ % compute coefficients of interpolation functions
+ x0 = polyfit(t, px, degree);
+ y0 = polyfit(t, py, degree);
+
+ % compute coefficients of first and second derivatives. In the case of a
+ % polynom, it is possible to compute coefficient of derivative by
+ % multiplying with a matrix.
+ derive = diag(degree:-1:0);
+ xp = circshift(x0*derive, [0 1]);
+ yp = circshift(y0*derive, [0 1]);
+ xs = circshift(xp*derive, [0 1]);
+ ys = circshift(yp*derive, [0 1]);
+
+ % compute values of first and second derivatives for needed points
+ xprime = polyval(xp, tc);
+ yprime = polyval(yp, tc);
+ xsec = polyval(xs, tc);
+ ysec = polyval(ys, tc);
+
+ % compute value of curvature
+ kappa = (xprime.*ysec - xsec.*yprime)./ ...
+ power(xprime.*xprime + yprime.*yprime, 3/2);
+
+ if nargout > 1
+ varargout{1} = [polyval(x0,tc(:)) polyval(y0,tc(:))];
+ if nargout > 2
+ varargout{2} = tc;
+ end
+ end
+ else
+ error('unknown method');
+ end
+
+endfunction
diff --git a/inst/polygons2d/distancePointPolygon.m b/inst/polygons2d/distancePointPolygon.m
new file mode 100755
index 0000000..6290b91
--- /dev/null
+++ b/inst/polygons2d/distancePointPolygon.m
@@ -0,0 +1,51 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{dist} = } distancePointPolygon (@var{point},@var{poly})
+## Compute shortest distance between a point and a polygon
+##
+## @seealso{polygons2d, points2d, distancePointPolyline, distancePointEdge, projPointOnPolyline}
+## @end deftypefn
+
+function varargout = distancePointPolygon(point, poly)
+
+ % eventually copy first point at the end to ensure closed polygon
+ if sum(poly(end, :)==poly(1,:))~=2
+ poly = [poly; poly(1,:)];
+ end
+
+ % call to distancePointPolyline
+ minDist = distancePointPolyline(point, poly);
+
+ % process output arguments
+ if nargout<=1
+ varargout{1} = minDist;
+ end
+
+endfunction
diff --git a/inst/polygons2d/distancePointPolyline.m b/inst/polygons2d/distancePointPolyline.m
new file mode 100755
index 0000000..c4fcd4a
--- /dev/null
+++ b/inst/polygons2d/distancePointPolyline.m
@@ -0,0 +1,71 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{dist} = } distancePointPolyline (@var{point},@var{poly})
+## Compute shortest distance between a point and a polyline
+## Example:
+## @example
+## pt1 = [30 20];
+## pt2 = [30 5];
+## poly = [10 10;50 10;50 50;10 50];
+## distancePointPolyline([pt1;pt2], poly)
+## ans =
+## 10
+## 5
+## @end example
+##
+## @seealso{polygons2d, points2d,distancePointEdge, projPointOnPolyline}
+## @end deftypefn
+
+function varargout = distancePointPolyline(point, poly, varargin)
+
+ # number of points
+ Np = size(point, 1);
+
+ # allocate memory for result
+ minDist = inf * ones(Np, 1);
+
+ # process each point
+ for p = 1:Np
+ # construct the set of edges
+ edges = [poly(1:end-1, :) poly(2:end, :)];
+
+ # compute distance between current each point and all edges
+ dist = distancePointEdge(point(p, :), edges);
+
+ # update distance if necessary
+ minDist(p) = min(dist);
+ end
+
+ # process output arguments
+ if nargout<=1
+ varargout{1} = minDist;
+ end
+
+endfunction
diff --git a/inst/polygons2d/distancePolygons.m b/inst/polygons2d/distancePolygons.m
new file mode 100755
index 0000000..53dfc9b
--- /dev/null
+++ b/inst/polygons2d/distancePolygons.m
@@ -0,0 +1,43 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{dist} = } distancePolygons (@var{poly1},@var{poly2})
+## Compute the shortest distance between 2 polygons
+##
+## @end deftypefn
+function dist = distancePolygons(poly1, poly2)
+
+ # compute distance of each vertex of a polygon to the other polygon
+ dist1 = min(distancePointPolygon(poly1, poly2));
+ dist2 = min(distancePointPolygon(poly2, poly1));
+
+ # keep the minimum of the two distances
+ dist = min(dist1, dist2);
+
+endfunction
diff --git a/inst/polygons2d/expandPolygon.m b/inst/polygons2d/expandPolygon.m
new file mode 100755
index 0000000..d009454
--- /dev/null
+++ b/inst/polygons2d/expandPolygon.m
@@ -0,0 +1,85 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{loops} = } expandPolygon (@var{poly}, @var{dist})
+## Expand a polygon by a given (signed) distance
+##
+## Associates to each edge of the polygon @var{poly} the parallel line located
+## at distance @var{dist} from the current edge, and compute intersections with
+## neighbor parallel lines. The resulting polygon is simplified to remove
+## inner "loops", and can be disconnected.
+## The result is a cell array, each cell containing a simple linear ring.
+##
+## This is a kind of dilation, but behaviour on corners is different.
+## This function keeps angles of polygons, but there is no direct relation
+## between length of 2 polygons.
+##
+## It is also possible to specify negative distance, and get all points
+## inside the polygon. If the polygon is convex, the result equals
+## morphological erosion of polygon by a ball with radius equal to the
+## given distance.
+##
+## @seealso{polygons2d}
+## @end deftypefn
+
+function loops = expandPolygon(poly, dist)
+
+ # eventually copy first point at the end to ensure closed polygon
+ if sum(poly(end, :)==poly(1,:))~=2
+ poly = [poly; poly(1,:)];
+ end
+
+ # number of vertices of the polygon
+ N = size(poly, 1)-1;
+
+ # find lines parallel to polygon edges located at distance DIST
+ lines = zeros(N, 4);
+ for i=1:N
+ side = createLine(poly(i,:), poly(i+1,:));
+ lines(i, 1:4) = parallelLine(side, dist);
+ end
+
+ # compute intersection points of consecutive lines
+ lines = [lines;lines(1,:)];
+ poly2 = zeros(N, 2);
+ for i=1:N
+ poly2(i,1:2) = intersectLines(lines(i,:), lines(i+1,:));
+ end
+
+ # split result polygon into set of loops (simple polygons)
+ loops = polygonLoops(poly2);
+
+ # keep only loops whose distance to original polygon is correct
+ distLoop = zeros(length(loops), 1);
+ for i=1:length(loops)
+ distLoop(i) = distancePolygons(loops{i}, poly);
+ end
+ loops = loops(abs(distLoop-abs(dist))<abs(dist)/1000);
+
+endfunction
diff --git a/inst/polygons2d/medialAxisConvex.m b/inst/polygons2d/medialAxisConvex.m
new file mode 100755
index 0000000..ac7a1fa
--- /dev/null
+++ b/inst/polygons2d/medialAxisConvex.m
@@ -0,0 +1,153 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {[@var{n} @var{e}] = } medialAxisConvex (@var{polygon})
+## Compute medial axis of a convex polygon
+##
+## @var{polygon} is given as a set of points [x1 y1;x2 y2 ...], returns
+## the medial axis of the polygon as a graph.
+## @var{n} is a set of nodes. The first elements of @var{n} are the vertices of the
+## original polygon.
+## @var{e} is a set of edges, containing indices of source and target nodes.
+## Edges are sorted according to order of creation. Index of first vertex
+## is lower than index of last vertex, i.e. edges always point to newly
+## created nodes.
+##
+## Notes:
+## - Is not fully implemented, need more development (usually crashes for
+## polygons with more than 6-7 points...)
+## - Works only for convex polygons.
+## - Complexity is not optimal: this algorithm is O(n*log n), but linear
+## algorithms exist.
+##
+## @seealso{polygons2d, bisector}
+## @end deftypefn
+
+function [nodes, edges] = medialAxisConvex(points)
+
+ # eventually remove the last point if it is the same as the first one
+ if points(1,:) == points(end, :)
+ nodes = points(1:end-1, :);
+ else
+ nodes = points;
+ end
+
+ # special case of triangles:
+ # compute directly the gravity center, and simplify computation.
+ if size(nodes, 1)==3
+ nodes = [nodes; mean(nodes, 1)];
+ edges = [1 4;2 4;3 4];
+ return
+ end
+
+ # number of nodes, and also of initial rays
+ N = size(nodes, 1);
+
+ # create ray of each vertex
+ rays = zeros(N, 4);
+ rays(1, 1:4) = bisector(nodes([2 1 N], :));
+ rays(N, 1:4) = bisector(nodes([1 N N-1], :));
+ for i=2:N-1
+ rays(i, 1:4) = bisector(nodes([i+1, i, i-1], :));
+ end
+
+ # add indices of edges producing rays (indices of first vertex, second
+ # vertex is obtained by adding one modulo N).
+ rayEdges = [[N (1:N-1)]' (1:N)'];
+
+ pint = intersectLines(rays, rays([2:N 1], :));
+ #ti = linePosition(pint, rays);
+ #ti = min(linePosition(pint, rays), linePosition(pint, rays([2:N 1], :)));
+ ti = distancePointLine(pint, ...
+ createLine(points([N (1:N-1)]', :), points((1:N)', :)));
+
+ # create list of events.
+ # terms are : R1 R2 X Y t0
+ # R1 and R2 are indices of involved rays
+ # X and Y is coordinate of intersection point
+ # t0 is position of point on rays
+ events = sortrows([ (1:N)' [2:N 1]' pint ti], 5);
+
+ # initialize edges
+ edges = zeros(0, 2);
+
+
+ # -------------------
+ # process each event until there is no more
+
+ # start after index of last vertex, and process N-3 intermediate rays
+ for i=N+1:2*N-3
+ # add new node at the rays intersection
+ nodes(i,:) = events(1, 3:4);
+
+ # add new couple of edges
+ edges = [edges; events(1,1) i; events(1,2) i];
+
+ # find the two edges creating the new emanating ray
+ n1 = rayEdges(events(1, 1), 1);
+ n2 = rayEdges(events(1, 2), 2);
+
+ # create the new ray
+ line1 = createLine(nodes(n1, :), nodes(mod(n1,N)+1, :));
+ line2 = createLine(nodes(mod(n2,N)+1, :), nodes(n2, :));
+ ray0 = bisector(line1, line2);
+
+ # set its origin to emanating point
+ ray0(1:2) = nodes(i, :);
+
+ # add the new ray to the list
+ rays = [rays; ray0];
+ rayEdges(size(rayEdges, 1)+1, 1:2) = [n1 n2];
+
+ # find the two neighbour rays
+ ind = sum(ismember(events(:,1:2), events(1, 1:2)), 2)==0;
+ ir = unique(events(ind, 1:2));
+ ir = ir(~ismember(ir, events(1,1:2)));
+
+ # create new intersections
+ pint = intersectLines(ray0, rays(ir, :));
+ #ti = min(linePosition(pint, ray0), linePosition(pint, rays(ir, :))) + events(1,5);
+ ti = distancePointLine(pint, line1);
+
+ # remove all events involving old intersected rays
+ ind = sum(ismember(events(:,1:2), events(1, 1:2)), 2)==0;
+ events = events(ind, :);
+
+ # add the newly formed events
+ events = [events; ir(1) i pint(1,:) ti(1); ir(2) i pint(2,:) ti(2)];
+
+ # and sort them according to 'position' parameter
+ events = sortrows(events, 5);
+ end
+
+ # centroid computation for last 3 rays
+ nodes = [nodes; mean(events(:, 3:4))];
+ edges = [edges; [unique(events(:,1:2)) ones(3, 1)*(2*N-2)]];
+
+endfunction
diff --git a/inst/polygons2d/parametrize.m b/inst/polygons2d/parametrize.m
new file mode 100644
index 0000000..0e36196
--- /dev/null
+++ b/inst/polygons2d/parametrize.m
@@ -0,0 +1,96 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{par} = } parametrize (@var{poly})
+%% @deftypefnx {Function File} {@var{par} = } parametrize (@var{px},@var{py})
+%% @deftypefnx {Function File} {@var{par} = } parametrize (@dots{},@var{normalize})
+%%
+%% Parametrization of a curve, based on edges length
+%%
+%% Returns a parametrization of the curve defined by the serie of points,
+%% based on euclidean distance between two consecutive points.
+%% POLY is a N-by-2 array, representing coordinates of vertices. The
+%% result PAR is N-by-1, and contains the cumulative length of edges until
+%% corresponding vertex. The function also accepts the polygon as two inputs
+%% @var{px} and @var{py} representinx coordinates x and y respectively.
+%% When optional argument @var{normalize} is non-empty @var{par} is rescaled
+%% such that the last element equals 1, i.e. @code{@var{par}(end)==1}.
+%%
+%% Example
+%% @example
+%% % Parametrize a circle approximation
+%% poly = circleToPolygon([0 0 1], 200);
+%% p = parametrize(poly);
+%% p(end)
+%% ans =
+%% 6.2829
+%% p = parametrize(poly,'norm');
+%% p(end)
+%% ans =
+%% 1
+%% p = parametrize(poly,true);
+%% p(end)
+%% ans =
+%% 1
+%% @end example
+%%
+%% @seealso{polygons2d, polylineLength}
+%% @end deftypefn
+function par = parametrize(varargin)
+ %% Process inputs
+
+ % extract vertex coordinates
+ if size(varargin{1}, 2) > 1
+ % vertices in a single array
+ pts = varargin{1};
+ normalize = numel(varargin) > 1;
+ elseif size(varargin{1}, 2) == 1 && numel(varargin) >= 2
+ % points as separate arrays
+ pts = [varargin{1} varargin{2}];
+ normalize = numel(varargin) > 2;
+ end
+
+ %% Parametrize polyline
+
+ % compute cumulative sum of euclidean distances between consecutive
+ % vertices, setting distance of first vertex to 0.
+ if size(pts, 2) == 2
+ % process points in 2D
+ par = [0 ; cumsum(hypot(diff(pts(:,1)), diff(pts(:,2))))];
+ else
+ % process points in arbitrary dimension
+ par = [0 ; cumsum(sqrt(sum(diff(pts).^2, 2)))];
+ end
+
+ % eventually rescale between 0 and 1
+ if normalize
+ par = par / par(end);
+ end
+
+endfunction
diff --git a/inst/polygons2d/polygonLoops.m b/inst/polygons2d/polygonLoops.m
new file mode 100755
index 0000000..e024f6b
--- /dev/null
+++ b/inst/polygons2d/polygonLoops.m
@@ -0,0 +1,143 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{loops} = } polygonLoops (@var{poly})
+## Divide a possibly self-intersecting polygon into a set of simple loops
+##
+## @var{poly} is a polygone defined by a series of vertices,
+## @var{loops} is a cell array of polygons, containing the same vertices of the
+## original polygon, but no loop self-intersect, and no couple of loops
+## intersect each other.
+##
+## Example:
+## @example
+## poly = [0 0;0 10;20 10;20 20;10 20;10 0];
+## loops = polygonLoops(poly);
+## figure(1); hold on;
+## drawPolygon(loops);
+## polygonArea(loops)
+## @end example
+##
+## @seealso{polygons2d, polygonSelfIntersections}
+## @end deftypefn
+
+function loops = polygonLoops(poly)
+
+ ## Initialisations
+
+ # compute intersections
+ [inters pos1 pos2] = polygonSelfIntersections(poly);
+
+ # case of a polygon without self-intersection
+ if isempty(inters)
+ loops = {poly};
+ return;
+ end
+
+ # array for storing loops
+ loops = cell(0, 1);
+
+ positions = sortrows([pos1 pos2;pos2 pos1]);
+
+
+ ## First loop
+
+ pos0 = 0;
+ loop = polygonSubcurve(poly, pos0, positions(1, 1));
+ pos = positions(1, 2);
+ positions(1, :) = [];
+
+ while true
+ # index of next intersection point
+ ind = find(positions(:,1)>pos, 1, 'first');
+
+ # if not found, break
+ if isempty(ind)
+ break;
+ end
+
+ # add portion of curve
+ loop = [loop;polygonSubcurve(poly, pos, positions(ind, 1))]; ##ok<AGROW>
+
+ # look for next intersection point
+ pos = positions(ind, 2);
+ positions(ind, :) = [];
+ end
+
+ # add the last portion of curve
+ loop = [loop;polygonSubcurve(poly, pos, pos0)];
+
+ # remove redundant vertices
+ loop(sum(loop(1:end-1,:) == loop(2:end,:) ,2)==2, :) = [];
+ if sum(diff(loop([1 end], :))==0)==2
+ loop(end, :) = [];
+ end
+
+ # add current loop to the list of loops
+ loops{1} = loop;
+
+
+ ## Other loops
+
+ Nl = 1;
+ while ~isempty(positions)
+
+ loop = [];
+ pos0 = positions(1, 2);
+ pos = positions(1, 2);
+
+ while true
+ # index of next intersection point
+ ind = find(positions(:,1)>pos, 1, 'first');
+
+ # add portion of curve
+ loop = [loop;polygonSubcurve(poly, pos, positions(ind, 1))]; ##ok<AGROW>
+
+ # look for next intersection point
+ pos = positions(ind, 2);
+ positions(ind, :) = [];
+
+ # if not found, break
+ if pos==pos0
+ break;
+ end
+ end
+
+ # remove redundant vertices
+ loop(sum(loop(1:end-1,:) == loop(2:end,:) ,2)==2, :) = []; ##ok<AGROW>
+ if sum(diff(loop([1 end], :))==0)==2
+ loop(end, :) = []; ##ok<AGROW>
+ end
+
+ # add current loop to the list of loops
+ Nl = Nl + 1;
+ loops{Nl} = loop;
+ end
+
+endfunction
diff --git a/inst/polygons2d/polygonSelfIntersections.m b/inst/polygons2d/polygonSelfIntersections.m
new file mode 100755
index 0000000..ec5f43f
--- /dev/null
+++ b/inst/polygons2d/polygonSelfIntersections.m
@@ -0,0 +1,87 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{pts} = } polygonSelfIntersections (@var{poly})
+## @deftypefnx {Function File} {[@var{pts} @var{pos1} @var{pos2}] = } polygonSelfIntersections (@var{poly})
+## Find-self intersection points of a polygon
+##
+## Return the position of self intersection points
+##
+## Also return the 2 positions of each intersection point (the position
+## when meeting point for first time, then position when meeting point
+## for the second time).
+##
+## Example
+## @example
+## # use a '8'-shaped polygon
+## poly = [10 0;0 0;0 10;20 10;20 20;10 20];
+## polygonSelfIntersections(poly)
+## ans =
+## 10 10
+## @end example
+##
+## @seealso{polygons2d, polylineSelfIntersections}
+## @end deftypefn
+
+function varargout = polygonSelfIntersections(poly, varargin)
+
+ tol = 1e-14;
+
+ # ensure the last point equals the first one
+ if sum(abs(poly(end, :)-poly(1,:)) < tol) ~= 2
+ poly = [poly; poly(1,:)];
+ end
+
+ # compute intersections by calling algo for polylines
+ [points pos1 pos2] = polylineSelfIntersections(poly);
+
+ # It may append that first vertex of polygon is detected as intersection,
+ # the following tries to detect this
+ n = size(poly, 1) - 1;
+ inds = (pos1 == 0 & pos2 == n) | (pos1 == n & pos2 == 0);
+ points(inds, :) = [];
+ pos1(inds) = [];
+ pos2(inds) = [];
+
+ # remove multiple intersections
+ [points I J] = unique(points, 'rows', 'first'); ##ok<NASGU>
+ pos1 = pos1(I);
+ pos2 = pos2(I);
+
+
+ ## Post-processing
+
+ # process output arguments
+ if nargout <= 1
+ varargout = {points};
+ elseif nargout == 3
+ varargout = {points, pos1, pos2};
+ end
+
+endfunction
diff --git a/inst/polygons2d/polylineSelfIntersections.m b/inst/polygons2d/polylineSelfIntersections.m
new file mode 100755
index 0000000..d759be9
--- /dev/null
+++ b/inst/polygons2d/polylineSelfIntersections.m
@@ -0,0 +1,153 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{pts} = } polylineSelfIntersections (@var{poly})
+## Find self-intersections points of a polyline
+##
+## Return the position of self intersection points
+##
+## Also return the 2 positions of each intersection point (the position
+## when meeting point for first time, then position when meeting point
+## for the second time).
+##
+## Example
+## @example
+## # use a gamma-shaped polyline
+## poly = [0 0;0 10;20 10;20 20;10 20;10 0];
+## polylineSelfIntersections(poly)
+## ans =
+## 10 10
+##
+## # use a 'S'-shaped polyline
+## poly = [10 0;0 0;0 10;20 10;20 20;10 20];
+## polylineSelfIntersections(poly)
+## ans =
+## 10 10
+## @end example
+##
+## @seealso{polygons2d, intersectPolylines, polygonSelfIntersections}
+## @end deftypefn
+
+function varargout = polylineSelfIntersections(poly, varargin)
+
+ ## Initialisations
+
+ # determine whether the polyline is closed
+ closed = false;
+ if ~isempty(varargin)
+ closed = varargin{1};
+ if ischar(closed)
+ if strcmp(closed, 'closed')
+ closed = true;
+ elseif strcmp(closed, 'open')
+ closed = false;
+ end
+ end
+ end
+
+ # if polyline is closed, ensure the last point equals the first one
+ if closed
+ if sum(abs(poly(end, :)-poly(1,:))<1e-14)~=2
+ poly = [poly; poly(1,:)];
+ end
+ end
+
+ # arrays for storing results
+ points = zeros(0, 2);
+ pos1 = zeros(0, 1);
+ pos2 = zeros(0, 1);
+
+ # number of vertices
+ Nv = size(poly, 1);
+
+
+ ## Main processing
+
+ # index of current intersection
+ ip = 0;
+
+ # iterate over each couple of edge ( (N-1)*(N-2)/2 iterations)
+ for i=1:Nv-2
+ # create first edge
+ edge1 = [poly(i, :) poly(i+1, :)];
+ for j=i+2:Nv-1
+ # create second edge
+ edge2 = [poly(j, :) poly(j+1, :)];
+
+ # check conditions on bounding boxes
+ if min(edge1([1 3]))>max(edge2([1 3]))
+ continue;
+ end
+ if max(edge1([1 3]))<min(edge2([1 3]))
+ continue;
+ end
+ if min(edge1([2 4]))>max(edge2([2 4]))
+ continue;
+ end
+ if max(edge1([2 4]))<min(edge2([2 4]))
+ continue;
+ end
+
+ # compute intersection point
+ inter = intersectEdges(edge1, edge2);
+
+ if sum(isfinite(inter))==2
+ # add point to the list
+ ip = ip + 1;
+ points(ip, :) = inter;
+
+ # also compute positions on the polyline
+ pos1(ip, 1) = i+edgePosition(inter, edge1)-1;
+ pos2(ip, 1) = j+edgePosition(inter, edge2)-1;
+ end
+ end
+ end
+
+ # if polyline is closed, the first vertex was found as an intersection, so
+ # we need to remove it
+ if closed
+ dist = distancePoints(points, poly(1,:));
+ [minDist ind] = min(dist); ##ok<ASGLU>
+ points(ind,:) = [];
+ pos1(ind) = [];
+ pos2(ind) = [];
+ end
+
+ ## Post-processing
+
+ # process output arguments
+ if nargout<=1
+ varargout{1} = points;
+ elseif nargout==3
+ varargout{1} = points;
+ varargout{2} = pos1;
+ varargout{3} = pos2;
+ end
+
+endfunction
diff --git a/inst/polygons2d/reversePolygon.m b/inst/polygons2d/reversePolygon.m
new file mode 100644
index 0000000..b0febf2
--- /dev/null
+++ b/inst/polygons2d/reversePolygon.m
@@ -0,0 +1,44 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{poly2} = } reversePolygon (@var{poly})
+%% Reverse a polygon, by iterating vertices from the end
+%%
+%% POLY2 = reversePolygon(POLY)
+%% POLY2 has same vertices as POLY, but in different order. The first
+%% vertex of the polygon is still the same.
+%%
+%% @seealso{reversePolyline}
+%% @end deftypefn
+
+function rev = reversePolygon(poly)
+
+ rev = poly([1 end:-1:2], :);
+
+endfunction
diff --git a/inst/polygons2d/reversePolyline.m b/inst/polygons2d/reversePolyline.m
new file mode 100644
index 0000000..bc16338
--- /dev/null
+++ b/inst/polygons2d/reversePolyline.m
@@ -0,0 +1,43 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{poly2} = } reversePolyline (@var{poly})
+%% Reverse a polyline, by iterating vertices from the end
+%%
+%% POLY2 = reversePolyline(POLY)
+%% POLY2 has same vertices as POLY, but POLY2(i,:) is the same as
+%% POLY(END-i+1,:).
+%%
+%% @seealso{reversePolygon}
+%% @end deftypefn
+function rev = reversePolyline(poly)
+
+ rev = poly(end:-1:1, :);
+
+endfunction
diff --git a/inst/polygons2d/simplifypolygon.m b/inst/polygons2d/simplifypolygon.m
index 4a197a6..5993cfc 100644
--- a/inst/polygons2d/simplifypolygon.m
+++ b/inst/polygons2d/simplifypolygon.m
@@ -15,37 +15,32 @@
%% -*- texinfo -*-
%% @deftypefn {Function File} {@var{spoly} = } simplifypolygon (@var{poly})
-%% Filter colinear vertex from a 2D polygon.
+%% Simplify a polygon using the Ramer-Douglas-Peucker algorithm.
%%
%% @var{poly} is a N-by-2 matrix, each row representing a vertex.
%%
-%% @seealso{shape2polygon}
+%% @seealso{simplifypolyline, shape2polygon}
%% @end deftypefn
-function polygonsimp = simplifypolygon (polygon)
+function polygonsimp = simplifypolygon (polygon, varargin)
- # Filter colinear points
- edges = diff(polygon([1:end 1],:));
- ned = size(edges,1);
- nxt = [2:ned 1];
+ polygonsimp = simplifypolyline (polygon,varargin{:});
- # check if consecutive edges are parallel
- para = edges(:,1).*edges(nxt,2) - edges(:,2).*edges(nxt,1);
- ind = abs(para) > sqrt(eps);
-
- polygonsimp = polygon(circshift (ind,1),:);
-
- if isempty(polygonsimp)
- warning('simplifypolygon:devel',"The simplification gives an empty polygon. Returning original\n");
- polygonsimp = polygon;
- end
+ # Remove parrallel consecutive edges
+ PL = polygonsimp(1:end-1,:);
+ PC = polygonsimp(2:end,:);
+ PR = polygonsimp([3:end 1],:);
+ a = PL - PC;
+ b = PR - PC;
+ tf = find(isParallel(a,b))+1;
+ polygonsimp (tf,:) = [];
endfunction
%!test
%! P = [0 0; 1 0; 0 1];
%! P2 = [0 0; 0.1 0; 0.2 0; 0.25 0; 1 0; 0 1; 0 0.7; 0 0.6; 0 0.3; 0 0.1];
-%! assert(P,simplifypolygon (P2))
+%! assert(simplifypolygon (P2),P,min(P2(:))*eps)
%!demo
%!
diff --git a/inst/polygons2d/simplifypolyline.m b/inst/polygons2d/simplifypolyline.m
new file mode 100644
index 0000000..0be0efd
--- /dev/null
+++ b/inst/polygons2d/simplifypolyline.m
@@ -0,0 +1,156 @@
+%% Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%%
+%% This program is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {[@var{pline2} @var{idx}] = } simplifypolyline (@var{pline})
+%% @deftypefnx {Function File} {@dots{} = } simplifypolyline (@dots{},@var{property},@var{value},@dots{})
+%% Simplify or subsample a polyline using the Ramer-Douglas-Peucker algorithm,
+%% a.k.a. the iterative end-point fit algorithm or the split-and-merge algorithm.
+%%
+%% The @var{pline} as a N-by-2 matrix. Rows correspond to the
+%% verices (compatible with @code{polygons2d}). The vector @var{idx} constains
+%% the indexes on vetices in @var{pline} that generates @var{pline2}, i.e.
+%% @code{pline2 = pline(idx,:)}.
+%%
+%% @strong{Parameters}
+%% @table @samp
+%% @item 'Nmax'
+%% Maximum number of vertices. Default value @code{1e3}.
+%% @item 'Tol'
+%% Tolerance for the error criteria. Default value @code{1e-4}.
+%% @item 'MaxIter'
+%% Maximum number of iterations. Default value @code{10}.
+%% @item 'Method'
+%% Not implemented.
+%% @end table
+%%
+%% Run @code{demo simplifypolyline} to see an example.
+%%
+%% @seealso{curve2polyline, curveval}
+%% @end deftypefn
+
+function [pline idx] = simplifypolyline (pline_o, varargin)
+%% TODO do not print warnings if user provided Nmax or MaxIter.
+
+ # --- Parse arguments --- #
+ parser = inputParser ();
+ parser.FunctionName = "simplifypolyline";
+ parser = addParamValue (parser,'Nmax', 1e3, @(x)x>0);
+ toldef = 1e-4;%max(sumsq(diff(pline_o),2))*2;
+ parser = addParamValue (parser,'Tol', toldef, @(x)x>0);
+ parser = addParamValue (parser,'MaxIter', 100, @(x)x>0);
+ parser = parse(parser,varargin{:});
+
+ Nmax = parser.Results.Nmax;
+ tol = parser.Results.Tol;
+ MaxIter = parser.Results.MaxIter;
+
+ clear parser toldef
+ msg = ["simplifypolyline: Maximum number of points reached with maximum error %g." ...
+ " Increase %s if the result is not satisfactory."];
+ # ------ #
+
+ [N dim] = size(pline_o);
+ idx = [1 N];
+
+ for iter = 1:MaxIter
+ % Find the point with the maximum distance.
+ [dist ii] = maxdistance (pline_o, idx);
+
+ tf = dist > tol;
+ n = sum(tf);
+ if all(!tf);
+ break;
+ end
+
+ idx(end+1:end+n) = ii(tf);
+ idx = sort(idx);
+
+ if length(idx) >= Nmax
+ %% TODO remove extra points
+ warning('geometry:MayBeWrongOutput', sprintf(msg,max(dist),'Nmax'));
+ break;
+ end
+
+ end
+ if iter == MaxIter
+ warning('geometry:MayBeWrongOutput', sprintf(msg,max(dist),'MaxIter'));
+ end
+
+ pline = pline_o(idx,:);
+endfunction
+
+function [dist ii] = maxdistance (p, idx)
+
+ %% Separate the groups of points according to the edge they can divide.
+ func = @(x,y) x:y;
+ idxc = arrayfun (func, idx(1:end-1), idx(2:end), "UniformOutput",false);
+ points = cellfun (@(x)p(x,:), idxc, "UniformOutput",false);
+
+ %% Build the edges
+ edges = [p(idx(1:end-1),:) p(idx(2:end),:)];
+ edges = mat2cell (edges, ones(1,size(edges,1)), 4)';
+
+ %% Calculate distance between the points and the corresponding edge
+ [dist ii] = cellfun(@dd, points,edges,idxc);
+
+endfunction
+
+function [dist ii] = dd (p,e,idx)
+ [d pos] = distancePointEdge(p,e);
+ [dist ii] = max(d);
+ ii = idx(ii);
+endfunction
+
+%!demo
+%! t = linspace(0,1,100).';
+%! y = polyval([1 -1.5 0.5 0],t);
+%! pline = [t y];
+%!
+%! figure(1)
+%! clf
+%! plot (t,y,'-r;Original;','linewidth',2);
+%! hold on
+%!
+%! tol = [8 2 1 0.5]*1e-2;
+%! colors = jet(4);
+%!
+%! for i=1:4
+%! pline_ = simplifypolyline(pline,'tol',tol(i));
+%! msg = sprintf('-;%g;',tol(i));
+%! h = plot (pline_(:,1),pline_(:,2),msg);
+%! set(h,'color',colors(i,:),'linewidth',2,'markersize',4);
+%! end
+%! hold off
+%!
+%! % ---------------------------------------------------------
+%! % Four approximations of the initial polyline with decreasing tolerances.
+
+%!demo
+%! P = [0 0; 3 1; 3 4; 1 3; 2 2; 1 1];
+%! func = @(x,y) linspace(x,y,5);
+%! P2(:,1) = cell2mat( ...
+%! arrayfun (func, P(1:end-1,1),P(2:end,1), ...
+%! 'uniformoutput',false))'(:);
+%! P2(:,2) = cell2mat( ...
+%! arrayfun (func, P(1:end-1,2),P(2:end,2), ...
+%! 'uniformoutput',false))'(:);
+%!
+%! P2s = simplifypolyline (P2);
+%!
+%! plot(P(:,1),P(:,2),'s',P2(:,1),P2(:,2),'o',P2s(:,1),P2s(:,2),'-ok');
+%!
+%! % ---------------------------------------------------------
+%! % Simplification of a polyline in the plane.
diff --git a/inst/polygons2d/splitPolygons.m b/inst/polygons2d/splitPolygons.m
new file mode 100644
index 0000000..e373668
--- /dev/null
+++ b/inst/polygons2d/splitPolygons.m
@@ -0,0 +1,64 @@
+## Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+## Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are met:
+##
+## 1 Redistributions of source code must retain the above copyright notice,
+## this list of conditions and the following disclaimer.
+## 2 Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## The views and conclusions contained in the software and documentation are
+## those of the authors and should not be interpreted as representing official
+## policies, either expressed or implied, of the copyright holders.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{polygons} = } splitPolygons (@var{polygon})
+## Convert a NaN separated polygon list to a cell array of polygons.
+##
+## @var{polygon} is a N-by-2 array of points, with possibly couples of NaN values.
+## The functions separates each component separated by NaN values, and
+## returns a cell array of polygons.
+##
+## @seealso{polygons2d}
+## @end deftypefn
+function polygons = splitPolygons(polygon)
+
+ if iscell(polygon)
+ # case of a cell array
+ polygons = polygon;
+
+ elseif sum(isnan(polygon(:)))==0
+ # single polygon -> no break
+ polygons = {polygon};
+
+ else
+ # find indices of NaN couples
+ inds = find(sum(isnan(polygon), 2)>0);
+
+ # number of polygons
+ N = length(inds)+1;
+ polygons = cell(N, 1);
+
+ # iterate over NaN-separated regions to create new polygon
+ inds = [0;inds;size(polygon, 1)+1];
+ for i=1:N
+ polygons{i} = polygon((inds(i)+1):(inds(i+1)-1), :);
+ end
+ end
+
+endfunction
diff --git a/inst/polygons2d/supportFunction.m b/inst/polygons2d/supportFunction.m
new file mode 100644
index 0000000..7936aae
--- /dev/null
+++ b/inst/polygons2d/supportFunction.m
@@ -0,0 +1,72 @@
+%% Copyright (C) 2003-2011 David Legland <david.legland@grignon.inra.fr>
+%% Copyright (C) 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions are met:
+%%
+%% 1 Redistributions of source code must retain the above copyright notice,
+%% this list of conditions and the following disclaimer.
+%% 2 Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
+%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%
+%% The views and conclusions contained in the software and documentation are
+%% those of the authors and should not be interpreted as representing official
+%% policies, either expressed or implied, of the copyright holders.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{h} = } suppportFunction (@var{polygon})
+%% @deftypefnx {Function File} {@var{h} = } suppportFunction (@var{polygon}, @var{n})
+%% @deftypefnx {Function File} {@var{h} = } suppportFunction (@var{polygon}, @var{v})
+%% Compute support function of a polygon
+%%
+%% H = supportFunction(POLYGON, N)
+%% uses N points for suport function approximation
+%%
+%% H = supportFunction(POLYGON)
+%% assume 24 points for approximation
+%%
+%% H = supportFunction(POLYGON, V)
+%% where V is a vector, uses vector V of angles to compute support
+%% function.
+%%
+%% @seealso{convexification}
+%% @end deftypefn
+
+function h = supportFunction(polygon, varargin)
+ N = 24;
+ u = (0:2*pi/N:2*pi*(1-1/N)).';
+
+ if length(varargin)==1
+ var = varargin{1};
+ if length(var)==1
+ N = var;
+ u = (0:2*pi/N:2*pi*(1-1/N)).';
+ else
+ u = var(:);
+ end
+ end
+
+
+ h = zeros(size(u));
+
+ for i=1:length(u)
+
+ v = repmat([cos(u(i)) sin(u(i))], [size(polygon, 1), 1]);
+
+ h(i) = max(dot(polygon, v, 2));
+ end
+
+endfunction
diff --git a/inst/shape2d/curve2polyline.m b/inst/shape2d/curve2polyline.m
new file mode 100644
index 0000000..389aec0
--- /dev/null
+++ b/inst/shape2d/curve2polyline.m
@@ -0,0 +1,141 @@
+%% Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%%
+%% This program is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{polyline} = } curve2polyline (@var{curve})
+%% @deftypefnx {Function File} {@var{polyline} = } curve2polyline (@dots{},@var{property},@var{value},@dots{})
+%% Adaptive sampling of a parametric curve.
+%%
+%% The @var{curve} is described as a 2-by-N matrix. Rows correspond to the
+%% polynomial (compatible with @code{polyval}) describing the respective component
+%% of the curve. The curve must be parametrized in the interval [0,1].
+%% The vertices of the polyline are accumulated in regions of the curve where
+%% the curvature is higher.
+%%
+%% @strong{Parameters}
+%% @table @samp
+%% @item 'Nmax'
+%% Maximum number of vertices. Not used.
+%% @item 'Tol'
+%% Tolerance for the error criteria. Default value @code{1e-4}.
+%% @item 'MaxIter'
+%% Maximum number of iterations. Default value @code{10}.
+%% @item 'Method'
+%% Not implemented.
+%% @end table
+%%
+%% @seealso{shape2polygon, curveval}
+%% @end deftypefn
+
+%% This function is based on the algorithm described in
+%% L. H. de Figueiredo (1993). "Adaptive Sampling of Parametric Curves". Graphic Gems III.
+%% I had to remove the recursion so this version could be improved.
+%% Thursday, April 12 2012 -- JuanPi
+
+function [polyline t bump]= curve2polyline (curve, varargin)
+%% TODO make tolerance relative to the "diameter" of the curve.
+
+ # --- Parse arguments --- #
+ parser = inputParser ();
+ parser.FunctionName = "curve2polyline";
+ parser = addParamValue (parser,'Nmax', 32, @(x)x>0);
+ parser = addParamValue (parser,'Tol', 1e-4, @(x)x>0);
+ parser = addParamValue (parser,'MaxIter', 10, @(x)x>0);
+ parser = parse(parser,varargin{:});
+
+ Nmax = parser.Results.Nmax;
+ tol = parser.Results.Tol;
+ MaxIter = parser.Results.MaxIter;
+
+ clear parser toldef
+ # ------ #
+
+ t = [0; 1];
+ tf = 1;
+ points = 1;
+ for iter = 1:MaxIter
+ % Add parameter values where error is still bigger than tol.
+ t = interleave(t, tf);
+ nt = length(t);
+
+ % Update error
+ polyline = curveval (curve,t);
+ bump = bumpyness(polyline);
+
+ % Check which intervals must be subdivided
+ idx = find(bump > tol);
+ % The position of the bumps mpas into intervals
+ % 1 -> 1 2
+ % 2 -> 3 4
+ % 3 -> 5 6
+ % and so on
+ idx = [2*(idx-1)+1; 2*idx](:);
+ tf = false (nt-1,1);
+ tf(idx) = true;
+
+ if all (!tf)
+ break;
+ end
+
+ end
+
+endfunction
+
+function f = bumpyness (p)
+%% Check for co-linearity
+%% TODO implement various method for this
+%% -- Area of the triangle close to zero (used currently).
+%% -- Angle close to pi.
+%% -- abs(p0-pt) + abs(pt-p1) - abs(p0-p1) almost zero.
+%% -- Curve's tange at 0,t,1 are almost parallel.
+%% -- pt is in chord p0 -> p1.
+%% Do this in isParallel.m and remove this function
+
+ PL = p(1:2:end-2,:);
+ PC = p(2:2:end-1,:);
+ PR = p(3:2:end,:);
+
+ a = PL - PC;
+ b = PR - PC;
+
+ f = (a(:,1).*b(:,2) - a(:,2).*b(:,1)).^2;
+
+endfunction
+
+function tt = interleave (t,varargin)
+
+ nt = length(t);
+ ntt = 2 * nt -1;
+ tt = zeros(ntt,1);
+ tt(1:2:ntt) = t;
+ beta = 0.4 + 0.2*rand(nt-1, 1);
+ tt(2:2:ntt) = t(1:end-1) + beta.*(t(2:end)-t(1:end-1));
+
+ if nargin > 1
+ tf = true (ntt,1);
+ tf(2:2:ntt) = varargin{1};
+ tt(!tf) = [];
+ end
+
+endfunction
+
+%!demo
+%! curve = [0 0 1 0;1 -0.3-1 0.3 0];
+%! polyline = curve2polyline(curve,'tol',1e-8);
+%!
+%! t = linspace(0,1,100)';
+%! pc = curveval(curve,t);
+%!
+%! plot(polyline(:,1),polyline(:,2),'-o',pc(:,1),pc(:,2),'-r')
diff --git a/inst/io/private/getSVGstrPath.m b/inst/shape2d/curveval.m
index ae58654..b47ec77 100644
--- a/inst/io/private/getSVGstrPath.m
+++ b/inst/shape2d/curveval.m
@@ -1,5 +1,5 @@
-%% Copyright (c) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
-%%
+%% Copyright (c) 2012 Juan Pablo Carbajal <carbajal@ifi.uzh.ch>
+%%
%% This program is free software: you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published by
%% the Free Software Foundation, either version 3 of the License, or
@@ -13,8 +13,18 @@
%% You should have received a copy of the GNU General Public License
%% along with this program. If not, see <http://www.gnu.org/licenses/>.
-function strPath = getSVGstrPath(svg)
+%% -*- texinfo -*-
+%% @deftypefn {Function File} {@var{p} = } curveval (@var{curve}, @var{t})
+%% Evaluates parametric @var{curve} at @var{t}.
+%%
+%% @end deftypefn
+function p = curveval (curve, t)
+
+ dim = size (curve,1);
+ p = zeros (length(t), dim);
- [s e te strPath] = regexpi(svg,'<[ ]*path(?:(?!/>).)*/>');
+ for i = 1:dim
+ p(:,i) = polyval (curve(i,:), t);
+ end
-end
+endfunction
diff --git a/inst/shape2d/shape2polygon.m b/inst/shape2d/shape2polygon.m
index 1d7a987..86fb143 100644
--- a/inst/shape2d/shape2polygon.m
+++ b/inst/shape2d/shape2polygon.m
@@ -15,24 +15,22 @@
%% -*- texinfo -*-
%% @deftypefn {Function File} {@var{polygon} = } shape2polygon (@var{shape})
-%% @deftypefnx {Function File} {@var{polygon} = } shape2polygon (@var{shape},@var{N})
+%% @deftypefnx {Function File} {@var{polygon} = } shape2polygon (@dots{},@var{property},@var{value},@dots{})
%% Transforms a 2D shape described by piecewise smooth polynomials into a polygon.
%%
%% @var{shape} is a n-by-1 cell where each element is a pair of polynomials
%% compatible with polyval.
%% @var{polygon} is a k-by-2 matrix, where each row represents a vertex.
-%% @var{N} defines the number of points to be used in non-straigth edges.
+%% The property-value pairs are passed to @code{curve2polyline}.
%%
-%% @seealso{polygon2shape, drawPolygon}
+%% @seealso{polygon2shape, curve2poyline}
%% @end deftypefn
-function polygon = shape2polygon (shape, N=16)
+function polygon = shape2polygon (shape, varargin)
polygon = cell2mat ( ...
- cellfun (@(x) func (x,N), shape,'UniformOutput',false) );
-
- %% TODO simply the polygon based on curvature
-% polygon = unique (polygon, 'rows');
+ cellfun (@(x) curve2polyline(x,varargin{:}), shape,'UniformOutput',false) );
+ polygon = simplifypolygon(polygon);
if size (polygon, 1) == 1
polygon(2,1) = polyval (shape{1}(1,:), 1);
@@ -41,14 +39,27 @@ function polygon = shape2polygon (shape, N=16)
endfunction
-function y = func (x,N)
-
- if size (x,2) > 2
- t = linspace (0,1-1/N,N).';
- y(:,1) = polyval (x(1,:), t);
- y(:,2) = polyval (x(2,:), t);
- else
- y = x(:,2).';
- end
-
-endfunction
+%!demo
+%! shape = {[-93.172 606.368 -476.054 291.429; ...
+%! -431.196 637.253 11.085 163.791]; ...
+%! [-75.3626 -253.2337 457.1678 328.5714; ...
+%! 438.7659 -653.6278 -7.9953 380.9336]; ...
+%! [-89.5841 344.9716 -275.3876 457.1429; ...
+%! -170.3613 237.8858 1.0469 158.0765];...
+%! [32.900 -298.704 145.804 437.143; ...
+%! -243.903 369.597 -34.265 226.648]; ...
+%! [-99.081 409.127 -352.903 317.143; ...
+%! 55.289 -114.223 -26.781 318.076]; ...
+%! [-342.231 191.266 168.108 274.286; ...
+%! 58.870 -38.083 -89.358 232.362]};
+%!
+%! % Estimate a good tolerance
+%! n = cell2mat(cellfun(@(x)curveval(x,rand(1,10)), shape, 'uniformoutput',false));
+%! dr = (max(n(:,1))-min(n(:,1)))*(max(n(:,2))-min(n(:,2)))*40;
+%! p = shape2polygon (shape,'tol',dr);
+%!
+%! figure(1)
+%! shapeplot(shape,'-b');
+%! hold on;
+%! drawPolygon (p,'-or');
+%! hold off
diff --git a/inst/shape2d/shapecentroid.m b/inst/shape2d/shapecentroid.m
index a7ad8d5..8094b0b 100644
--- a/inst/shape2d/shapecentroid.m
+++ b/inst/shape2d/shapecentroid.m
@@ -66,9 +66,8 @@ endfunction
%! 0 0]};
%! CoM = shapecentroid (boomerang)
%! Gcentroid = centroid(shape2polygon(boomerang))
-%!
%! figure(1); clf;
-%! shapeplot(boomerang,10,'-o');
+%! shapeplot(boomerang,'-o');
%! hold on
%! drawPoint(CoM,'xk;shape centroid;');
%! drawPoint(Gcentroid,'xr;point centroid;');
@@ -85,7 +84,7 @@ endfunction
%! CoM = shapecentroid (Lshape)
%! Gcentroid = centroid (shape2polygon (Lshape))
%!
-%! shapeplot(Lshape,10,'-o');
+%! shapeplot(Lshape,'-o');
%! hold on
%! drawPoint(CoM,'xk;shape centroid;');
%! drawPoint(Gcentroid,'xr;point centroid;');
diff --git a/inst/shape2d/shapeplot.m b/inst/shape2d/shapeplot.m
index adeae7d..b820464 100644
--- a/inst/shape2d/shapeplot.m
+++ b/inst/shape2d/shapeplot.m
@@ -27,9 +27,11 @@
%% @seealso{drawPolygon, shape2polygon}
%% @end deftypefn
-function h = shapeplot(shape, N = 16, varargin)
+function h = shapeplot(shape, varargin)
- p = shape2polygon(shape, N);
+ n = cell2mat(cellfun(@(x)curveval(x,rand(1,5)), shape, 'uniformoutput',false));
+ dr = (max(n(:,1))-min(n(:,1)))*(max(n(:,2))-min(n(:,2)))/100;
+ p = shape2polygon(shape,'tol', dr);
h = drawPolygon(p,varargin{:});
endfunction
diff --git a/inst/shape2d/shapetransform.m b/inst/shape2d/shapetransform.m
index 6cf387e..ca04f9d 100644
--- a/inst/shape2d/shapetransform.m
+++ b/inst/shape2d/shapetransform.m
@@ -98,14 +98,12 @@ endfunction
%! shape = shapetransform (shape,-T + [2; 0]);
%!
%! close
-%! shapeplot (shape,10,'-r','linewidth',2)
+%! shapeplot (shape,'-r','linewidth',2);
%! hold on
%! for i = 1:9
%! T = createRotation (i*pi/5)(1:2,1:2)/exp(0.3*i);
-%! shapeplot (shapetransform(shape, T), 10, 'color',rand(1,3),'linewidth',2);
+%! shapeplot (shapetransform(shape, T), 'color',rand(1,3),'linewidth',2);
%! end
%! hold off
%! axis tight
%! axis square
-
-