add NurbsSurfaceEvaluator

This commit is contained in:
David Rose 2003-10-11 02:44:21 +00:00
parent 41232c24d9
commit a356726b35
10 changed files with 1394 additions and 3 deletions

View File

@ -20,6 +20,8 @@
nurbsCurveInterface.I nurbsCurveInterface.h \
nurbsCurveResult.I nurbsCurveResult.h \
nurbsBasisVector.I nurbsBasisVector.h \
nurbsSurfaceEvaluator.I nurbsSurfaceEvaluator.h \
nurbsSurfaceResult.I nurbsSurfaceResult.h \
nurbsVertex.h nurbsVertex.I \
parametricCurve.h \
parametricCurveCollection.I parametricCurveCollection.h \
@ -33,9 +35,11 @@
parametricCurveDrawer.cxx curveFitter.cxx hermiteCurve.cxx \
nurbsCurveDrawer.cxx \
nurbsCurveEvaluator.cxx \
nurbsCurveResult.cxx \
nurbsCurveInterface.cxx \
nurbsCurveResult.cxx \
nurbsBasisVector.cxx \
nurbsSurfaceEvaluator.cxx \
nurbsSurfaceResult.cxx \
nurbsVertex.cxx \
parametricCurve.cxx parametricCurveCollection.cxx \
piecewiseCurve.cxx \
@ -54,6 +58,8 @@
nurbsCurveInterface.I nurbsCurveInterface.h \
nurbsCurveResult.I nurbsCurveResult.h \
nurbsBasisVector.I nurbsBasisVector.h \
nurbsSurfaceEvaluator.I nurbsSurfaceEvaluator.h \
nurbsSurfaceResult.I nurbsSurfaceResult.h \
nurbsVertex.h nurbsVertex.I \
nurbsPPCurve.h \
parametricCurve.h \

View File

