/* * __ .__ .__ ._____. * _/ |_ _______ __|__| ____ | | |__\_ |__ ______ * \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/ * | | ( <_> > <| \ \___| |_| || \_\ \\___ \ * |__| \____/__/\_ \__|\___ >____/__||___ /____ > * \/ \/ \/ \/ * * Copyright (c) 2006-2011 Karsten Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * http://creativecommons.org/licenses/LGPL/2.1/ * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ package toxi.geom; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** *
* This is a generic 3D B-Spline class for curves of arbitrary length, control * handles and patches are created and joined automatically as described here: * ibiblio.org/e-notes/ * Splines/Bint.htm *
* ** Thanks to a bug report by Aaron Meyers (http://universaloscillation.com) the * {@linkplain #toLineStrip2D(int)} method has a slightly changed behaviour from * version 0014 onwards. In earlier versions erroneous duplicate points would be * added near each given control point, which lead to various weird results. *
* ** The new behaviour of the curve interpolation/computation is described in the * docs for the {@linkplain #toLineStrip2D(int)} method below. *
* * @version 0014 Added user adjustable curve tightness control * @version 0015 Added JAXB annotations and List support for dynamic building of * spline */ public class Spline2D { /** * */ public static final float DEFAULT_TIGHTNESS = 0.25f; /** * */ public static final int DEFAULT_RES = 16; /** * */ protected Vec2D[] points; /** * */ public List* Computes all curve vertices based on the resolution/number of * subdivisions requested. The higher, the more vertices are computed: *
** (number of control points - 1) * resolution + 1 *
** Since version 0014 the automatic placement of the curve handles can also * be manipulated via the {@linkplain #setTightness(float)} method. *
* * @param res * the number of vertices to be computed per segment between * original control points (incl. control point always at the * start of each segment) * @return list of Vec2D vertices along the curve */ public LineStrip2D toLineStrip2D(int res) { updateCoefficients(); if (res < 1) { res = 1; } res++; if (bernstein == null || bernstein.resolution != res) { bernstein = new BernsteinPolynomial(res); } findCPoints(); Vec2D deltaP = new Vec2D(); Vec2D deltaQ = new Vec2D(); res--; LineStrip2D strip = new LineStrip2D(); for (int i = 0, numP = getNumPoints(); i < numP - 1; i++) { Vec2D p = points[i]; Vec2D q = points[i + 1]; deltaP.set(delta[i]).addSelf(p); deltaQ.set(q).subSelf(delta[i + 1]); for (int k = 0; k < res; k++) { float x = p.x * bernstein.b0[k] + deltaP.x * bernstein.b1[k] + deltaQ.x * bernstein.b2[k] + q.x * bernstein.b3[k]; float y = p.y * bernstein.b0[k] + deltaP.y * bernstein.b1[k] + deltaQ.y * bernstein.b2[k] + q.y * bernstein.b3[k]; strip.add(new Vec2D(x, y)); } } strip.add(points[points.length - 1].copy()); return strip; } /** * */ public void updateCoefficients() { final int numP = getNumPoints(); if (points == null || (points != null && points.length != numP)) { coeffA = new Vec2D[numP]; delta = new Vec2D[numP]; bi = new float[numP]; for (int i = 0; i < numP; i++) { coeffA[i] = new Vec2D(); delta[i] = new Vec2D(); } } setTightness(tightness); points = pointList.toArray(new Vec2D[numP]); } }