# Using \foreach loop in Cubic B-spline curve refinement

This question is only about TikZ (/PGF) implementation. This is a MWE of what I want to ask for:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}[scale=2]
\coordinate (p1) at (1,.5);
\coordinate (p2) at (1,1);
\coordinate (p3) at (0,1);
\coordinate (p4) at (0,0);
\coordinate (p5) at (1,0);
\coordinate (p6) at (1,-1);
\coordinate (p7) at (0,-1);
\coordinate (p8) at (0,-.5);
\draw[line width=1pt,blue] (p1) \foreach \p in {p2,p3,p4,p5,p6,p7,p8} {
-- (\p)};

%% For odd points the rule is $n_{2i-1} = .5*p_{i} + .5*p_{i+1}$
%% For even points the rule is $n_{2i} = .125*p_{i-1} + .75*p_{i} + .125*p_{i+1}$

\coordinate (n1) at ($.5*(p1) + .5*(p2)$);
\coordinate (n2) at ($.125*(p1) + .75*(p2) + .125*(p3)$);
\coordinate (n3) at ($.5*(p2) + .5*(p3)$);
\coordinate (n4) at ($.125*(p2) + .75*(p3) + .125*(p4)$);
\coordinate (n5) at ($.5*(p3) + .5*(p4)$);
\coordinate (n6) at ($.125*(p3) + .75*(p4) + .125*(p5)$);
\coordinate (n7) at ($.5*(p4) + .5*(p5)$);
\coordinate (n8) at ($.125*(p4) + .75*(p5) + .125*(p6)$);
\coordinate (n9) at ($.5*(p5) + .5*(p6)$);
\coordinate (n10) at ($.125*(p5) + .75*(p6) + .125*(p7)$);
\coordinate (n11) at ($.5*(p6) + .5*(p7)$);
\coordinate (n12) at ($.125*(p6) + .75*(p7) + .125*(p8)$);
\coordinate (n13) at ($.5*(p7) + .5*(p8)$);
\draw[line width=3pt] (n1) \foreach \n in {n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13} {
-- (\n)};
\end{tikzpicture}

\end{document}


The point is that I want to compute all the n1,...,n13 coordinates found by the cubic B-spline curve refinement considering the initial points p1,...,p8 with a \foreach instructions and NOT by hand as was shown, but I don't know how to use many points in the \foreach list at the same iteration. If you could also generate the new points as a list or array will be nice.

Please do that in the more general way, considering as many as possible initial points (not just 8) and the possibility of many points used in the same iteration. Think that for me this question is the tip of the iceberg!

Here a mix from the first answers and I used barycentric cs to avoid calc. I used foreach to create the first points.

I used \pgfmathtruncatemacro instead of evaluate like percusse because I don't know what is the form the most efficient.

\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[scale=2]
\foreach \x/\y [count=\i] in {1/.5,1/1,0/1,0/0,1/0,1/-1,0/-1,0/-.5,0/0}{%
\coordinate (p\i) at (\x,\y);}
\draw[line width=1pt,blue] (p1) \foreach \p in {2,...,8} {-- (p\p)};

\foreach \i  in {1,...,7} {%
\pgfmathtruncatemacro{\j}{\i+1}%
\pgfmathtruncatemacro{\k}{\i+2}%
\pgfmathtruncatemacro{\ind}{2*\i-1}%
\pgfmathtruncatemacro{\next}{2*\i}%
\coordinate (n\ind) at (barycentric cs:p\i=0.5,p\j=0.5);
\coordinate (n\next) at (barycentric cs:p\i=0.125,p\j=0.75,p\k=0.125);
}

\draw[line width=2pt,red] (n1)\foreach \i in {2,...,13}{-- (n\i)};
\end{tikzpicture}

\end{document} • Sweet! Good to see your answers again :) – percusse Oct 21 '12 at 9:52
• @AlainMatthes: I didn't noticed the possibility of use barycentric cs in Ti_k_Z. That's just what I need, because I'm mainly working with barycentric coordinates. Thanks! – rafaeldf Nov 14 '12 at 22:18

Here is something but I think I don't get your question. Your formulation is not good for complicated indices e.g. check the even number formula. You might find it helpful to leave the i on the left hand side and write the indices on the right in terms of i.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}

