static Point3f NURBSEvaluateSurface(int uOrder, const Float *uKnot, int ucp, Float u, int vOrder, const Float *vKnot, int vcp, Float v, const Homogeneous3 *cp, Vector3f *dpdu, Vector3f *dpdv) { Homogeneous3 *iso = ALLOCA(Homogeneous3, std::max(uOrder, vOrder)); int uOffset = KnotOffset(uKnot, uOrder, ucp, u); int uFirstCp = uOffset - uOrder + 1; Assert(uFirstCp >= 0 && uFirstCp + uOrder - 1 < ucp); for (int i = 0; i < uOrder; ++i) iso[i] = NURBSEvaluate(vOrder, vKnot, &cp[uFirstCp + i], vcp, ucp, v); int vOffset = KnotOffset(vKnot, vOrder, vcp, v); int vFirstCp = vOffset - vOrder + 1; Assert(vFirstCp >= 0 && vFirstCp + vOrder - 1 < vcp); Homogeneous3 P = NURBSEvaluate(uOrder, uKnot, iso - uFirstCp, ucp, 1, u, dpdu); if (dpdv) { for (int i = 0; i < vOrder; ++i) iso[i] = NURBSEvaluate(uOrder, uKnot, &cp[(vFirstCp + i) * ucp], ucp, 1, u); (void)NURBSEvaluate(vOrder, vKnot, iso - vFirstCp, vcp, 1, v, dpdv); } return Point3f(P.x / P.w, P.y / P.w, P.z / P.w); }
static Point NURBSEvaluateSurface(int uOrder, const float *uKnot, int ucp, float u, int vOrder, const float *vKnot, int vcp, float v, const Homogeneous3 *cp, Vector *dPdu, Vector *dPdv) { Homogeneous3 *iso = (Homogeneous3 *)alloca(max(uOrder, vOrder) * sizeof(Homogeneous3)); int uOffset = KnotOffset(uKnot, uOrder, ucp, u); int uFirstCp = uOffset - uOrder + 1; assert(uFirstCp >= 0 && uFirstCp + uOrder - 1 < ucp); for (int i = 0; i < uOrder; ++i) iso[i] = NURBSEvaluate(vOrder, vKnot, &cp[uFirstCp + i], vcp, ucp, v); int vOffset = KnotOffset(vKnot, vOrder, vcp, v); int vFirstCp = vOffset - vOrder + 1; assert(vFirstCp >= 0 && vFirstCp + vOrder - 1 < vcp); Homogeneous3 P = NURBSEvaluate(uOrder, uKnot, iso - uFirstCp, ucp, 1, u, dPdu); if (dPdv) { for (int i = 0; i < vOrder; ++i) iso[i] = NURBSEvaluate(uOrder, uKnot, &cp[(vFirstCp+i)*ucp], ucp, 1, u); (void)NURBSEvaluate(vOrder, vKnot, iso - vFirstCp, vcp, 1, v, dPdv); } return Point(P.x/P.w, P.y/P.w, P.z/P.w);; }
static Homogeneous3 NURBSEvaluate(int order, const float *knot, const Homogeneous3 *cp, int np, int cpStride, float t, Vector *deriv = NULL) { // int nKnots = np + order; float alpha; int knotOffset = KnotOffset(knot, order, np, t); knot += knotOffset; int cpOffset = knotOffset - order + 1; assert(cpOffset >= 0 && cpOffset < np); Homogeneous3 *cpWork = (Homogeneous3 *)alloca(order * sizeof(Homogeneous3)); for (int i = 0; i < order; ++i) cpWork[i] = cp[(cpOffset+i) * cpStride]; for (int i = 0; i < order - 2; ++i) for (int j = 0; j < order - 1 - i; ++j) { alpha = (knot[1 + j] - t) / (knot[1 + j] - knot[j + 2 - order + i]); assert(alpha >= 0. && alpha <= 1.); cpWork[j].x = cpWork[j].x * alpha + cpWork[j+1].x * (1 - alpha); cpWork[j].y = cpWork[j].y * alpha + cpWork[j+1].y * (1 - alpha); cpWork[j].z = cpWork[j].z * alpha + cpWork[j+1].z * (1 - alpha); cpWork[j].w = cpWork[j].w * alpha + cpWork[j+1].w * (1 - alpha); } alpha = (knot[1] - t) / (knot[1] - knot[0]); assert(alpha >= 0. && alpha <= 1.); Homogeneous3 val(cpWork[0].x * alpha + cpWork[1].x * (1 - alpha), cpWork[0].y * alpha + cpWork[1].y * (1 - alpha), cpWork[0].z * alpha + cpWork[1].z * (1 - alpha), cpWork[0].w * alpha + cpWork[1].w * (1 - alpha)); if (deriv) { float factor = (order - 1) / (knot[1] - knot[0]); Homogeneous3 delta((cpWork[1].x - cpWork[0].x) * factor, (cpWork[1].y - cpWork[0].y) * factor, (cpWork[1].z - cpWork[0].z) * factor, (cpWork[1].w - cpWork[0].w) * factor); deriv->x = delta.x / val.w - (val.x * delta.w / (val.w * val.w)); deriv->y = delta.y / val.w - (val.y * delta.w / (val.w * val.w)); deriv->z = delta.z / val.w - (val.z * delta.w / (val.w * val.w)); } return val; }