/** * */ package wblut.geom; // TODO: Auto-generated Javadoc /** * The Class WB_RBSplineSurface. * * @author Frederik Vanhoutte, W:Blut */ public class WB_RBSplineSurface extends WB_BSplineSurface { /** The weights. */ private final double[][] weights; /** The wpoints. */ protected WB_Homogeneous[][] wpoints; /** * Instantiates a new w b_ rb spline surface. * * @param controlPoints the control points * @param uknot the uknot * @param vknot the vknot * @param weights the weights */ public WB_RBSplineSurface(final WB_Point3d[][] controlPoints, final WB_NurbsKnot uknot, final WB_NurbsKnot vknot, final double[][] weights) { super(controlPoints, uknot, vknot); if ((weights.length != controlPoints.length) || (weights[0].length != controlPoints[0].length)) { throw new IllegalArgumentException( "Number of weights doesn't match number of control points."); } this.weights = weights; wpoints = new WB_Homogeneous[n + 1][m + 1]; for (int i = 0; i < n + 1; i++) { for (int j = 0; j < m + 1; j++) { wpoints[i][j] = new WB_Homogeneous(points[i][j], weights[i][j]); } } } /** * Instantiates a new w b_ rb spline surface. * * @param controlPoints the control points * @param udegree the udegree * @param vdegree the vdegree * @param weights the weights */ public WB_RBSplineSurface(final WB_Point3d[][] controlPoints, final int udegree, final int vdegree, final double[][] weights) { super(controlPoints, udegree, vdegree); if ((weights.length != controlPoints.length) || (weights[0].length != controlPoints[0].length)) { throw new IllegalArgumentException( "Number of weights doesn't match number of control points."); } this.weights = weights; wpoints = new WB_Homogeneous[n + 1][m + 1]; for (int i = 0; i < n + 1; i++) { for (int j = 0; j < m + 1; j++) { wpoints[i][j] = new WB_Homogeneous(points[i][j], weights[i][j]); } } } /** * Instantiates a new w b_ rb spline surface. * * @param controlPoints the control points * @param udegree the udegree * @param vdegree the vdegree */ public WB_RBSplineSurface(final WB_Point3d[][] controlPoints, final int udegree, final int vdegree) { super(controlPoints, udegree, vdegree); weights = new double[n + 1][m + 1]; for (int i = 0; i <= n; i++) { for (int j = 0; j <= m; j++) { weights[i][j] = 1.0; } } wpoints = new WB_Homogeneous[n + 1][m + 1]; for (int i = 0; i < n + 1; i++) { for (int j = 0; j < m + 1; j++) { wpoints[i][j] = new WB_Homogeneous(points[i][j], weights[i][j]); } } } /** * Instantiates a new w b_ rb spline surface. * * @param controlPoints the control points * @param uknot the uknot * @param vknot the vknot */ public WB_RBSplineSurface(final WB_Homogeneous[][] controlPoints, final WB_NurbsKnot uknot, final WB_NurbsKnot vknot) { super(); if (uknot.n != controlPoints.length - 1) { throw new IllegalArgumentException( "U knot size and/or degree doesn't match number of control points."); } if (vknot.n != controlPoints[0].length - 1) { throw new IllegalArgumentException( "V knot size and/or degree doesn't match number of control points."); } p = uknot.p(); n = uknot.n(); q = vknot.p(); m = vknot.n(); this.uknot = uknot; this.vknot = vknot; wpoints = controlPoints; points = new WB_Point3d[n + 1][m + 1]; weights = new double[n + 1][m + 1]; for (int i = 0; i < n + 1; i++) { for (int j = 0; j < m + 1; j++) { points[i][j] = controlPoints[i][j].project(); weights[i][j] = controlPoints[i][j].w; } } } /** * Sets the weight. * * @param i the i * @param j the j * @param w the w */ public void setWeight(final int i, final int j, final double w) { if ((i < 0) || (i > n) || (j < 0) || (j > m)) { throw new IllegalArgumentException( "Index outside of weights range."); } weights[i][j] = w; wpoints[i][j] = new WB_Homogeneous(points[i][j], weights[i][j]); } /* * (non-Javadoc) * @see wblut.nurbs.WB_Surface#surfacePoint(double, double) */ @Override public WB_Point3d surfacePoint(final double u, final double v) { final int uspan = uknot.span(u); final double[] Nu = uknot.basisFunctions(uspan, u); final int vspan = vknot.span(v); final double[] Nv = vknot.basisFunctions(vspan, v); WB_Homogeneous ttmp = new WB_Homogeneous(); final WB_Homogeneous[] tmp = new WB_Homogeneous[q + 1]; for (int el = 0; el <= q; el++) { tmp[el] = new WB_Homogeneous(); for (int k = 0; k <= p; k++) { ttmp = new WB_Homogeneous( wpoints[uspan - p + k][vspan - q + el]); tmp[el].add(ttmp.mult(Nu[k])); } } final WB_Homogeneous SH = new WB_Homogeneous(); for (int el = 0; el <= q; el++) { SH.add(tmp[el].mult(Nv[el])); } return new WB_Point3d(SH.project()); } /** * Update weights. */ public void updateWeights() { for (int i = 0; i < n + 1; i++) { for (int j = 0; j < m + 1; j++) { wpoints[i][j] = new WB_Homogeneous(points[i][j], weights[i][j]); } } } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertUKnot(double) */ @Override public WB_RBSplineSurface insertUKnot(final double u) { return insertUKnot(u, 1); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertUKnotMax(double) */ @Override public WB_RBSplineSurface insertUKnotMax(final double u) { final int k = uknot.multiplicity(u); return insertUKnot(u, p - k); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertUKnot(double, int) */ @Override public WB_RBSplineSurface insertUKnot(final double u, final int r) { final int nq = n + r; final int k = uknot.span(u); final int s = uknot.multiplicity(u, k); if (r + s > p) { throw new IllegalArgumentException( "Attempting to increase knot multiplicity above curve degree."); } final WB_NurbsKnot UQ = new WB_NurbsKnot(n + 1 + r, p); for (int i = 0; i <= k; i++) { UQ.setValue(i, uknot.value(i)); } for (int i = 1; i <= r; i++) { UQ.setValue(k + i, u); } for (int i = k + 1; i <= n + p + 1; i++) { UQ.setValue(i + r, uknot.value(i)); } int L = 0; final double[][] alpha = new double[p - s + 1][r + 1]; for (int j = 1; j <= r; j++) { L = k - p + j; for (int i = 0; i <= p - j - s; i++) { alpha[i][j] = (u - uknot.value(L + i)) / (uknot.value(i + k + 1) - uknot.value(L + i)); } } final WB_Homogeneous[][] Q = new WB_Homogeneous[nq + 1][m + 1]; final WB_Homogeneous[] RW = new WB_Homogeneous[p - s + 1]; for (int row = 0; row <= m; row++) { for (int i = 0; i <= k - p; i++) { Q[i][row] = new WB_Homogeneous(wpoints[i][row]); } for (int i = k - s; i <= n; i++) { Q[i + r][row] = new WB_Homogeneous(wpoints[i][row]); } for (int i = 0; i <= p - s; i++) { RW[i] = new WB_Homogeneous(wpoints[k - p + i][row]); } for (int j = 1; j <= r; j++) { L = k - p + j; for (int i = 0; i <= p - j - s; i++) { RW[i] = WB_Homogeneous.interpolate(RW[i], RW[i + 1], alpha[i][j]); } Q[L][row] = RW[0]; Q[k + r - j - s][row] = RW[p - j - s]; } for (int i = L + 1; i < k - s; i++) { Q[i][row] = RW[i - L]; } } return new WB_RBSplineSurface(Q, UQ, vknot); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertVKnot(double) */ @Override public WB_RBSplineSurface insertVKnot(final double v) { return insertVKnot(v, 1); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertVKnotMax(double) */ @Override public WB_RBSplineSurface insertVKnotMax(final double v) { final int k = vknot.multiplicity(v); return insertVKnot(v, q - k); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#insertVKnot(double, int) */ @Override public WB_RBSplineSurface insertVKnot(final double v, final int r) { final int mq = m + r; final int k = vknot.span(v); final int s = vknot.multiplicity(v, k); if (r + s > q) { throw new IllegalArgumentException( "Attempting to increase knot multiplicity above curve degree."); } final WB_NurbsKnot VQ = new WB_NurbsKnot(m + 1 + r, q); for (int i = 0; i <= k; i++) { VQ.setValue(i, vknot.value(i)); } for (int i = 1; i <= r; i++) { VQ.setValue(k + i, v); } for (int i = k + 1; i <= m + q + 1; i++) { VQ.setValue(i + r, vknot.value(i)); } int L = 0; final double[][] alpha = new double[q - s + 1][r + 1]; for (int j = 1; j <= r; j++) { L = k - q + j; for (int i = 0; i <= q - j - s; i++) { alpha[i][j] = (v - vknot.value(L + i)) / (vknot.value(i + k + 1) - vknot.value(L + i)); } } final WB_Homogeneous[][] Q = new WB_Homogeneous[n + 1][mq + 1]; final WB_Homogeneous[] RW = new WB_Homogeneous[q - s + 1]; for (int col = 0; col <= n; col++) { for (int i = 0; i <= k - q; i++) { Q[col][i] = new WB_Homogeneous(wpoints[col][i]); } for (int i = k - s; i <= m; i++) { Q[col][i + r] = new WB_Homogeneous(wpoints[col][i]); } for (int i = 0; i <= q - s; i++) { RW[i] = new WB_Homogeneous(wpoints[col][k - q + i]); } for (int j = 1; j <= r; j++) { L = k - q + j; for (int i = 0; i <= q - j - s; i++) { RW[i] = WB_Homogeneous.interpolate(RW[i], RW[i + 1], alpha[i][j]); } Q[col][L] = RW[0]; Q[col][k + r - j - s] = RW[q - j - s]; } for (int i = L + 1; i < k - s; i++) { Q[col][i] = RW[i - L]; } } return new WB_RBSplineSurface(Q, uknot, VQ); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#isoCurveU(double) */ @Override public WB_RBSpline isoCurveU(final double u) { final WB_Homogeneous[] cpoints = new WB_Homogeneous[m + 1]; final int span = uknot.span(u); double[] N; for (int j = 0; j <= m; j++) { N = uknot.basisFunctions(span, u); cpoints[j] = new WB_Homogeneous(); for (int i = 0; i <= p; i++) { final WB_Homogeneous tmp = wpoints[span - p + i][j]; cpoints[j].add(N[i] * tmp.x, N[i] * tmp.y, N[i] * tmp.z, N[i] * tmp.w); } } return new WB_RBSpline(cpoints, vknot); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#isoCurveV(double) */ @Override public WB_RBSpline isoCurveV(final double v) { final WB_Homogeneous[] cpoints = new WB_Homogeneous[n + 1]; final int span = vknot.span(v); double[] N; for (int i = 0; i <= n; i++) { N = vknot.basisFunctions(span, v); cpoints[i] = new WB_Homogeneous(); for (int j = 0; j <= q; j++) { final WB_Homogeneous tmp = wpoints[i][span - q + j]; cpoints[i].add(N[j] * tmp.x, N[j] * tmp.y, N[j] * tmp.z, N[j] * tmp.w); } } return new WB_RBSpline(cpoints, uknot); } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#splitU(double) */ @Override public WB_RBSplineSurface[] splitU(final double u) { final WB_RBSplineSurface newRBSplineSurface = insertUKnotMax(u); final int k = newRBSplineSurface.uknot().span(u); final int km = newRBSplineSurface.uknot().m; final WB_NurbsKnot knot1 = new WB_NurbsKnot(k + 1 - p, p); for (int i = 0; i < knot1.m; i++) { knot1.setValue(i, newRBSplineSurface.uknot().value(i)); } knot1.setValue(knot1.m, u); knot1.normalize(); final WB_Homogeneous[][] wpoints1 = new WB_Homogeneous[k + 1 - p][m + 1]; for (int j = 0; j <= m; j++) { for (int i = 0; i < k + 1 - p; i++) { wpoints1[i][j] = newRBSplineSurface.wpoints[i][j]; } } final WB_NurbsKnot knot2 = new WB_NurbsKnot(km - k, p); for (int i = 0; i <= p; i++) { knot2.setValue(i, u); } for (int i = k + 1; i <= km; i++) { knot2.setValue(i - k + p, newRBSplineSurface.uknot().value(i)); } knot2.normalize(); final WB_Homogeneous[][] wpoints2 = new WB_Homogeneous[km - k][m + 1]; for (int j = 0; j <= m; j++) { for (int i = 0; i < km - k; i++) { wpoints2[i][j] = newRBSplineSurface.wpoints[k - p + i][j]; } } final WB_RBSplineSurface[] splitSurfaces = new WB_RBSplineSurface[2]; splitSurfaces[0] = new WB_RBSplineSurface(wpoints1, knot1, vknot); splitSurfaces[1] = new WB_RBSplineSurface(wpoints2, knot2, vknot); return splitSurfaces; } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#splitV(double) */ @Override public WB_RBSplineSurface[] splitV(final double v) { final WB_RBSplineSurface newRBSplineSurface = insertVKnotMax(v); final int k = newRBSplineSurface.vknot().span(v); final int km = newRBSplineSurface.vknot().m; final WB_NurbsKnot knot1 = new WB_NurbsKnot(k + 1 - q, q); for (int i = 0; i < knot1.m; i++) { knot1.setValue(i, newRBSplineSurface.vknot().value(i)); } knot1.setValue(knot1.m, v); knot1.normalize(); final WB_Homogeneous[][] wpoints1 = new WB_Homogeneous[n + 1][k + 1 - q]; for (int j = 0; j <= n; j++) { for (int i = 0; i < k + 1 - q; i++) { wpoints1[j][i] = newRBSplineSurface.wpoints[j][i]; } } final WB_NurbsKnot knot2 = new WB_NurbsKnot(km - k, q); for (int i = 0; i <= q; i++) { knot2.setValue(i, v); } for (int i = k + 1; i <= km; i++) { knot2.setValue(i - k + q, newRBSplineSurface.vknot().value(i)); } knot2.normalize(); final WB_Homogeneous[][] wpoints2 = new WB_Homogeneous[n + 1][km - k]; for (int j = 0; j <= n; j++) { for (int i = 0; i < km - k; i++) { wpoints2[j][i] = newRBSplineSurface.wpoints[j][k - q + i]; } } final WB_RBSplineSurface[] splitSurfaces = new WB_RBSplineSurface[2]; splitSurfaces[0] = new WB_RBSplineSurface(wpoints1, uknot, knot1); splitSurfaces[1] = new WB_RBSplineSurface(wpoints2, uknot, knot2); return splitSurfaces; } /* (non-Javadoc) * @see wblut.geom.WB_BSplineSurface#split(double, double) */ @Override public WB_RBSplineSurface[] split(final double u, final double v) { final WB_RBSplineSurface[] splitSurfaces = new WB_RBSplineSurface[4]; WB_RBSplineSurface[] tmp = new WB_RBSplineSurface[2]; tmp = splitU(u); splitSurfaces[0] = tmp[0]; splitSurfaces[2] = tmp[1]; tmp = splitSurfaces[0].splitV(v); splitSurfaces[0] = tmp[0]; splitSurfaces[1] = tmp[1]; tmp = splitSurfaces[2].splitV(v); splitSurfaces[2] = tmp[0]; splitSurfaces[3] = tmp[1]; return splitSurfaces; } }