/** * */ package wblut.geom; import wblut.hemesh.HEC_FromFacelist; import wblut.hemesh.HE_Mesh; // TODO: Auto-generated Javadoc /** * The Class WB_BSplineSurface. * * @author Frederik Vanhoutte, W:Blut */ public class WB_BSplineSurface implements WB_Surface { /** The uknot. */ protected WB_NurbsKnot uknot; /** The vknot. */ protected WB_NurbsKnot vknot; /** The points. */ protected WB_Point3d[][] points; /** The p. */ protected int p; /** The n. */ protected int n; /** The q. */ protected int q; /** The m. */ protected int m; /** * Instantiates a new w b_ b spline surface. */ public WB_BSplineSurface() { } /** * Instantiates a new w b_ b spline surface. * * @param controlPoints the control points * @param uknot the uknot * @param vknot the vknot */ public WB_BSplineSurface(final WB_Point3d[][] controlPoints, final WB_NurbsKnot uknot, final WB_NurbsKnot vknot) { 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; points = controlPoints; } /** * Instantiates a new w b_ b spline surface. * * @param controlPoints the control points * @param uknot the uknot * @param vknot the vknot */ public WB_BSplineSurface(final WB_Homogeneous[][] controlPoints, final WB_NurbsKnot uknot, final WB_NurbsKnot vknot) { 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; points = new WB_Point3d[n + 1][m + 1]; for (int i = 0; i <= n; i++) { for (int j = 0; j <= m; j++) { points[i][j] = controlPoints[i][j].project(); } } } /** * Instantiates a new w b_ b spline surface. * * @param controlPoints the control points * @param udegree the udegree * @param vdegree the vdegree */ public WB_BSplineSurface(final WB_Point3d[][] controlPoints, final int udegree, final int vdegree) { uknot = new WB_NurbsKnot(controlPoints.length, udegree); vknot = new WB_NurbsKnot(controlPoints[0].length, vdegree); p = uknot.p(); n = uknot.n(); q = vknot.p(); m = vknot.n(); points = controlPoints; } /** * Instantiates a new w b_ b spline surface. * * @param point00 the point00 * @param point10 the point10 * @param point01 the point01 * @param point11 the point11 */ public WB_BSplineSurface(final WB_Point3d point00, final WB_Point3d point10, final WB_Point3d point01, final WB_Point3d point11) { uknot = new WB_NurbsKnot(2, 1); vknot = new WB_NurbsKnot(2, 1); p = uknot.p(); n = uknot.n(); q = vknot.p(); m = vknot.n(); points = new WB_Point3d[2][2]; points[0][0] = point00; points[0][1] = point01; points[1][0] = point10; points[1][1] = point11; } /* * (non-Javadoc) * @see wblut.nurbs.WB_Surface#surfacePoint(double, double) */ 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); final int uind = uspan - p; final WB_Point3d S = new WB_Point3d(); WB_Point3d tmp; for (int el = 0; el <= q; el++) { tmp = new WB_Point3d(); final int vind = vspan - q + el; for (int k = 0; k <= p; k++) { tmp.add(Nu[k] * points[uind + k][vind].x, Nu[k] * points[uind + k][vind].y, Nu[k] * points[uind + k][vind].z); } S.add(tmp.mult(Nv[el])); } return S; } /** * To control hemesh. * * @return the h e_ mesh */ public HE_Mesh toControlHemesh() { final WB_Point3d[] cpoints = new WB_Point3d[(n + 1) * (m + 1)]; for (int i = 0; i <= n; i++) { for (int j = 0; j <= m; j++) { cpoints[i + (n + 1) * j] = points[i][j]; } } final int[][] faces = new int[n * m][4]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { faces[i + n * j][0] = i + (n + 1) * j; faces[i + n * j][1] = i + 1 + (n + 1) * j; faces[i + n * j][2] = i + 1 + (n + 1) * (j + 1); faces[i + n * j][3] = i + (n + 1) * (j + 1); } } final HEC_FromFacelist fl = new HEC_FromFacelist(); fl.setFaces(faces).setVertices(cpoints); return new HE_Mesh(fl); } /** * Insert u knot. * * @param u the u * @return the w b_ b spline surface */ public WB_BSplineSurface insertUKnot(final double u) { return insertUKnot(u, 1); } /** * Insert u knot max. * * @param u the u * @return the w b_ b spline surface */ public WB_BSplineSurface insertUKnotMax(final double u) { final int k = uknot.multiplicity(u); return insertUKnot(u, p - k); } /** * Insert u knot. * * @param u the u * @param r the r * @return the w b_ b spline surface */ public WB_BSplineSurface 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_Point3d[][] Q = new WB_Point3d[nq + 1][m + 1]; final WB_Point3d[] RW = new WB_Point3d[p - s + 1]; for (int row = 0; row <= m; row++) { for (int i = 0; i <= k - p; i++) { Q[i][row] = new WB_Point3d(points[i][row]); } for (int i = k - s; i <= n; i++) { Q[i + r][row] = new WB_Point3d(points[i][row]); } for (int i = 0; i <= p - s; i++) { RW[i] = new WB_Point3d(points[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_Point3d.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_BSplineSurface(Q, UQ, vknot); } /** * Insert v knot. * * @param v the v * @return the w b_ b spline surface */ public WB_BSplineSurface insertVKnot(final double v) { return insertVKnot(v, 1); } /** * Insert v knot max. * * @param v the v * @return the w b_ b spline surface */ public WB_BSplineSurface insertVKnotMax(final double v) { final int k = vknot.multiplicity(v); return insertVKnot(v, q - k); } /** * Insert v knot. * * @param v the v * @param r the r * @return the w b_ b spline surface */ public WB_BSplineSurface 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_Point3d[][] Q = new WB_Point3d[n + 1][mq + 1]; final WB_Point3d[] RW = new WB_Point3d[q - s + 1]; for (int col = 0; col <= n; col++) { for (int i = 0; i <= k - q; i++) { Q[col][i] = new WB_Point3d(points[col][i]); } for (int i = k - s; i <= m; i++) { Q[col][i + r] = new WB_Point3d(points[col][i]); } for (int i = 0; i <= q - s; i++) { RW[i] = new WB_Point3d(points[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_Point3d.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_BSplineSurface(Q, uknot, VQ); } /** * Iso curve u. * * @param u the u * @return the w b_ b spline */ public WB_BSpline isoCurveU(final double u) { final WB_Point3d[] cpoints = new WB_Point3d[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_Point3d(); for (int i = 0; i <= p; i++) { final WB_Point3d tmp = points[span - p + i][j]; cpoints[j].add(N[i] * tmp.x, N[i] * tmp.y, N[i] * tmp.z); } } return new WB_BSpline(cpoints, vknot); } /** * Iso curve v. * * @param v the v * @return the w b_ b spline */ public WB_BSpline isoCurveV(final double v) { final WB_Point3d[] cpoints = new WB_Point3d[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_Point3d(); for (int j = 0; j <= q; j++) { final WB_Point3d tmp = points[i][span - q + j]; cpoints[i].add(N[j] * tmp.x, N[j] * tmp.y, N[j] * tmp.z); } } return new WB_BSpline(cpoints, uknot); } /** * Points. * * @return the w b_ point3d[][] */ public WB_Point3d[][] points() { return points; } /** * P. * * @return the int */ public int p() { return p; } /** * N. * * @return the int */ public int n() { return n; } /** * Q. * * @return the int */ public int q() { return q; } /** * M. * * @return the int */ public int m() { return m; } /** * Uknot. * * @return the w b_ nurbs knot */ public WB_NurbsKnot uknot() { return uknot; } /** * Vknot. * * @return the w b_ nurbs knot */ public WB_NurbsKnot vknot() { return vknot; } /** * Split u. * * @param u the u * @return the w b_ b spline surface[] */ public WB_BSplineSurface[] splitU(final double u) { final WB_BSplineSurface newBSplineSurface = insertUKnotMax(u); final int k = newBSplineSurface.uknot().span(u); final int km = newBSplineSurface.uknot().m; final WB_NurbsKnot knot1 = new WB_NurbsKnot(k + 1 - p, p); for (int i = 0; i < knot1.m; i++) { knot1.setValue(i, newBSplineSurface.uknot().value(i)); } knot1.setValue(knot1.m, u); knot1.normalize(); final WB_Point3d[][] points1 = new WB_Point3d[k + 1 - p][m + 1]; for (int j = 0; j <= m; j++) { for (int i = 0; i < k + 1 - p; i++) { points1[i][j] = newBSplineSurface.points[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, newBSplineSurface.uknot().value(i)); } knot2.normalize(); final WB_Point3d[][] points2 = new WB_Point3d[km - k][m + 1]; for (int j = 0; j <= m; j++) { for (int i = 0; i < km - k; i++) { points2[i][j] = newBSplineSurface.points[k - p + i][j]; } } final WB_BSplineSurface[] splitSurfaces = new WB_BSplineSurface[2]; splitSurfaces[0] = new WB_BSplineSurface(points1, knot1, vknot); splitSurfaces[1] = new WB_BSplineSurface(points2, knot2, vknot); return splitSurfaces; } /** * Split v. * * @param v the v * @return the w b_ b spline surface[] */ public WB_BSplineSurface[] splitV(final double v) { final WB_BSplineSurface newBSplineSurface = insertVKnotMax(v); final int k = newBSplineSurface.vknot().span(v); final int km = newBSplineSurface.vknot().m; final WB_NurbsKnot knot1 = new WB_NurbsKnot(k + 1 - q, q); for (int i = 0; i < knot1.m; i++) { knot1.setValue(i, newBSplineSurface.vknot().value(i)); } knot1.setValue(knot1.m, v); knot1.normalize(); final WB_Point3d[][] points1 = new WB_Point3d[n + 1][k + 1 - q]; for (int j = 0; j <= n; j++) { for (int i = 0; i < k + 1 - q; i++) { points1[j][i] = newBSplineSurface.points[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, newBSplineSurface.vknot().value(i)); } knot2.normalize(); final WB_Point3d[][] points2 = new WB_Point3d[n + 1][km - k]; for (int j = 0; j <= n; j++) { for (int i = 0; i < km - k; i++) { points2[j][i] = newBSplineSurface.points[j][k - q + i]; } } final WB_BSplineSurface[] splitSurfaces = new WB_BSplineSurface[2]; splitSurfaces[0] = new WB_BSplineSurface(points1, uknot, knot1); splitSurfaces[1] = new WB_BSplineSurface(points2, uknot, knot2); return splitSurfaces; } /** * Split. * * @param u the u * @param v the v * @return the w b_ b spline surface[] */ public WB_BSplineSurface[] split(final double u, final double v) { final WB_BSplineSurface[] splitSurfaces = new WB_BSplineSurface[4]; WB_BSplineSurface[] tmp = new WB_BSplineSurface[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; } /* * (non-Javadoc) * @see wblut.nurbs.WB_Curve#loweru() */ public double loweru() { return uknot.value(0); } /* * (non-Javadoc) * @see wblut.nurbs.WB_Curve#upperu() */ public double upperu() { return uknot.value(uknot.m); } /* * (non-Javadoc) * @see wblut.nurbs.WB_Curve#loweru() */ public double lowerv() { return vknot.value(0); } /* * (non-Javadoc) * @see wblut.nurbs.WB_Curve#upperu() */ public double upperv() { return vknot.value(vknot.m); } }