@ -40,7 +40,7 @@ NurbsCurveResult(const NurbsBasisVector &basis,
_composed.reserve(num_segments);
for (int i = 0; i < num_segments; i++) {
int vi = _basis.get_vertex_index(i);
nassertv(vi >= 0 && vi < num_vertices);
nassertv(vi >= 0 && vi + order - 1 < num_vertices);
// Create a geometry matrix from our (up to) four involved vertices.
LMatrix4f geom;
@ -86,6 +86,7 @@ eval_segment_point(int segment, float t, LVecBase3f &point) const {
LVecBase4f tvec(t*t2, t2, t, 1.0f);
float weight = tvec.dot(_composed[segment].get_col(3));
point.set(tvec.dot(_composed[segment].get_col(0)) / weight,
tvec.dot(_composed[segment].get_col(1)) / weight,
tvec.dot(_composed[segment].get_col(2)) / weight);

View File

@ -70,7 +70,7 @@ private:
// We pre-compose the basis matrix and the geometry vectors, so we
// have these handy for evaluation. There is one entry in the
// _composed_vector for each entry in basis._segments.
// _composed for each entry in basis._segments.
typedef pvector<LMatrix4f> ComposedGeom;
ComposedGeom _composed;

View File

@ -0,0 +1,271 @@
// Filename: nurbsSurfaceEvaluator.I
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_u_order
// Access: Published
// Description: Sets the order of the surface in the U direction.
// This resets the knot vector to the default knot
// vector for the number of vertices.
//
// The order must be 1, 2, 3, or 4, and the value is one
// more than the degree of the surface.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_u_order(int u_order) {
_u_order = u_order;
_u_knots_dirty = true;
_u_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_u_order
// Access: Published
// Description: Returns the order of the surface in the U direction
// as set by a previous call to set_u_order().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_u_order() const {
return _u_order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_v_order
// Access: Published
// Description: Sets the order of the surface in the V direction.
// This resets the knot vector to the default knot
// vector for the number of vertices.
//
// The order must be 1, 2, 3, or 4, and the value is one
// more than the degree of the surface.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_v_order(int v_order) {
_v_order = v_order;
_v_knots_dirty = true;
_v_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_v_order
// Access: Published
// Description: Returns the order of the surface in the V direction
// as set by a previous call to set_v_order().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_v_order() const {
return _v_order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_num_u_vertices
// Access: Published
// Description: Returns the number of control vertices in the U
// direction on the surface. This is the number passed
// to the last call to reset().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_num_u_vertices() const {
return _num_u_vertices;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_num_v_vertices
// Access: Published
// Description: Returns the number of control vertices in the V
// direction on the surface. This is the number passed
// to the last call to reset().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_num_v_vertices() const {
return _num_v_vertices;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the surface, as a vertex
// in 4-d homogeneous space. In this form, the first
// three components of the vertex should already have
// been scaled by the fourth component, which is the
// homogeneous weight.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_vertex(int ui, int vi, const LVecBase4f &vertex) {
nassertv(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices);
vert(ui, vi).set_vertex(vertex);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the surface. This
// flavor sets the vertex as a 3-d coordinate and a
// weight; the 3-d coordinate values are implicitly
// scaled up by the weight factor.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_vertex(int ui, int vi, const LVecBase3f &vertex, float weight) {
nassertv(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices);
vert(ui, vi).set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_vertex
// Access: Published
// Description: Returns the nth control vertex of the surface, relative
// to its indicated coordinate space.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase4f &NurbsSurfaceEvaluator::
get_vertex(int ui, int vi) const {
nassertr(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices, LVecBase4f::zero());
return vert(ui, vi).get_vertex();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_vertex_space
// Access: Published
// Description: Sets the coordinate space of the nth control vertex.
// If this is not specified, or is set to an empty
// NodePath, the nth control vertex is deemed to be in
// the coordinate space passed to evaluate().
//
// This specifies the space as a fixed NodePath, which
// is always the same NodePath. Also see setting the
// space as a path string, which can specify a different
// NodePath for different instances of the surface.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_vertex_space(int ui, int vi, const NodePath &space) {
nassertv(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices);
vert(ui, vi).set_space(space);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_vertex_space
// Access: Published
// Description: Sets the coordinate space of the nth control vertex.
// If this is not specified, or is set to an empty
// string, the nth control vertex is deemed to be in
// the coordinate space passed to evaluate().
//
// This specifies the space as a string, which describes
// the path to find the node relative to the rel_to
// NodePath when the surface is evaluated.
////////////////////////////////////////////////////////////////////
INLINE void NurbsSurfaceEvaluator::
set_vertex_space(int ui, int vi, const string &space) {
nassertv(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices);
vert(ui, vi).set_space(space);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_extended_vertex
// Access: Public
// Description: Sets an n-dimensional vertex value. This allows
// definition of a NURBS surface or surface in a sparse
// n-dimensional space, typically used for associating
// additional properties (like color or joint
// membership) with each vertex of a surface.
//
// The value d is an arbitrary integer value and
// specifies the dimension of question for this
// particular vertex. Any number of dimensions may be
// specified, and they need not be consecutive. If a
// value for a given dimension is not specified, is it
// implicitly 0.0.
//
// The value is implicitly scaled by the homogenous
// weight value--that is, the fourth component of the
// value passed to set_vertex(). This means the
// ordinary vertex must be set first, before the
// extended vertices can be set.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
set_extended_vertex(int ui, int vi, int d, float value) {
nassertv(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices);
vert(ui, vi).set_extended_vertex(d, value);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::float_extended_vertex
// Access: Public
// Description: Returns an n-dimensional vertex value. See
// set_extended_vertex(). This returns the value set
// for the indicated dimension, or 0.0 if nothing has
// been set.
////////////////////////////////////////////////////////////////////
float NurbsSurfaceEvaluator::
get_extended_vertex(int ui, int vi, int d) const {
nassertr(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices, 0.0f);
return vert(ui, vi).get_extended_vertex(d);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_num_u_knots
// Access: Published
// Description: Returns the number of knot values in the surface in
// the U direction. This is based on the number of
// vertices and the order.
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_num_u_knots() const {
return _num_u_vertices + _u_order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_num_v_knots
// Access: Published
// Description: Returns the number of knot values in the surface in
// the V direction. This is based on the number of
// vertices and the order.
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceEvaluator::
get_num_v_knots() const {
return _num_v_vertices + _v_order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::vert
// Access: Private
// Description: Internal accessor to dereference the 2-d vertex
// coordinate pair into a linear list of vertices.
////////////////////////////////////////////////////////////////////
INLINE NurbsVertex &NurbsSurfaceEvaluator::
vert(int ui, int vi) {
return _vertices[ui * _num_v_vertices + vi];
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::vert
// Access: Private
// Description: Internal accessor to dereference the 2-d vertex
// coordinate pair into a linear list of vertices.
////////////////////////////////////////////////////////////////////
INLINE const NurbsVertex &NurbsSurfaceEvaluator::
vert(int ui, int vi) const {
return _vertices[ui * _num_v_vertices + vi];
}

View File

@ -0,0 +1,353 @@
// Filename: nurbsSurfaceEvaluator.cxx
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "nurbsSurfaceEvaluator.h"
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
NurbsSurfaceEvaluator::
NurbsSurfaceEvaluator() {
_u_order = 4;
_v_order = 4;
_u_knots_dirty = true;
_v_knots_dirty = true;
_u_basis_dirty = true;
_v_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
NurbsSurfaceEvaluator::
~NurbsSurfaceEvaluator() {
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::reset
// Access: Published
// Description: Resets all the vertices and knots to their default
// values, and sets the surface up with the indicated
// number of vertices. You must then call set_vertex()
// repeatedly to fill in all of the vertex values
// appropriately.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
reset(int num_u_vertices, int num_v_vertices) {
int num_vertices = num_u_vertices * num_v_vertices;
_vertices.clear();
_vertices.reserve(num_vertices);
_num_u_vertices = num_u_vertices;
_num_v_vertices = num_v_vertices;
for (int i = 0; i < num_vertices; i++) {
_vertices.push_back(NurbsVertex());
}
_u_knots_dirty = true;
_v_knots_dirty = true;
_u_basis_dirty = true;
_v_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_vertex_space
// Access: Published
// Description: Returns the coordinate space of the nth control
// vertex of the surface, expressed as a NodePath.
////////////////////////////////////////////////////////////////////
NodePath NurbsSurfaceEvaluator::
get_vertex_space(int ui, int vi, const NodePath &rel_to) const {
#ifndef NDEBUG
static NodePath empty_node_path;
nassertr(ui >= 0 && ui < _num_u_vertices &&
vi >= 0 && vi < _num_v_vertices, empty_node_path);
#endif
return vert(ui, vi).get_space(rel_to);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_u_knot
// Access: Published
// Description: Sets the value of the nth knot. Each knot value
// should be greater than or equal to the preceding
// value. If no knot values are set, a default knot
// vector is supplied.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
set_u_knot(int i, float knot) {
if (_u_knots_dirty) {
recompute_u_knots();
}
nassertv(i >= 0 && i < (int)_u_knots.size());
_u_knots[i] = knot;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_u_knot
// Access: Published
// Description: Returns the value of the nth knot.
////////////////////////////////////////////////////////////////////
float NurbsSurfaceEvaluator::
get_u_knot(int i) const {
if (_u_knots_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
}
nassertr(i >= 0 && i < (int)_u_knots.size(), 0.0f);
return _u_knots[i];
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::set_v_knot
// Access: Published
// Description: Sets the value of the nth knot. Each knot value
// should be greater than or equal to the preceding
// value. If no knot values are set, a default knot
// vector is supplied.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
set_v_knot(int i, float knot) {
if (_v_knots_dirty) {
recompute_v_knots();
}
nassertv(i >= 0 && i < (int)_v_knots.size());
_v_knots[i] = knot;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_v_knot
// Access: Published
// Description: Returns the value of the nth knot.
////////////////////////////////////////////////////////////////////
float NurbsSurfaceEvaluator::
get_v_knot(int i) const {
if (_v_knots_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
}
nassertr(i >= 0 && i < (int)_v_knots.size(), 0.0f);
return _v_knots[i];
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::evaluate
// Access: Published
// Description: Returns a NurbsSurfaceResult object that represents the
// result of applying the knots to all of the current
// values of the vertices, transformed into the
// indicated coordinate space.
////////////////////////////////////////////////////////////////////
PT(NurbsSurfaceResult) NurbsSurfaceEvaluator::
evaluate(const NodePath &rel_to) const {
if (_u_basis_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_u_basis();
}
if (_v_basis_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_v_basis();
}
// First, transform the vertices as appropriate.
pvector<LVecBase4f> vecs;
get_vertices(vecs, rel_to);
// And apply those transformed vertices to the basis matrices to
// derive the result.
return new NurbsSurfaceResult(_u_basis, _v_basis,
&vecs[0], &_vertices[0],
_num_u_vertices, _num_v_vertices);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_vertices
// Access: Public
// Description: Fills the indicated vector with the set of vertices
// in the surface, transformed to the given space. This
// flavor returns the vertices in 4-dimensional
// homogenous space.
//
// Vertices are arranged in linear sequence, with the v
// coordinate changing more rapidly.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const {
int num_vertices = (int)_vertices.size();
verts.reserve(verts.size() + num_vertices);
int vi;
for (vi = 0; vi < num_vertices; vi++) {
NodePath space = _vertices[vi].get_space(rel_to);
const LVecBase4f &vertex = _vertices[vi].get_vertex();
if (space.is_empty()) {
verts.push_back(vertex);
} else {
const LMatrix4f &mat = space.get_mat(rel_to);
verts.push_back(vertex * mat);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::get_vertices
// Access: Public
// Description: Fills the indicated vector with the set of vertices
// in the surface, transformed to the given space. This
// flavor returns the vertices in 4-dimensional
// homogenous space.
//
// Vertices are arranged in linear sequence, with the v
// coordinate changing more rapidly.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const {
int num_vertices = (int)_vertices.size();
verts.reserve(verts.size() + num_vertices);
int vi;
for (vi = 0; vi < num_vertices; vi++) {
const NodePath &space = _vertices[vi].get_space(rel_to);
LVecBase4f vertex = _vertices[vi].get_vertex();
if (!space.is_empty()) {
const LMatrix4f &mat = space.get_mat(rel_to);
vertex = vertex * mat;
}
LPoint3f v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
verts.push_back(v3);
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::recompute_u_knots
// Access: Private
// Description: Creates a default knot vector.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
recompute_u_knots() {
_u_knots.clear();
int num_knots = get_num_u_knots();
_u_knots.reserve(num_knots);
float value = 0.0f;
int i = 0;
while (i < _u_order) {
_u_knots.push_back(value);
i++;
}
while (i < num_knots - _u_order) {
value += 1.0f;
_u_knots.push_back(value);
i++;
}
value += 1.0f;
while (i < num_knots) {
_u_knots.push_back(value);
i++;
}
_u_knots_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::recompute_v_knots
// Access: Private
// Description: Creates a default knot vector.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
recompute_v_knots() {
_v_knots.clear();
int num_knots = get_num_v_knots();
_v_knots.reserve(num_knots);
float value = 0.0f;
int i = 0;
while (i < _v_order) {
_v_knots.push_back(value);
i++;
}
while (i < num_knots - _v_order) {
value += 1.0f;
_v_knots.push_back(value);
i++;
}
value += 1.0f;
while (i < num_knots) {
_v_knots.push_back(value);
i++;
}
_v_knots_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::recompute_u_basis
// Access: Private
// Description: Recomputes the basis matrices according to the knot
// vector.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
recompute_u_basis() {
if (_u_knots_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
}
_u_basis.clear(_u_order);
if (_num_u_vertices > _u_order - 1) {
int min_knot = _u_order;
int max_knot = _num_u_vertices + 1;
for (int i = min_knot; i <= max_knot; i++) {
nassertv(i - 1 >= 0 && i < (int)_u_knots.size());
if (_u_knots[i - 1] < _u_knots[i]) {
// Here's a non-empty segment.
_u_basis.append_segment(i - _u_order, &_u_knots[i - _u_order]);
}
}
}
_u_basis_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceEvaluator::recompute_v_basis
// Access: Private
// Description: Recomputes the basis matrices according to the knot
// vector.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceEvaluator::
recompute_v_basis() {
if (_v_knots_dirty) {
((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
}
_v_basis.clear(_v_order);
if (_num_v_vertices > _v_order - 1) {
int min_knot = _v_order;
int max_knot = _num_v_vertices + 1;
for (int i = min_knot; i <= max_knot; i++) {
nassertv(i - 1 >= 0 && i < (int)_v_knots.size());
if (_v_knots[i - 1] < _v_knots[i]) {
// Here's a non-empty segment.
_v_basis.append_segment(i - _v_order, &_v_knots[i - _v_order]);
}
}
}
_v_basis_dirty = false;
}

View File

@ -0,0 +1,113 @@
// Filename: nurbsSurfaceEvaluator.h
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef NURBSSURFACEEVALUATOR_H
#define NURBSSURFACEEVALUATOR_H
#include "pandabase.h"
#include "nurbsBasisVector.h"
#include "nurbsSurfaceResult.h"
#include "nurbsVertex.h"
#include "pointerTo.h"
#include "vector_float.h"
#include "pvector.h"
#include "nodePath.h"
#include "referenceCount.h"
#include "luse.h"
////////////////////////////////////////////////////////////////////
// Class : NurbsSurfaceEvaluator
// Description : This class is an abstraction for evaluating NURBS
// surfaces. It accepts an array of vertices, each of
// which may be in a different coordinate space (as
// defined by a NodePath), as well as an optional knot
// vector.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA NurbsSurfaceEvaluator : public ReferenceCount {
PUBLISHED:
NurbsSurfaceEvaluator();
~NurbsSurfaceEvaluator();
INLINE void set_u_order(int u_order);
INLINE int get_u_order() const;
INLINE void set_v_order(int v_order);
INLINE int get_v_order() const;
void reset(int num_u_vertices, int num_v_vertices);
INLINE int get_num_u_vertices() const;
INLINE int get_num_v_vertices() const;
INLINE void set_vertex(int ui, int vi, const LVecBase4f &vertex);
INLINE void set_vertex(int ui, int vi, const LVecBase3f &vertex, float weight = 1.0);
INLINE const LVecBase4f &get_vertex(int ui, int vi) const;
INLINE void set_vertex_space(int ui, int vi, const NodePath &space);
INLINE void set_vertex_space(int ui, int vi, const string &space);
NodePath get_vertex_space(int ui, int vi, const NodePath &rel_to) const;
INLINE void set_extended_vertex(int ui, int vi, int d, float value);
INLINE float get_extended_vertex(int ui, int vi, int d) const;
INLINE int get_num_u_knots() const;
void set_u_knot(int i, float knot);
float get_u_knot(int i) const;
INLINE int get_num_v_knots() const;
void set_v_knot(int i, float knot);
float get_v_knot(int i) const;
PT(NurbsSurfaceResult) evaluate(const NodePath &rel_to = NodePath()) const;
public:
void get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const;
void get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const;
private:
INLINE NurbsVertex &vert(int ui, int vi);
INLINE const NurbsVertex &vert(int ui, int vi) const;
void recompute_u_knots();
void recompute_v_knots();
void recompute_u_basis();
void recompute_v_basis();
int _u_order;
int _v_order;
typedef pvector<NurbsVertex> Vertices;
Vertices _vertices;
int _num_u_vertices;
int _num_v_vertices;
bool _u_knots_dirty;
bool _v_knots_dirty;
typedef vector_float Knots;
Knots _u_knots;
Knots _v_knots;
bool _u_basis_dirty;
bool _v_basis_dirty;
NurbsBasisVector _u_basis;
NurbsBasisVector _v_basis;
};
#include "nurbsSurfaceEvaluator.I"
#endif

View File

@ -0,0 +1,207 @@
// Filename: nurbsSurfaceResult.I
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE NurbsSurfaceResult::
~NurbsSurfaceResult() {
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_start_u
// Access: Public
// Description: Returns the first legal value of u on the surface.
// Usually this is 0.0.
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_start_u() const {
return _u_basis.get_start_t();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_end_u
// Access: Public
// Description: Returns the last legal value of u on the surface.
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_end_u() const {
return _u_basis.get_end_t();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_start_v
// Access: Public
// Description: Returns the first legal value of v on the surface.
// Usually this is 0.0.
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_start_v() const {
return _v_basis.get_start_t();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_end_v
// Access: Public
// Description: Returns the last legal value of v on the surface.
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_end_v() const {
return _v_basis.get_end_t();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_point
// Access: Published
// Description: Computes the point on the surface corresponding to the
// indicated value in parametric time. Returns true if
// the t value is value, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool NurbsSurfaceResult::
eval_point(float u, float v, LVecBase3f &point) {
int ui = find_u_segment(u);
int vi = find_v_segment(v);
if (ui == -1 || vi == -1) {
return false;
}
eval_segment_point(ui, vi, _u_basis.scale_t(ui, u), _v_basis.scale_t(vi, v),
point);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_normal
// Access: Published
// Description: Computes the normal to the surface at the indicated
// point in parametric time. This normal vector will
// not necessarily be normalized, and could be zero.
// See also eval_point().
////////////////////////////////////////////////////////////////////
INLINE bool NurbsSurfaceResult::
eval_normal(float u, float v, LVecBase3f &normal) {
int ui = find_u_segment(u);
int vi = find_v_segment(v);
if (ui == -1 || vi == -1) {
return false;
}
eval_segment_normal(ui, vi, _u_basis.scale_t(ui, u), _v_basis.scale_t(vi, v),
normal);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_extended_point
// Access: Published
// Description: Evaluates the surface in n-dimensional space according
// to the extended vertices associated with the surface in
// the indicated dimension.
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
eval_extended_point(float u, float v, int d) {
int ui = find_u_segment(u);
int vi = find_v_segment(v);
if (ui == -1 || vi == -1) {
return 0.0f;
}
return eval_segment_extended_point(ui, vi, _u_basis.scale_t(ui, u),
_v_basis.scale_t(vi, v), d);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_num_u_segments
// Access: Public
// Description: Returns the number of piecewise continuous segments
// within the surface in the U direction. This number
// is usually not important unless you plan to call
// eval_segment_point().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceResult::
get_num_u_segments() const {
return _u_basis.get_num_segments();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_num_v_segments
// Access: Public
// Description: Returns the number of piecewise continuous segments
// within the surface in the V direction. This number
// is usually not important unless you plan to call
// eval_segment_point().
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceResult::
get_num_v_segments() const {
return _v_basis.get_num_segments();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_segment_u
// Access: Public
// Description: Accepts a u value in the range [0, 1], and assumed to
// be relative to the indicated segment (as in
// eval_segment_point()), and returns the corresponding
// u value in the entire surface (as in eval_point()).
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_segment_u(int ui, float u) const {
return u * (_u_basis.get_to(ui) - _u_basis.get_from(ui)) + _u_basis.get_from(ui);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::get_segment_v
// Access: Public
// Description: Accepts a v value in the range [0, 1], and assumed to
// be relative to the indicated segment (as in
// eval_segment_point()), and returns the corresponding
// v value in the entire surface (as in eval_point()).
////////////////////////////////////////////////////////////////////
INLINE float NurbsSurfaceResult::
get_segment_v(int vi, float v) const {
return v * (_v_basis.get_to(vi) - _v_basis.get_from(vi)) + _v_basis.get_from(vi);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::verti
// Access: Private
// Description: An internal function to dereference a 2-d vertex
// coordinate pair into a linear list of vertices. This
// returns the linear index corresponding to the 2-d
// pair.
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceResult::
verti(int ui, int vi) const {
return ui * _num_v_vertices + vi;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::segi
// Access: Private
// Description: An internal function to dereference a 2-d segment
// coordinate pair into a linear list of segments. This
// returns the linear index corresponding to the 2-d
// pair.
////////////////////////////////////////////////////////////////////
INLINE int NurbsSurfaceResult::
segi(int ui, int vi) const {
return ui * _v_basis.get_num_segments() + vi;
}

View File

@ -0,0 +1,337 @@
// Filename: nurbsSurfaceResult.cxx
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "nurbsSurfaceResult.h"
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::Constructor
// Access: Public
// Description: The constructor automatically builds up the result as
// the product of the indicated set of basis matrices
// and the indicated table of control vertex positions.
////////////////////////////////////////////////////////////////////
NurbsSurfaceResult::
NurbsSurfaceResult(const NurbsBasisVector &u_basis,
const NurbsBasisVector &v_basis,
const LVecBase4f vecs[], const NurbsVertex *verts,
int num_u_vertices, int num_v_vertices) :
_u_basis(u_basis),
_v_basis(v_basis),
_verts(verts),
_num_u_vertices(num_u_vertices),
_num_v_vertices(num_v_vertices)
{
_last_u_segment = -1;
_last_v_segment = -1;
int u_order = _u_basis.get_order();
int v_order = _v_basis.get_order();
int num_u_segments = _u_basis.get_num_segments();
int num_v_segments = _v_basis.get_num_segments();
int num_segments = num_u_segments * num_v_segments;
_composed.reserve(num_segments);
for (int ui = 0; ui < num_u_segments; ui++) {
const LMatrix4f &u_basis_mat = _u_basis.get_basis(ui);
int un = _u_basis.get_vertex_index(ui);
nassertv(un >= 0 && un + u_order - 1 < _num_u_vertices);
for (int vi = 0; vi < num_v_segments; vi++) {
LMatrix4f v_basis_transpose = transpose(_v_basis.get_basis(vi));
int vn = _v_basis.get_vertex_index(vi);
nassertv(vn >= 0 && vn + v_order - 1 < _num_v_vertices);
// Create four geometry matrices from our (up to) sixteen
// involved vertices.
LVecBase4f c[4][4];
for (int uni = 0; uni < 4; uni++) {
for (int vni = 0; vni < 4; vni++) {
c[uni][vni] = (uni < u_order && vni < v_order) ?
vecs[verti(un + uni, vn + vni)] :
LVecBase4f::zero();
}
}
LMatrix4f geom_x(c[0][0][0], c[0][1][0], c[0][2][0], c[0][3][0],
c[1][0][0], c[1][1][0], c[1][2][0], c[1][3][0],
c[2][0][0], c[2][1][0], c[2][2][0], c[2][3][0],
c[3][0][0], c[3][1][0], c[3][2][0], c[3][3][0]);
LMatrix4f geom_y(c[0][0][1], c[0][1][1], c[0][2][1], c[0][3][1],
c[1][0][1], c[1][1][1], c[1][2][1], c[1][3][1],
c[2][0][1], c[2][1][1], c[2][2][1], c[2][3][1],
c[3][0][1], c[3][1][1], c[3][2][1], c[3][3][1]);
LMatrix4f geom_z(c[0][0][2], c[0][1][2], c[0][2][2], c[0][3][2],
c[1][0][2], c[1][1][2], c[1][2][2], c[1][3][2],
c[2][0][2], c[2][1][2], c[2][2][2], c[2][3][2],
c[3][0][2], c[3][1][2], c[3][2][2], c[3][3][2]);
LMatrix4f geom_w(c[0][0][3], c[0][1][3], c[0][2][3], c[0][3][3],
c[1][0][3], c[1][1][3], c[1][2][3], c[1][3][3],
c[2][0][3], c[2][1][3], c[2][2][3], c[2][3][3],
c[3][0][3], c[3][1][3], c[3][2][3], c[3][3][3]);
// And compose these geometry matrices with the basis matrices
// to produce a new set of matrices, which will be used to
// evaluate the surface.
ComposedMats result;
result._x = u_basis_mat * geom_x * v_basis_transpose;
result._y = u_basis_mat * geom_y * v_basis_transpose;
result._z = u_basis_mat * geom_z * v_basis_transpose;
result._w = u_basis_mat * geom_w * v_basis_transpose;
_composed.push_back(result);
}
}
nassertv((int)_composed.size() == num_segments);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_segment_point
// Access: Published
// Description: Evaluates the point on the surface corresponding to the
// indicated value in parametric time within the
// indicated surface segment. u and v should be in the
// range [0, 1].
//
// The surface is internally represented as a number of
// connected (or possibly unconnected) piecewise
// continuous segments. The exact number of segments
// for a particular surface depends on the knot vector,
// and is returned by get_num_segments(). Normally,
// eval_point() is used to evaluate a point along the
// continuous surface, but when you care more about local
// continuity, you can use eval_segment_point() to
// evaluate the points along each segment.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceResult::
eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const {
float u2 = u*u;
LVecBase4f uvec(u*u2, u2, u, 1.0f);
float v2 = v*v;
LVecBase4f vvec(v*v2, v2, v, 1.0f);
int i = segi(ui, vi);
nassertv(i >= 0 && i < (int)_composed.size());
float weight = vvec.dot(uvec * _composed[i]._w);
point.set(vvec.dot(uvec * _composed[i]._x) / weight,
vvec.dot(uvec * _composed[i]._y) / weight,
vvec.dot(uvec * _composed[i]._z) / weight);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_segment_normal
// Access: Published
// Description: As eval_segment_point, but computes the normal to
// the surface at the indicated point. The normal vector
// will not necessarily be normalized, and could be
// zero.
////////////////////////////////////////////////////////////////////
void NurbsSurfaceResult::
eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const {
/*
float t2 = t*t;
LVecBase4f tvec(t2, t, 1.0f, 0.0f);
normal.set(tvec.dot(_composed[segment].get_col(0)),
tvec.dot(_composed[segment].get_col(1)),
tvec.dot(_composed[segment].get_col(2)));
*/
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::eval_segment_extended_point
// Access: Published
// Description: Evaluates the surface in n-dimensional space according
// to the extended vertices associated with the surface in
// the indicated dimension.
////////////////////////////////////////////////////////////////////
float NurbsSurfaceResult::
eval_segment_extended_point(int ui, int vi, float u, float v, int d) const {
/*
nassertr(segment >= 0 && segment < _basis.get_num_segments(), 0.0f);
int order = _basis.get_order();
int vi = _basis.get_vertex_index(segment);
LVecBase4f geom;
int ci = 0;
while (ci < order) {
geom[ci] = _verts[vi + ci].get_extended_vertex(d);
ci++;
}
while (ci < 4) {
geom[ci] = 0.0f;
ci++;
}
const LMatrix4f &basis = _basis.get_basis(segment);
// Compute matrix * column vector.
LVecBase4f composed_geom(basis.get_row(0).dot(geom),
basis.get_row(1).dot(geom),
basis.get_row(2).dot(geom),
basis.get_row(3).dot(geom));
float t2 = t*t;
LVecBase4f tvec(t*t2, t2, t, 1.0f);
float weight = tvec.dot(_composed[segment].get_col(3));
float result = tvec.dot(composed_geom) / weight;
return result;
*/
return 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::find_u_segment
// Access: Private
// Description: Returns the index of the segment that contains the
// indicated value of t, or -1 if no segment contains
// this value.
////////////////////////////////////////////////////////////////////
int NurbsSurfaceResult::
find_u_segment(float u) {
// Trivially check the endpoints of the surface.
if (u >= get_end_u()) {
return _u_basis.get_num_segments() - 1;
} else if (u <= get_start_u()) {
return 0;
}
// Check the last segment we searched for. Often, two consecutive
// requests are for the same segment.
if (_last_u_segment != -1 && (u >= _last_u_from && u < _last_u_to)) {
return _last_u_segment;
}
// Look for the segment the hard way.
int segment = r_find_u_segment(u, 0, _u_basis.get_num_segments() - 1);
if (segment != -1) {
_last_u_segment = segment;
_last_u_from = _u_basis.get_from(segment);
_last_u_to = _u_basis.get_to(segment);
}
return segment;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::r_find_u_segment
// Access: Private
// Description: Recursively searches for the segment that contains
// the indicated value of t by performing a binary
// search. This assumes the segments are stored in
// increasing order of t, and they don't overlap.
////////////////////////////////////////////////////////////////////
int NurbsSurfaceResult::
r_find_u_segment(float u, int top, int bot) const {
if (bot < top) {
// Not found.
return -1;
}
int mid = (top + bot) / 2;
nassertr(mid >= 0 && mid < _u_basis.get_num_segments(), -1);
float from = _u_basis.get_from(mid);
float to = _u_basis.get_to(mid);
if (from > u) {
// Too high, try lower.
return r_find_u_segment(u, top, mid - 1);
} else if (to <= u) {
// Too low, try higher.
return r_find_u_segment(u, mid + 1, bot);
} else {
// Here we are!
return mid;
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::find_v_segment
// Access: Private
// Description: Returns the index of the segment that contains the
// indicated value of t, or -1 if no segment contains
// this value.
////////////////////////////////////////////////////////////////////
int NurbsSurfaceResult::
find_v_segment(float v) {
// Trivially check the endpoints of the surface.
if (v >= get_end_v()) {
return _v_basis.get_num_segments() - 1;
} else if (v <= get_start_v()) {
return 0;
}
// Check the last segment we searched for. Often, two consecutive
// requests are for the same segment.
if (_last_v_segment != -1 && (v >= _last_v_from && v < _last_v_to)) {
return _last_v_segment;
}
// Look for the segment the hard way.
int segment = r_find_v_segment(v, 0, _v_basis.get_num_segments() - 1);
if (segment != -1) {
_last_v_segment = segment;
_last_v_from = _v_basis.get_from(segment);
_last_v_to = _v_basis.get_to(segment);
}
return segment;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsSurfaceResult::r_find_v_segment
// Access: Private
// Description: Recursively searches for the segment that contains
// the indicated value of t by performing a binary
// search. This assumes the segments are stored in
// increasing order of t, and they don't overlap.
////////////////////////////////////////////////////////////////////
int NurbsSurfaceResult::
r_find_v_segment(float v, int top, int bot) const {
if (bot < top) {
// Not found.
return -1;
}
int mid = (top + bot) / 2;
nassertr(mid >= 0 && mid < _v_basis.get_num_segments(), -1);
float from = _v_basis.get_from(mid);
float to = _v_basis.get_to(mid);
if (from > v) {
// Too high, try lower.
return r_find_v_segment(v, top, mid - 1);
} else if (to <= v) {
// Too low, try higher.
return r_find_v_segment(v, mid + 1, bot);
} else {
// Here we are!
return mid;
}
}

View File

@ -0,0 +1,101 @@
// Filename: nurbsSurfaceResult.h
// Created by: drose (10Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef NURBSSURFACERESULT_H
#define NURBSSURFACERESULT_H
#include "pandabase.h"
#include "referenceCount.h"
#include "nurbsBasisVector.h"
class NurbsVertex;
////////////////////////////////////////////////////////////////////
// Class : NurbsSurfaceResult
// Description : The result of a NurbsSurfaceEvaluator. This object
// represents a surface in a particular coordinate space.
// It can return the point and/or normal to the surface
// at any point.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA NurbsSurfaceResult : public ReferenceCount {
public:
NurbsSurfaceResult(const NurbsBasisVector &u_basis,
const NurbsBasisVector &v_basis,
const LVecBase4f vecs[], const NurbsVertex *verts,
int num_u_vertices, int num_v_vertices);
PUBLISHED:
INLINE ~NurbsSurfaceResult();
INLINE float get_start_u() const;
INLINE float get_end_u() const;
INLINE float get_start_v() const;
INLINE float get_end_v() const;
INLINE bool eval_point(float u, float v, LVecBase3f &point);
INLINE bool eval_normal(float u, float v, LVecBase3f &normal);
INLINE float eval_extended_point(float u, float v, int d);
INLINE int get_num_u_segments() const;
INLINE int get_num_v_segments() const;
void eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const;
void eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const;
float eval_segment_extended_point(int ui, int vi, float u, float v, int d) const;
INLINE float get_segment_u(int ui, float u) const;
INLINE float get_segment_v(int vi, float v) const;
private:
INLINE int verti(int ui, int vi) const;
INLINE int segi(int ui, int vi) const;
int find_u_segment(float u);
int r_find_u_segment(float u, int top, int bot) const;
int find_v_segment(float v);
int r_find_v_segment(float v, int top, int bot) const;
NurbsBasisVector _u_basis;
NurbsBasisVector _v_basis;
const NurbsVertex *_verts;
int _num_u_vertices;
int _num_v_vertices;
// We pre-compose the basis matrix and the geometry vectors, so we
// have these handy for evaluation. There is one entry in the
// _composed for each entry in u_basis._segments *
// v_basis._segments.
class ComposedMats {
public:
LMatrix4f _x, _y, _z, _w;
};
typedef pvector<ComposedMats> ComposedGeom;
ComposedGeom _composed;
int _last_u_segment;
float _last_u_from;
float _last_u_to;
int _last_v_segment;
float _last_v_from;
float _last_v_to;
};
#include "nurbsSurfaceResult.I"
#endif

View File

@ -5,6 +5,8 @@
#include "parametricCurveDrawer.cxx"
#include "nurbsCurveEvaluator.cxx"
#include "nurbsCurveResult.cxx"
#include "nurbsSurfaceEvaluator.cxx"
#include "nurbsSurfaceResult.cxx"
#include "nurbsBasisVector.cxx"
#include "nurbsVertex.cxx"
#include "ropeNode.cxx"