diff --git a/panda/src/parametrics/Sources.pp b/panda/src/parametrics/Sources.pp index c2063b06e6..071da62e6e 100644 --- a/panda/src/parametrics/Sources.pp +++ b/panda/src/parametrics/Sources.pp @@ -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 \ diff --git a/panda/src/parametrics/nurbsCurveResult.cxx b/panda/src/parametrics/nurbsCurveResult.cxx index ba2e3dbdec..6c6a2b643c 100644 --- a/panda/src/parametrics/nurbsCurveResult.cxx +++ b/panda/src/parametrics/nurbsCurveResult.cxx @@ -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); diff --git a/panda/src/parametrics/nurbsCurveResult.h b/panda/src/parametrics/nurbsCurveResult.h index 98647fd1ad..1775d4949d 100644 --- a/panda/src/parametrics/nurbsCurveResult.h +++ b/panda/src/parametrics/nurbsCurveResult.h @@ -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 ComposedGeom; ComposedGeom _composed; diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.I b/panda/src/parametrics/nurbsSurfaceEvaluator.I new file mode 100644 index 0000000000..fd1e878041 --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.I @@ -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]; +} diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.cxx b/panda/src/parametrics/nurbsSurfaceEvaluator.cxx new file mode 100644 index 0000000000..08ee54daf6 --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.cxx @@ -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 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 &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 &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; +} diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.h b/panda/src/parametrics/nurbsSurfaceEvaluator.h new file mode 100644 index 0000000000..e964cb5d91 --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.h @@ -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 &verts, const NodePath &rel_to) const; + void get_vertices(pvector &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 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 + diff --git a/panda/src/parametrics/nurbsSurfaceResult.I b/panda/src/parametrics/nurbsSurfaceResult.I new file mode 100644 index 0000000000..30a436aed3 --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceResult.I @@ -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; +} diff --git a/panda/src/parametrics/nurbsSurfaceResult.cxx b/panda/src/parametrics/nurbsSurfaceResult.cxx new file mode 100644 index 0000000000..c5f285f62c --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceResult.cxx @@ -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; + } +} + diff --git a/panda/src/parametrics/nurbsSurfaceResult.h b/panda/src/parametrics/nurbsSurfaceResult.h new file mode 100644 index 0000000000..4fcb2b8d12 --- /dev/null +++ b/panda/src/parametrics/nurbsSurfaceResult.h @@ -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 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 + diff --git a/panda/src/parametrics/parametrics_composite2.cxx b/panda/src/parametrics/parametrics_composite2.cxx index 7a7c3fdf7b..8ab62563ca 100644 --- a/panda/src/parametrics/parametrics_composite2.cxx +++ b/panda/src/parametrics/parametrics_composite2.cxx @@ -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"