/* * 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.Vec3D; import toxi.geom.Vec4D; /** * A Basic NurbsSurface implementation. * * @author sg * @version 1.2 */ public class BasicNurbsSurface implements NurbsSurface { private KnotVector uKnots; private KnotVector vKnots; private ControlNet cpnet; // private List trimms = new LinkedList(); /** * Create a Nurbs Surface from the given {@link ControlNet} and the knot * values of degree p in u direction and of degree q in v direction. * * @param cps * ControlNet of the Nurbs * @param uK * Knot values in u direction * @param vK * Knot values in v direction * @param p * degree in u direction * @param q * degree in v direction */ public BasicNurbsSurface(ControlNet cps, float[] uK, float[] vK, int p, int q) throws IllegalArgumentException { this(cps, new KnotVector(uK, p), new KnotVector(vK, q)); } /** * Create a Nurbs form the Controlnet and the two Knot vectors. * * @param net * Contorl net of Nurbs * @param u * KnotVector in u direction * @param v * KnotVector in v direction */ public BasicNurbsSurface(ControlNet net, KnotVector u, KnotVector v) throws IllegalArgumentException { cpnet = net; uKnots = u; vKnots = v; validate(); } // public void addTrimCurve(TrimCurve tc) { // trimms.add(tc); // } @Override public ControlNet getControlNet() { return cpnet; } // public List getTrimCurves() { // return trimms; // } @Override public int getUDegree() { return uKnots.getDegree(); } @Override public float[] getUKnots() { return uKnots.getArray(); } /** * * @return */ @Override public KnotVector getUKnotVector() { return uKnots; } @Override public int getVDegree() { return vKnots.getDegree(); } @Override public float[] getVKnots() { return vKnots.getArray(); } /** * * @return */ @Override public KnotVector getVKnotVector() { return vKnots; } /** * * @param u * @param v * @return */ @Override public Vec3D pointOnSurface(double u, double v) { return pointOnSurface((float) u, (float) v, new Vec3D()); } @Override public Vec3D pointOnSurface(float u, float v) { return pointOnSurface(u, v, new Vec3D()); } @Override public Vec3D pointOnSurface(float u, float v, Vec3D out) { // Piegl -> Algorithm A4.3 -> page 134 int uspan = uKnots.findSpan(u); double[] bfu = uKnots.basisFunctions(uspan, u); int vspan = vKnots.findSpan(v); double[] bfv = vKnots.basisFunctions(vspan, v); int p = uKnots.getDegree(); int q = vKnots.getDegree(); Vec4D[] tmp = new Vec4D[q + 1]; for (int l = 0; l <= q; l++) { Vec4D pw = new Vec4D(); for (int k = 0; k <= p; k++) { pw.addSelf(cpnet.get(uspan - p + k, vspan - q + l) .getWeighted().scaleSelf((float) bfu[k])); } tmp[l] = pw; } Vec4D sw = new Vec4D(); for (int l = 0; l <= q; l++) { sw.addSelf(tmp[l].scaleSelf((float) bfv[l])); } return sw.unweightInto(out); } @Override public Vec4D[][][][] surfaceDerivCpts(int d, int r1, int r2, int s1, int s2) { Vec4D[][][][] result = new Vec4D[d + 1][d + 1][r2 - r1 + 1][s2 - s1 + 1]; int degreeU = uKnots.getDegree(); int degreeV = vKnots.getDegree(); int du = d < degreeU ? d : degreeU; int dv = d < degreeV ? d : degreeV; int r = r2 - r1; int s = s2 - s1; Vec4D[][] cps = cpnet.getControlPoints(); Vec4D[] ucps = new Vec4D[cpnet.uLength()]; for (int j = s1; j <= s2; j++) { for (int idxu = 0; idxu < cpnet.uLength(); idxu++) { ucps[idxu] = cps[idxu][j]; } Vec4D[][] tmp = new BasicNurbsCurve(ucps, uKnots).curveDerivCpts( du, r1, r2); for (int k = 0; k <= du; k++) { final Vec4D[][] resk0 = result[k][0]; for (int i = 0; i <= (r - k); i++) { resk0[i][j - s1] = tmp[k][i]; } } } for (int k = 0; k <= du; k++) { final Vec4D[][] resk0 = result[k][0]; for (int i = 0; i <= (r - k); i++) { final int length = resk0[i].length; final Vec4D[] resk0i = resk0[i]; Vec4D[] vcps = new Vec4D[length]; System.arraycopy(resk0i, 0, vcps, 0, length); final int dd = (d - k) < dv ? (d - k) : dv; Vec4D[][] tmp = new BasicNurbsCurve(vcps, vKnots) .curveDerivCpts(dd, 0, s); for (int l = 1; l <= dd; l++) { final Vec4D[] reskli = result[k][l][i]; final Vec4D[] tmpL = tmp[l]; for (int j = 0; j <= (s - 1); j++) { reskli[j] = tmpL[j]; } } } } return result; } private void validate() { if (uKnots.length() != uKnots.getDegree() + cpnet.uLength() + 1) { throw new IllegalArgumentException( "Nurbs Surface has wrong Knot number in u Direction"); } if (vKnots.length() != vKnots.getDegree() + cpnet.vLength() + 1) { throw new IllegalArgumentException( "Nurbs Surface has wrong Knot number in v Direction"); } } }