/* * jgeom: Geometry Library fo Java * * Copyright (C) 2005 Samuel Gerber * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package toxi.geom.nurbs; import toxi.geom.Polygon2D; import toxi.geom.Vec3D; import toxi.geom.Vec4D; /** * A Basic implementation of a NurbsCurve. * * @author sg * @version 1.0 */ public class BasicNurbsCurve implements NurbsCurve, Cloneable { private Vec4D[] cpoly; private KnotVector uKnots; /** * Create a Nurbs Curve from the given Controlpoints, Knots and degree.
* [TODO Validate Input, part of it is done by creating the KnotVector] * * @param cps * Array of Controlpoints * @param uK * Knot values * @param degree * Degree of the Nurbs Curve */ public BasicNurbsCurve(Vec4D[] cps, float[] uK, int degree) { this(cps, new KnotVector(uK, degree)); } /** * Generate a Nurbs from the given Controlpoints and the given Knotvector.
* [TODO validate input] * * @param cps * Array of Controlpoints * @param uKnots * Knotvector of the Nurbs */ public BasicNurbsCurve(Vec4D[] cps, KnotVector uKnots) { cpoly = cps; this.uKnots = uKnots; if (uKnots.length() != uKnots.getDegree() + cpoly.length + 1) { throw new IllegalArgumentException( "Nurbs Curve has wrong knot number"); } } @Override public Vec4D[][] curveDerivCpts(int d, int r1, int r2) { Vec4D[][] result = new Vec4D[d + 1][r2 - r1 + 1]; int degree = uKnots.getDegree(); // k=0 => control points int r = r2 - r1; for (int i = 0; i <= r; i++) { result[0][i] = cpoly[i]; } // k=1 => 1st derivative, k=2 => 2nd derivative, etc... for (int k = 1; k <= d; k++) { int tmp = degree - k + 1; for (int i = 0; i <= (r - k); i++) { Vec4D cw = new Vec4D(result[k - 1][i + 1]); cw.subSelf(result[k - 1][i]); cw.scaleSelf(tmp); cw.scaleSelf(1 / (uKnots.get(r1 + i + degree + 1) - uKnots .get(r1 + i + k))); result[k][i] = cw; } } return result; } /** * * @param u * @param grade * @return */ @Override public Vec3D[] derivativesOnCurve(float u, int grade) { return derivativesOnCurve(u, grade, new Vec3D[grade + 1]); } /** * * @param u * @param grade * @param derivs * @return */ @Override public Vec3D[] derivativesOnCurve(float u, int grade, Vec3D[] derivs) { int span = uKnots.findSpan(u); int degree = uKnots.getDegree(); // TODO: compute derivatives also for NURBS // currently supports only non-rational B-Splines float derivVals[][] = uKnots.derivBasisFunctions(span, u, grade); // Zero values for (int k = (degree + 1); k <= grade; k++) { derivs[k] = new Vec3D(); } for (int k = 0; k <= grade; k++) { Vec3D d = new Vec3D(); for (int j = 0; j <= degree; j++) { Vec4D v = cpoly[(span - degree) + j]; float s = derivVals[k][j]; d.addSelf(v.x * s, v.y * s, v.z * s); } derivs[k] = d; } return derivs; } @Override public Vec4D[] getControlPoints() { return cpoly; } @Override public int getDegree() { return uKnots.getDegree(); } @Override public float[] getKnots() { return uKnots.getArray(); } /** * * @return */ @Override public KnotVector getKnotVector() { return uKnots; } @Override public Vec3D pointOnCurve(float u) { return pointOnCurve(u, new Vec3D()); } @Override public Vec3D pointOnCurve(float u, Vec3D out) { int span = uKnots.findSpan(u); int degree = uKnots.getDegree(); // for periodic knot vectors the usable parameter range is // span >= degree and span <= no control points (n+1) if (span < degree) { return out; } if (span > uKnots.getN()) { return out; } double[] bf = uKnots.basisFunctions(span, u); Vec4D cw = new Vec4D(); for (int i = 0; i <= degree; i++) { cw.addSelf(cpoly[(span - degree) + i].getWeighted().scaleSelf( (float) bf[i])); } return cw.unweightInto(out); } /** * * @param res * @return */ @Override public Polygon2D toPolygon2D(int res) { float delta = 1f / (res - 1); Polygon2D poly = new Polygon2D(); for (int i = 0; i < res; i++) { poly.add(pointOnCurve(i * delta).to2DXY()); } return poly; } }