\begin{tikzpicture}[scale=2]
\coordinate (p1) at (1,.5);
\coordinate (p2) at (1,1);
\coordinate (p3) at (0,1);
\coordinate (p4) at (0,0);
\coordinate (p5) at (1,0);
\coordinate (p6) at (1,-1);
\coordinate (p7) at (0,-1);
\coordinate (p8) at (0,-.5);
\draw[line width=1pt,blue] (p1) \foreach \x in {2,...,8} {-- (p\x)};

%% For odd points the rule is $n_{2i-1} = .5*p_{i} + .5*p_{i+1}$
%% For even points the rule is $n_{2i} = .125*p_{i-1} + .75*p_{i} + .125*p_{i+1}$
\foreach \x[evaluate=\x as \evxx using int(\x/2),
evaluate=\x as \odxxi using int((\x+1)/2),
evaluate=\x as \evxxi using int((\x/2)+1),
evaluate=\x as \odxxii using int((\x+3)/2),
evaluate=\x as \evxxii using int((\x/2)+2)] in {1,...,13}{
\ifodd\x
\coordinate (n\x) at ($.5*(p\odxxi) + .5*(p\odxxii)$);
\else
\coordinate (n\x) at ($.125*(p\evxx) + .75*(p\evxxi) + .125*(p\evxxii)$);
\fi
}
\draw[line width=3pt] (n1) \foreach \x in {2,...,13}{-- (n\x)};
\end{tikzpicture}
\end{document} • Your solution is nice but the indices aren't used in a suitable way, i.e. isn't helpful to leave the i on the left hand side and then write the indices on the right in terms of i as you do. First: think that on the left hand side are the new points while in the right hand side are the old points, so is more natural to describe news by means of old and not reverse. Second: you need to find the integer part while in the other way you don't. Anyway, thanks for your ideas! – rafaeldf Oct 22 '12 at 15:54
• @rafaeldf I didn't say this is the only way but if you check your even number formula, it's wrong and it's not unexpected because it's a common programming problem. That's what I wanted to emphasize. Instead of looking for f(2)=x you are looking for f(x)=4 so you have to invert your function get the correct indices which is unnecessary. If you can formulate your problem better you will benefit from it anyway. – percusse Oct 22 '12 at 17:08

I split your loop at 2. And I prepared the design for a variable number of points. You just need to add \point{ } for a new point. \documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{calc}

\newcounter{cnt}

\newcommand{\point}{
\stepcounter{cnt}
\coordinate (p\thecnt) at (#1);
}

\begin{document}

\begin{tikzpicture}[scale=2]
\point{1,.5};
\point{1,1};
\point{0,1};
\point{0,0};
\point{1,0};
\point{1,-1};
\point{0,-1};
\point{0,-.5};
\draw[line width=1pt,blue] (p1) \foreach \p in {2, ..., \thecnt} { -- (p\p)};

%% For odd points the rule is $n_{2i-1} = .5*p_{i} + .5*p_{i+1}$
%% For even points the rule is $n_{2i} = .125*p_{i-1} + .75*p_{i} + .125*p_{i+1}$

\pgfmathtruncatemacro{\max}{\thecnt -1}
\foreach \k in {1, ..., \max} {
\pgfmathtruncatemacro{\i}{2 * \k - 1)}
\pgfmathtruncatemacro{\l}{\k+1)}
\coordinate (n\i) at ($(p\k)!0.5!(p\l)$);
\xdef\t{\i}
}

\foreach \l in {2, ..., \max} {
\pgfmathtruncatemacro{\i}{2 * \l - 2)}
\pgfmathtruncatemacro{\k}{\l - 1)}
\pgfmathtruncatemacro{\m}{\l + 1)}
\coordinate (n\i) at ($0.125*(p\k) + 0.75*(p\l) + 0.125*(p\m)$);
}

\draw[line width=3pt] (n1) \foreach \k in {2, ..., \t} { -- (n\k)};

\end{tikzpicture}
\end{document}

• Thanks for your solution. The use of \pgfmathtruncatemacro is very useful and your idea of define the macro \point (with a counter for the amount of points) too. But, if the initial points could be declared as a list (e.g., as coordinates {(1,.5) (1,1) (0,1) ...}) and the output could be a list too, the algorithm will be even better. Maybe this is another question! ;-) – rafaeldf Nov 14 '12 at 22:38