## Copyright (C) 2012-2019 Juan Pablo Carbajal ## ## 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 . ## -*- texinfo -*- ## @defun {@var{polyline} = } curve2polyline (@var{curve}) ## @defunx {@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}. ## ## Currently the area of the smaller triangle formed by three consecutive points ## on the curve is considered. When this area is smaller than tolerance the ## points are colinear, and hence no more sampling between these points is ## needed. ## ## @item 'MaxIter' ## Maximum number of iterations. Default value @code{10}. ## @item 'Method' ## Not implemented. ## @end table ## ## This function is based on the algorithm described in ## L. H. de Figueiredo (1993). "Adaptive Sampling of Parametric Curves". Graphic Gems III. ## @seealso{shape2polygon, curveval} ## @end defun ## 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 ('Nmax', 32, @(x)x>0); parser.addParamValue ('Tol', 1e-4, @(x)x>0); parser.addParamValue ('MaxIter', 10, @(x)x>0); parser.parse(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 maps 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')