📄 nurbeval.c
字号:
/* * NurbEval.c - Code for evaluating NURB surfaces. * * John Peterson */#include <stdlib.h>#include <stdio.h>#include <math.h>#include "nurbs.h"#include "drawing.h"/* * Return the current knot the parameter u is less than or equal to. * Find this "breakpoint" allows the evaluation routines to concentrate on * only those control points actually effecting the curve around u.] * * m is the number of points on the curve (or surface direction) * k is the order of the curve (or surface direction) * kv is the knot vector ([0..m+k-1]) to find the break point in. */longFindBreakPoint( double u, double * kv, long m, long k ){ long i; if (u == kv[m+1]) /* Special case for closed interval */ return m; i = m + k; while ((u < kv[i]) && (i > 0)) i--; return( i );}/* * Compute Bi,k(u), for i = 0..k. * u is the parameter of the spline to find the basis functions for * brkPoint is the start of the knot interval ("segment") * kv is the knot vector * k is the order of the curve * bvals is the array of returned basis values. * * (From Bartels, Beatty & Barsky, p.387) */static voidBasisFunctions( double u, long brkPoint, double * kv, long k, double * bvals ){ register long r, s, i; register double omega; bvals[0] = 1.0; for (r = 2; r <= k; r++) { i = brkPoint - r + 1; bvals[r - 1] = 0.0; for (s = r-2; s >= 0; s--) { i++; if (i < 0) omega = 0; else omega = (u - kv[i]) / (kv[i + r - 1] - kv[i]); bvals[s + 1] = bvals[s + 1] + (1 - omega) * bvals[s]; bvals[s] = omega * bvals[s]; } }}/* * Compute derivatives of the basis functions Bi,k(u)' */static voidBasisDerivatives( double u, long brkPoint, double * kv, long k, double * dvals ){ register long s, i; register double omega, knotScale; BasisFunctions( u, brkPoint, kv, k - 1, dvals ); dvals[k-1] = 0.0; /* BasisFunctions misses this */ knotScale = kv[brkPoint + 1L] - kv[brkPoint]; i = brkPoint - k + 1L; for (s = k - 2L; s >= 0L; s--) { i++; omega = knotScale * ((double)(k-1L)) / (kv[i+k-1L] - kv[i]); dvals[s + 1L] += -omega * dvals[s]; dvals[s] *= omega; }}/* * Calculate a point p on NurbSurface n at a specific u, v using the tensor product. * If utan and vtan are not nil, compute the u and v tangents as well. * * Note the valid parameter range for u and v is * (kvU[orderU] <= u < kvU[numU), (kvV[orderV] <= v < kvV[numV]) */voidCalcPoint(double u, double v, NurbSurface * n, Point3 * p, Point3 * utan, Point3 * vtan){ register long i, j, ri, rj; register Point4 * cp; register double tmp; register double wsqrdiv; long ubrkPoint, ufirst; double bu[MAXORDER], buprime[MAXORDER]; long vbrkPoint, vfirst; double bv[MAXORDER], bvprime[MAXORDER]; Point4 r, rutan, rvtan; r.x = 0.0; r.y = 0.0; r.z = 0.0; r.w = 0.0; rutan = r; rvtan = r; /* Evaluate non-uniform basis functions (and derivatives) */ ubrkPoint = FindBreakPoint( u, n->kvU, n->numU-1, n->orderU ); ufirst = ubrkPoint - n->orderU + 1; BasisFunctions( u, ubrkPoint, n->kvU, n->orderU, bu ); if (utan) BasisDerivatives( u, ubrkPoint, n->kvU, n->orderU, buprime ); vbrkPoint = FindBreakPoint( v, n->kvV, n->numV-1, n->orderV ); vfirst = vbrkPoint - n->orderV + 1; BasisFunctions( v, vbrkPoint, n->kvV, n->orderV, bv ); if (vtan) BasisDerivatives( v, vbrkPoint, n->kvV, n->orderV, bvprime ); /* Weight control points against the basis functions */ for (i = 0; i < n->orderV; i++) for (j = 0; j < n->orderU; j++) { ri = n->orderV - 1L - i; rj = n->orderU - 1L - j; tmp = bu[rj] * bv[ri]; cp = &( n->points[i+vfirst][j+ufirst] ); r.x += cp->x * tmp; r.y += cp->y * tmp; r.z += cp->z * tmp; r.w += cp->w * tmp; if (utan) { tmp = buprime[rj] * bv[ri]; rutan.x += cp->x * tmp; rutan.y += cp->y * tmp; rutan.z += cp->z * tmp; rutan.w += cp->w * tmp; } if (vtan) { tmp = bu[rj] * bvprime[ri]; rvtan.x += cp->x * tmp; rvtan.y += cp->y * tmp; rvtan.z += cp->z * tmp; rvtan.w += cp->w * tmp; } } /* Project tangents, using the quotient rule for differentiation */ wsqrdiv = 1.0 / (r.w * r.w); if (utan) { utan->x = (r.w * rutan.x - rutan.w * r.x) * wsqrdiv; utan->y = (r.w * rutan.y - rutan.w * r.y) * wsqrdiv; utan->z = (r.w * rutan.z - rutan.w * r.z) * wsqrdiv; } if (vtan) { vtan->x = (r.w * rvtan.x - rvtan.w * r.x) * wsqrdiv; vtan->y = (r.w * rvtan.y - rvtan.w * r.y) * wsqrdiv; vtan->z = (r.w * rvtan.z - rvtan.w * r.z) * wsqrdiv; } p->x = r.x / r.w; p->y = r.y / r.w; p->z = r.z / r.w;}/* * Draw a mesh of points by evaluating the surface at evenly spaced * points. */voidDrawEvaluation( NurbSurface * n ){ Point3 p, utan, vtan; register long i, j; register double u, v, d; SurfSample ** pts ; long Granularity = 10; /* Controls the number of steps in u and v */ /* Allocate storage for the grid of points generated */ CHECK( pts = (SurfSample**) malloc( (Granularity+1L) * sizeof( SurfSample* ))); CHECK( pts[0] = (SurfSample*) malloc( (Granularity+1L)*(Granularity+1L) * sizeof( SurfSample ))); for (i = 1; i <= Granularity; i++) pts[i] = &(pts[0][(Granularity+1L) * i]); /* Compute points on curve */ for (i = 0; i <= Granularity; i++) { v = ((double) i / (double) Granularity) * (n->kvV[n->numV] - n->kvV[n->orderV-1]) + n->kvV[n->orderV-1]; for (j = 0; j <= Granularity; j++) { u = ((double) j / (double) Granularity) * (n->kvU[n->numU] - n->kvU[n->orderU-1]) + n->kvU[n->orderU-1]; CalcPoint( u, v, n, &(pts[i][j].point), &utan, &vtan ); (void) V3Cross( &utan, &vtan, &p ); d = V3Length( &p ); if (d != 0.0) { p.x /= d; p.y /= d; p.z /= d; } else { p.x = 0; p.y = 0; p.z = 0; } pts[i][j].normLen = d; pts[i][j].normal = p; pts[i][j].u = u; pts[i][j].v = v; } } /* Draw the grid */ for (i = 0; i < Granularity; i++) for (j = 0; j < Granularity; j++) { (*DrawTriangle)( &pts[i][j], &pts[i+1][j+1], &pts[i+1][j] ); (*DrawTriangle)( &pts[i][j], &pts[i][j+1], &pts[i+1][j+1] ); } free( pts[0] ); free( pts );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -