joined from add-parametrics

This commit is contained in:
Dave Schuyler 2000-12-22 21:14:11 +00:00
parent 7a7ba255b7
commit 386cc76544
12 changed files with 4431 additions and 0 deletions

View File

@ -0,0 +1,35 @@
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolutil:c dtoolbase:c dtool:m
#begin lib_target
#define TARGET parametrics
#define LOCAL_LIBS \
grutil linmath express putil pandabase
#define SOURCES \
config_parametrics.cxx config_parametrics.h \
curve.cxx curve.h \
curveDrawer.cxx curveDrawer.h \
nurbsCurve.cxx nurbsCurve.h \
nurbsCurveDrawer.cxx nurbsCurveDrawer.h
#define INSTALL_HEADERS \
config_parametrics.h \
curve.h \
curveDrawer.h \
nurbsCurve.h \
nurbsCurveDrawer.h
#define IGATESCAN all
#end lib_target
#begin test_bin_target
#define TARGET test_parametrics
#define LOCAL_LIBS \
parametrics
#define SOURCES \
test_parametrics.cxx
#end test_bin_target

View File

@ -0,0 +1,34 @@
// Filename: config_parametrics.cxx
// Created by: drose (19Mar00)
//
////////////////////////////////////////////////////////////////////
#include "config_parametrics.h"
#include "luse.h"
#include "typedWriteableReferenceCount.h"
#include "namable.h"
#include "curve.h"
#include "curveDrawer.h"
#include "nurbsCurve.h"
#include "nurbsCurveDrawer.h"
#include <dconfig.h>
#include <get_config_path.h>
Configure(config_parametrics);
NotifyCategoryDef(parametrics, "");
ConfigureFn(config_parametrics) {
ParametricCurve::init_type();
PiecewiseCurve::init_type();
CubicCurveseg::init_type();
ParametricCurveDrawer::init_type();
NurbsCurve::init_type();
NurbsCurveDrawer::init_type();
}
const DSearchPath &
get_parametrics_path() {
static DSearchPath *parametrics_path = NULL;
return get_config_path("parametrics-path", parametrics_path);
}

View File

@ -0,0 +1,14 @@
// Filename: config_parametrics.h
// Created by: drose (19Mar00)
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_PARAMETRICS_H
#define CONFIG_PARAMETRICS_H
#include <pandabase.h>
#include <notifyCategoryProxy.h>
NotifyCategoryDecl(parametrics, EXPCL_PANDA, EXPTP_PANDA);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,402 @@
// Filename: curve.h
// Created by: drose (14Mar97)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
#ifndef CURVE_H
#define CURVE_H
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include <typedef.h>
#include <list>
#include <vector>
using namespace std;
#include "typedWriteableReferenceCount.h"
#include "namable.h"
#include "luse.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
// Parametric curve semantic types. A parametric curve may have one
// of these types specified. These serve as hints to the egg reader
// and writer code about the intention of this curve, and have no
// other effect on the curve.
BEGIN_PUBLISH //[
#define PCT_NONE 0
// Unspecified type.
#define PCT_XYZ 1
// A three-dimensional curve in space.
#define PCT_HPR 2
// The curve represents Euler rotation angles.
#define PCT_T 3
// A one-dimensional timewarp curve.
END_PUBLISH //]
//#define LVector3f LVector3f
//typedef LVector3f LVector3f;
// These symbols are used to define the shape of the curve segment to
// CubicCurveseg::compute_seg().
#define RT_POINT 0x01
#define RT_TANGENT 0x02
#define RT_CV 0x03
#define RT_BASE_TYPE 0xff
#define RT_KEEP_ORIG 0x100
class ParametricCurveDrawer;
class HermiteCurveCV;
class HermiteCurve;
class NurbsCurve;
////////////////////////////////////////////////////////////////////
// Class : ParametricCurve
// Description : A virtual base class for parametric curves.
// This encapsulates all curves in 3-d space defined
// for a single parameter t in the range [0,get_max_t()].
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ParametricCurve : public TypedWriteableReferenceCount,
public Namable {
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
virtual bool is_valid() const;
virtual double get_max_t() const;
void set_curve_type(int type);
int get_curve_type() const;
void set_num_dimensions(int num);
int get_num_dimensions() const;
float calc_length() const;
float calc_length(double from, double to) const;
double compute_t(double start_t, double length_offset, double guess,
double threshold) const;
////bool convert_to_hermite(HermiteCurve &hc) const;
bool convert_to_nurbs(NurbsCurve &nc) const;
void ascii_draw() const;
public:
virtual bool get_point(double t, LVector3f &point) const=0;
virtual bool get_tangent(double t, LVector3f &tangent) const=0;
virtual bool get_pt(double t, LVector3f &point, LVector3f &tangent) const=0;
virtual bool get_2ndtangent(double t, LVector3f &tangent2) const=0;
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
public:
struct BezierSeg {
public:
LVector3f _v[4];
double _t;
};
typedef vector<BezierSeg> BezierSegs;
ParametricCurve();
virtual void write_datagram(BamWriter *, Datagram &);
virtual bool GetBezierSegs(BezierSegs &) const {
return false;
}
virtual bool GetBezierSeg(BezierSeg &) const {
return false;
}
void register_drawer(ParametricCurveDrawer *drawer);
void unregister_drawer(ParametricCurveDrawer *drawer);
protected:
virtual ~ParametricCurve();
void invalidate(double t1, double t2);
void invalidate_all();
float r_calc_length(double t1, double t2,
const LVector3f &p1, const LVector3f &p2,
float seglength) const;
typedef list< ParametricCurveDrawer * > DrawerList;
DrawerList _drawers;
int _curve_type;
int _num_dimensions;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
register_type(_type_handle, "ParametricCurve");
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Class : PiecewiseCurve
// Description : A PiecewiseCurve is a curve made up of several curve
// segments, connected in a head-to-tail fashion. The
// length of each curve segment in parametric space is
// definable.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PiecewiseCurve : public ParametricCurve {
public:
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
virtual bool is_valid() const;
virtual double get_max_t() const;
virtual bool get_point(double t, LVector3f &point) const;
virtual bool get_tangent(double t, LVector3f &tangent) const;
virtual bool get_pt(double t, LVector3f &point, LVector3f &tangent) const;
virtual bool get_2ndtangent(double t, LVector3f &tangent2) const;
bool adjust_point(double t,
float px, float py, float pz);
bool adjust_tangent(double t,
float tx, float ty, float tz);
bool adjust_pt(double t,
float px, float py, float pz,
float tx, float ty, float tz);
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
public:
PiecewiseCurve();
int get_num_segs() const;
ParametricCurve *get_curveseg(int ti);
bool insert_curveseg(int ti, ParametricCurve *seg, double tlength);
bool remove_curveseg(int ti);
void remove_all_curvesegs();
double get_tlength(int ti) const;
double get_tstart(int ti) const;
double get_tend(int ti) const;
bool set_tlength(int ti, double tlength);
void make_nurbs(int order, int num_cvs,
const double knots[], const LVector4f cvs[]);
virtual bool GetBezierSegs(BezierSegs &bz_segs) const;
virtual bool
rebuild_curveseg(int rtype0, double t0, const LVector4f &v0,
int rtype1, double t1, const LVector4f &v1,
int rtype2, double t2, const LVector4f &v2,
int rtype3, double t3, const LVector4f &v3);
protected:
~PiecewiseCurve();
bool find_curve(const ParametricCurve *&curve, double &t) const;
double current_seg_range(double t) const;
class Curveseg {
public:
Curveseg() {}
Curveseg(ParametricCurve *c, double t) : _curve(c), _tend(t) {}
int descend_pfb(void *handle);
int store_pfb(void *handle);
int load_pfb(void *handle);
ParametricCurve *_curve;
double _tend;
};
vector<Curveseg> _segs;
int _last_ti;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ParametricCurve::init_type();
register_type(_type_handle, "PiecewiseCurve",
ParametricCurve::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Class : CubicCurveseg
// Description : A CubicCurveseg is any curve that can be completely
// described by four 4-valued basis vectors, one for
// each dimension in three-space, and one for the
// homogeneous coordinate. This includes Beziers,
// Hermites, and NURBS.
//
// This class encapsulates a single curve segment of the
// cubic curve. Normally, when we think of Bezier and
// Hermite curves, we think of a piecewise collection of
// such segments.
//
// Although this class includes methods such as
// hermite_basis() and nurbs_basis(), to generate a
// Hermite and NURBS curve segment, respectively, only
// the final basis vectors are stored: the product of
// the basis matrix of the corresponding curve type, and
// its geometry vectors. This is the minimum
// information needed to evaluate the curve. However,
// the individual CV's that were used to compute these
// basis vectors are not retained; this might be handled
// in a subclass (for instance, HermiteCurve).
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA CubicCurveseg : public ParametricCurve {
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
virtual bool get_point(double t, LVector3f &point) const;
virtual bool get_tangent(double t, LVector3f &tangent) const;
virtual bool get_pt(double t, LVector3f &point, LVector3f &tangent) const;
virtual bool get_2ndtangent(double t, LVector3f &tangent2) const;
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
public:
CubicCurveseg();
CubicCurveseg(const LMatrix4f &basis);
CubicCurveseg(const HermiteCurveCV &cv0,
const HermiteCurveCV &cv1);
CubicCurveseg(const BezierSeg &seg);
CubicCurveseg(int order, const double knots[], const LVector4f cvs[]);
void hermite_basis(const HermiteCurveCV &cv0,
const HermiteCurveCV &cv1,
double tlength = 1.0);
void bezier_basis(const BezierSeg &seg);
void nurbs_basis(int order, const double knots[], const LVector4f cvs[]);
// evaluate_point() and evaluate_vector() both evaluate the curve at
// a given point by applying the basis vector against the vector
// [t3 t2 t 1] (or some derivative). The difference between the
// two is that evaluate_point() is called only with the vector
// [t3 t2 t 1] and computes a point in three-space and will scale by
// the homogeneous coordinate when the curve demands it (e.g. a
// NURBS), while evaluate_vector() is called with some derivative
// vector like [3t2 2t 1 0] and computes a vector difference between
// points, and will never scale by the homogeneous coordinate (which
// would be zero anyway).
void evaluate_point(const LVector4f &tv, LVector3f &result) const {
double h = (rational) ? tv.dot(Bw) : 1.0;
result.set(tv.dot(Bx) / h,
tv.dot(By) / h,
tv.dot(Bz) / h);
}
void evaluate_vector(const LVector4f &tv, LVector3f &result) const {
result.set(tv.dot(Bx),
tv.dot(By),
tv.dot(Bz));
}
virtual bool GetBezierSeg(BezierSeg &seg) const;
static bool compute_seg(int rtype0, double t0, const LVector4f &v0,
int rtype1, double t1, const LVector4f &v1,
int rtype2, double t2, const LVector4f &v2,
int rtype3, double t3, const LVector4f &v3,
const LMatrix4f &B,
const LMatrix4f &Bi,
LMatrix4f &G);
LVector4f Bx, By, Bz, Bw;
bool rational;
protected:
virtual ~CubicCurveseg();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ParametricCurve::init_type();
register_type(_type_handle, "CubicCurveseg",
ParametricCurve::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
// This function is used internally to build the NURBS basis matrix
// based on a given knot sequence.
void compute_nurbs_basis(int order,
const double knots_in[],
LMatrix4f &basis);
#endif

View File

@ -0,0 +1,733 @@
// Filename: curveDrawer.C
// Created by: drose (14Mar97)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "curveDrawer.h"
#include <math.h>
#include "luse.h"
#include "parametrics.h"
#include "typedWriteableReferenceCount.h"
#include "namable.h"
TypeHandle ParametricCurveDrawer::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::Constructor
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
ParametricCurveDrawer::
ParametricCurveDrawer(ParametricCurve *curve) {
_curve = curve;
_time_curve = NULL;
_lines.set_color(1.0, 1.0, 1.0);
_ticks.set_color(1.0, 0.0, 0.0);
_tick_scale = 0.1;
_num_segs = 100;
_num_ticks = 0;
_frame_accurate = false;
_geom_node = new GeomNode;
_drawn = false;
_mapper = DefaultMap;
_curve->register_drawer(this);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::Destructor
// Access: Public, Scheme, Virtual
// Description:
////////////////////////////////////////////////////////////////////
ParametricCurveDrawer::
~ParametricCurveDrawer() {
hide();
if (_curve!=NULL) {
_curve->unregister_drawer(this);
}
if (_time_curve!=NULL) {
_time_curve->unregister_drawer(this);
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_curve
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_curve(ParametricCurve *curve) {
if (_curve!=NULL) {
_curve->unregister_drawer(this);
}
_curve = curve;
_curve->register_drawer(this);
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_curve
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
ParametricCurve *ParametricCurveDrawer::
get_curve() {
return _curve;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_time_curve
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_time_curve(ParametricCurve *curve) {
if (_time_curve!=NULL) {
_time_curve->unregister_drawer(this);
}
_time_curve = curve;
if (_time_curve!=NULL) {
_time_curve->register_drawer(this);
}
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_time_curve
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
ParametricCurve *ParametricCurveDrawer::
get_time_curve() {
return _time_curve;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_geom_node
// Access: Public, Scheme
// Description: Returns a pointer to the drawer's GeomNode. This is
// where the drawer will build the visible
// representation of the curve. This GeomNode must be
// inserted into the scene graph to make the curve
// visible. The GeomNode remains connected to the drawer,
// so that future updates to the drawer will reflect in
// the GeomNode, and the GeomNode will be emptied when the
// drawer destructs. Also see detach_geom_node().
////////////////////////////////////////////////////////////////////
GeomNode *ParametricCurveDrawer::
get_geom_node() {
return _geom_node;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::detach_geom_node
// Access: Public, Scheme
// Description: Detaches the GeomNode from the drawer so that the
// drawing will remain after the death of the drawer.
// Returns the now-static GeomNode. A new, dynamic GeomNode
// is created for the drawer's future use; get_geom_node()
// will return this new GeomNode which will be empty until
// the next call to draw().
////////////////////////////////////////////////////////////////////
GeomNode *ParametricCurveDrawer::
detach_geom_node() {
if (!_drawn) {
draw();
}
PT(GeomNode) g = _geom_node;
_geom_node = new GeomNode;
_drawn = false;
return g;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_num_segs
// Access: Public, Scheme
// Description: Specifies the number of line segments used to
// approximate the curve for each parametric unit. This
// just affects the visual appearance of the curve as it
// is drawn. The total number of segments drawn for the
// curve will be get_max_t() * get_num_segs().
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_num_segs(int num_segs) {
_num_segs = num_segs;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_num_segs
// Access: Public, Scheme
// Description: Returns the number of line segments used to
// approximate the curve for each parametric unit. This
// just affects the visual appearance of the curve as it
// is drawn. The total number of segments drawn for the
// curve will be get_max_t() * get_num_segs().
////////////////////////////////////////////////////////////////////
int ParametricCurveDrawer::
get_num_segs() const {
return _num_segs;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_num_ticks
// Access: Public, Scheme
// Description: Specifies the number of time tick marks drawn
// for each unit of time. These tick marks are drawn at
// equal increments in time to give a visual
// approximation of speed. Specify 0 to disable drawing
// of tick marks.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_num_ticks(int num_ticks) {
_num_ticks = num_ticks;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_num_ticks
// Access: Public, Scheme
// Description: Returns the number of time tick marks per unit of
// time drawn.
////////////////////////////////////////////////////////////////////
int ParametricCurveDrawer::
get_num_ticks() const {
return _num_ticks;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_color
// Access: Public, Scheme
// Description: Specifies the color of the curve when it is drawn.
// The default is white.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_color(float r, float g, float b) {
_lines.set_color(r, g, b);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_color
// Access: Public, Scheme
// Description: Specifies the color of the time tick marks drawn on
// the curve. The default is red.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_tick_color(float r, float g, float b) {
_ticks.set_color(r, g, b);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_frame_accurate
// Access: Public, Scheme
// Description: Specifies whether the curve drawn is to be
// frame-accurate. If true, then changes made to the
// curve dynamically after it has been drawn will be
// reflected correctly in the render window. If false,
// dynamic updates may be drawn before the rest of the
// scene has updated.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_frame_accurate(bool frame_accurate) {
_frame_accurate = frame_accurate;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_frame_accurate
// Access: Public, Scheme
// Description: Returns whether the curve is drawn in frame-accurate
// mode.
////////////////////////////////////////////////////////////////////
bool ParametricCurveDrawer::
get_frame_accurate() const {
return _frame_accurate;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::draw
// Access: Public, Scheme, Virtual
// Description: Creates a series of line segments that approximates
// the curve. These line segments may be made visible
// by adding the GeomNode returned by get_geom_node() into the
// scene graph.
////////////////////////////////////////////////////////////////////
bool ParametricCurveDrawer::
draw() {
// First, remove the old drawing, if any.
hide();
// If there's no curve, draw nothing and return false.
if (_curve==NULL || !_curve->is_valid()) {
return false;
}
// Otherwise, let's go to town!
int total_segs = floor(_curve->get_max_t() * _num_segs + 0.5);
double scale = _curve->get_max_t() / (double)(total_segs-1);
double t;
LVector3f point, tangent;
bool last_in, next_in;
last_in = false;
int i;
for (i = 0; i<total_segs; i++) {
t = (double)i * scale;
// Since we're just drawing the geometric shape of the curve, we
// don't care at this point about the time curve.
next_in = _curve->get_pt(t, point, tangent);
LVector3f p = _mapper(point, tangent, t);
if (!next_in || !last_in) {
_lines.move_to(p);
} else {
_lines.draw_to(p);
}
last_in = next_in;
}
_lines.create(_geom_node, _frame_accurate);
_drawn = true;
// Now draw the time tick marks.
if (_num_ticks > 0) {
LVector3f tangent2;
int total_ticks = floor(_curve->get_max_t() * _num_ticks + 0.5);
scale = get_max_t() / (double)(total_ticks-1);
for (i = 0; i<total_ticks; i++) {
t = (double)i * scale;
if (_time_curve!=NULL) {
_time_curve->get_point(t, point);
t = point[0];
}
_curve->get_pt(t, point, tangent);
_curve->get_2ndtangent(t, tangent2);
LVector3f pt = _mapper(point, tangent, t);
LVector3f t1, t2;
get_tick_marks(_mapper(tangent, tangent2, t + 1.0), t1, t2);
_ticks.move_to(pt - t1 * _tick_scale);
_ticks.draw_to(pt + t1 * _tick_scale);
_ticks.move_to(pt - t2 * _tick_scale);
_ticks.draw_to(pt + t2 * _tick_scale);
}
_ticks.create(_geom_node, _frame_accurate);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::recompute
// Access: Public, Scheme, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool ParametricCurveDrawer::
recompute(double t1, double t2, ParametricCurve *curve) {
if (!_drawn || _curve==NULL || !_curve->is_valid()) {
return false;
}
bool redraw_curve = true;
if (_time_curve!=NULL) {
if (curve != _time_curve) {
// If the recompute call came from the basic curve, and not from
// the time curve, the t1 and t2 it gave us aren't the t1 and t2
// we need. To be safe, we'll run over the whole range.
t1 = 0.0;
t2 = get_max_t();
} else {
// On the other hand, if the recompute call came from the time
// curve, we won't be changing the curve's geometric shape at
// all--we only need to move the tick marks.
redraw_curve = false;
}
}
// Scale t1 and t2 to [0, 1].
t1 = min(max(t1 / get_max_t(), 0.0), 1.0);
t2 = min(max(t2 / get_max_t(), 0.0), 1.0);
int n1, n2, i;
double scale, t;
LVector3f point, tangent;
if (redraw_curve) {
// Compute the number of total segments we will draw. This is based
// on the parametric length of the curve, _curve->get_max_t().
int total_segs = floor(_curve->get_max_t() * _num_segs + 0.5);
n1 = (int)floor(t1 * (total_segs-1));
n2 = (int)ceil(t2 * (total_segs-1));
// This should be implied by the above t1, t2 bounds check.
nassertr(n1>=0 && n1<total_segs, false);
nassertr(n2>=0 && n2<total_segs, false);
scale = _curve->get_max_t() / (double)(total_segs-1);
for (i = n1; i<=n2; i++) {
t = (double)i * scale;
_curve->get_pt(t, point, tangent);
LVector3f p = _mapper(point, tangent, t);
_lines.set_vertex(i, p);
}
}
if (_num_ticks > 0) {
LVector3f tangent2;
int total_ticks = floor(_curve->get_max_t() * _num_ticks + 0.5);
n1 = (int)floor(t1 * (total_ticks-1));
n2 = (int)ceil(t2 * (total_ticks-1));
scale = get_max_t() / (double)(total_ticks-1);
for (i = n1; i<=n2; i++) {
t = (double)i * scale;
if (_time_curve!=NULL) {
_time_curve->get_point(t, point);
t = point[0];
}
_curve->get_pt(t, point, tangent);
_curve->get_2ndtangent(t, tangent2);
LVector3f pt = _mapper(point, tangent, t);
LVector3f t1, t2;
get_tick_marks(_mapper(tangent, tangent2, t + 1.0),
t1, t2);
int ti = i * 4;
_ticks.set_vertex(ti, pt - t1 * _tick_scale);
_ticks.set_vertex(ti+1, pt + t1 * _tick_scale);
_ticks.set_vertex(ti+2, pt - t2 * _tick_scale);
_ticks.set_vertex(ti+3, pt + t2 * _tick_scale);
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::hide
// Access: Public, Scheme
// Description: Removes the lines that were created by a previous
// call to draw().
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
hide() {
_geom_node->clear();
_drawn = false;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_tick_scale
// Access: Public, Scheme
// Description: Sets the visible size of the time tick marks.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_tick_scale(double scale) {
_tick_scale = scale;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_tick_scale
// Access: Public, Scheme
// Description: Returns the size of the time tick marks.
////////////////////////////////////////////////////////////////////
double ParametricCurveDrawer::
get_tick_scale() const {
return _tick_scale;
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_graph_type
// Access: Public, Scheme
// Description: Selects one of a handful of pre-canned graph types
// the drawer can represent. The default, PCD_DEFAULT,
// draws the curve's shape in three-dimensional space;
// other possibilites like PCD_XVST draw a graph of X(t)
// vs. t in the Z and X axes, respectively.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_graph_type(int graph_type) {
switch (graph_type) {
case PCD_DEFAULT:
set_mapper(DefaultMap);
break;
case PCD_XVST:
set_mapper(XvsT);
break;
case PCD_YVST:
set_mapper(YvsT);
break;
case PCD_ZVST:
set_mapper(ZvsT);
break;
case PCD_DXVST:
set_mapper(dXvsT);
break;
case PCD_DYVST:
set_mapper(dYvsT);
break;
case PCD_DZVST:
set_mapper(dZvsT);
break;
case PCD_IXVST:
set_mapper(iXvsT);
break;
case PCD_IYVST:
set_mapper(iYvsT);
break;
default:
parametrics_cat->warning() << "Invalid graph_type " << graph_type << endl;
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::disable
// Access: Public
// Description: Called by the ParametricCurve destructor to indicate
// that a curve we are depending on has just been
// deleted. We must no longer attempt to access this
// curve.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
disable(ParametricCurve *curve) {
if (curve==_time_curve) {
_time_curve = NULL;
} else if (curve==_curve) {
// Hmm, the primary curve has destructed. We're useless now.
_curve = NULL;
hide();
} else {
parametrics_cat->warning()
<< "ParametricCurveDrawer::disable() called on nonsensible curve"
<< endl;
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::set_mapper
// Access: Public
// Description: This establishes the function that will be applied to
// each point of the four-dimensional curve to translate
// it to a three-dimensional representation.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
set_mapper(LVector3fMapper *mapper) {
// If the mapper hasn't changed, don't force a redraw.
if (_mapper != mapper) {
_mapper = mapper;
if (_drawn) {
draw();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::DefaultMap
// Access: Public, Static
// Description: This mapping function returns the X,Y,Z component of
// each point, showing the line's three-dimensional
// shape.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
DefaultMap(const LVector3f &point, const LVector3f &, double) {
return LVector3f(point[0], point[1], point[2]);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::XvsT
// Access: Public, Static
// Description: This mapping function shows a graph of X(t), with the
// x along the Y axis and t along the X axis.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
XvsT(const LVector3f &point, const LVector3f &, double t) {
return LVector3f(t, point[0], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::iXvsT
// Access: Public, Static
// Description: This mapping function shows a graph of X(t), with the
// x along the X axis and t along the Y axis.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
iXvsT(const LVector3f &point, const LVector3f &, double t) {
return LVector3f(point[0], t, 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::YvsT
// Access: Public, Static
// Description: This mapping function shows a graph of Y(t), with the
// y along the Y axis and t along the X axis.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
YvsT(const LVector3f &point, const LVector3f &, double t) {
return LVector3f(t, point[1], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::YvsT
// Access: Public, Static
// Description: This mapping function shows a graph of Y(t), with the
// y along the X axis and t along the Y axis.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
iYvsT(const LVector3f &point, const LVector3f &, double t) {
return LVector3f(point[1], t, 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::ZvsT
// Access: Public, Static
// Description: This mapping function shows a graph of Z(t), with the
// z along the Y axis and t along the X axis.
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
ZvsT(const LVector3f &point, const LVector3f &, double t) {
return LVector3f(t, point[2], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::dXvsT
// Access: Public, Static
// Description: This mapping function shows a graph of dX(t), the
// derivative of X(t).
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
dXvsT(const LVector3f &, const LVector3f &tangent, double t) {
return LVector3f(t, tangent[0], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::dYvsT
// Access: Public, Static
// Description: This mapping function shows a graph of dY(t), the
// derivative of Y(t).
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
dYvsT(const LVector3f &, const LVector3f &tangent, double t) {
return LVector3f(t, tangent[1], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::dZvsT
// Access: Public, Static
// Description: This mapping function shows a graph of dZ(t), the
// derivative of Z(t).
////////////////////////////////////////////////////////////////////
LVector3f ParametricCurveDrawer::
dZvsT(const LVector3f &, const LVector3f &tangent, double t) {
return LVector3f(t, tangent[2], 0.0);
}
////////////////////////////////////////////////////////////////////
// Function: ParametricCurveDrawer::get_tick_marks
// Access: Protected, Static
// Description: Given a tangent vector, computes two vectors at right
// angles to the tangent and to each other, suitable for
// drawing as tick marks.
////////////////////////////////////////////////////////////////////
void ParametricCurveDrawer::
get_tick_marks(const LVector3f &tangent, LVector3f &t1, LVector3f &t2) {
LVector3f tn = tangent;
tn.normalize();
// Decide the smallest axis of tn and cross with the corresponding
// unit vector.
if (fabs(tn[0]) <= fabs(tn[1]) && fabs(tn[0]) <= fabs(tn[2])) {
// X is smallest.
t1 = tn.cross(LVector3f(1.0, 0.0, 0.0));
} else if (fabs(tn[1]) <= fabs(tn[2])) {
// Y is smallest.
t1 = tn.cross(LVector3f(0.0, 1.0, 0.0));
} else {
// Z is smallest.
t1 = tn.cross(LVector3f(0.0, 0.0, 1.0));
}
t2 = tn.cross(t1);
}

View File

@ -0,0 +1,147 @@
// Filename: curveDrawer.h
// Created by: drose (14Mar97)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
#ifndef CURVEDRAWER_H
#define CURVEDRAWER_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "curve.h"
#include "lineSegs.h"
////#include <Performer/pr/pfLinMath.h>
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
typedef LVector3f LVector3fMapper(const LVector3f &point,
const LVector3f &tangent,
double t);
BEGIN_PUBLISH //[
// The different kinds of ParametricCurveDrawer graph types
#define PCD_DEFAULT 1
#define PCD_XVST 2
#define PCD_YVST 3
#define PCD_ZVST 4
#define PCD_DXVST 6
#define PCD_DYVST 7
#define PCD_DZVST 8
#define PCD_IXVST 9
#define PCD_IYVST 10
END_PUBLISH //]
class ParametricSurface;
////////////////////////////////////////////////////////////////////
// Class : ParametricCurveDrawer
// Description : Draws a 3-d parametric curve in the scene by creating
// a series of line segments to approximate the curve.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ParametricCurveDrawer {
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
ParametricCurveDrawer(ParametricCurve *curve);
virtual ~ParametricCurveDrawer();
void set_curve(ParametricCurve *curve);
ParametricCurve *get_curve();
void set_time_curve(ParametricCurve *curve);
ParametricCurve *get_time_curve();
GeomNode *get_geom_node();
GeomNode *detach_geom_node();
void set_num_segs(int num_segs);
int get_num_segs() const;
void set_num_ticks(int num_ticks);
int get_num_ticks() const;
void set_color(float r, float g, float b);
void set_tick_color(float r, float g, float b);
void set_frame_accurate(bool frame_accurate);
bool get_frame_accurate() const;
virtual bool draw();
virtual bool recompute(double t1, double t2, ParametricCurve *curve=NULL);
void hide();
void set_tick_scale(double scale);
double get_tick_scale() const;
void set_graph_type(int graph_type);
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
public:
double get_max_t() const {
return _time_curve==NULL ? _curve->get_max_t() : _time_curve->get_max_t();
}
void disable(ParametricCurve *curve);
void set_mapper(LVector3fMapper *mapper);
static LVector3f DefaultMap(const LVector3f &point, const LVector3f &, double);
static LVector3f XvsT(const LVector3f &point, const LVector3f &, double t);
static LVector3f iXvsT(const LVector3f &point, const LVector3f &, double t);
static LVector3f YvsT(const LVector3f &point, const LVector3f &, double t);
static LVector3f iYvsT(const LVector3f &point, const LVector3f &, double t);
static LVector3f ZvsT(const LVector3f &point, const LVector3f &, double t);
static LVector3f dXvsT(const LVector3f &, const LVector3f &tangent, double t);
static LVector3f dYvsT(const LVector3f &, const LVector3f &tangent, double t);
static LVector3f dZvsT(const LVector3f &, const LVector3f &tangent, double t);
protected:
static void get_tick_marks(const LVector3f &tangent, LVector3f &t1, LVector3f &t2);
PT(GeomNode) _geom_node;
int _num_segs;
ParametricCurve *_curve, *_time_curve;
LineSegs _lines, _ticks;
bool _drawn;
int _num_ticks;
double _tick_scale;
bool _frame_accurate;
LVector3fMapper *_mapper;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
register_type(_type_handle, "ParametricCurveDrawer");
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#endif

View File

@ -0,0 +1,896 @@
// Filename: nurbsCurve.C
// Created by: drose (27Feb98)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
#include "nurbsCurve.h"
#include "luse.h"
#include "parametrics.h"
////#include <initReg.h>
////#include <linMathOutput.h>
#include <fstream>
////#include <alloca.h>
using namespace std;
////////////////////////////////////////////////////////////////////
// Statics
////////////////////////////////////////////////////////////////////
TypeHandle NurbsCurve::_type_handle;
static const LVector3f zero = LVector3f(0.0, 0.0, 0.0);
// This is returned occasionally from some of the functions, and is
// used from time to time as an initializer.
////////////////////////////////////////////////////////////////////
// Function: Indent
// Description: This function duplicates a similar function declared
// in eggBasics.C. It prints a specified number of
// spaces to indent each line of output.
////////////////////////////////////////////////////////////////////
static ostream &
Indent(ostream &out, int indent) {
for (int i=0; i<indent; i++) {
out << ' ';
}
return out;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::Constructor
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
NurbsCurve::
NurbsCurve() {
_order = 4;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::Constructor
// Access: Public, Scheme
// Description: Constructs a NURBS curve equivalent to the indicated
// (possibly non-NURBS) curve.
////////////////////////////////////////////////////////////////////
NurbsCurve::
NurbsCurve(const ParametricCurve &pc) {
_order = 4;
if (!pc.convert_to_nurbs(*this)) {
///DWARNING(dnparametrics)
///<< "Cannot make a NURBS from the indicated curve."
///<< dnend;
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::Constructor
// Access: Public
// Description: Constructs a NURBS curve according to the indicated
// NURBS parameters.
////////////////////////////////////////////////////////////////////
NurbsCurve::
NurbsCurve(int order, int num_cvs,
const double knots[], const LVector4f cvs[]) {
_order = order;
int i;
_cvs.reserve(num_cvs);
for (i = 0; i < num_cvs; i++) {
append_cv(cvs[i]);
}
int num_knots = num_cvs + order;
for (i = 0; i < num_knots; i++) {
set_knot(i, knots[i]);
}
recompute();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::set_order
// Access: Public, Scheme
// Description: Changes the order of the curve. Must be a value from
// 1 to 4. Can only be done when there are no cv's.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
set_order(int order) {
if (order < 1 || order > 4) {
///DWARNING(dnparametrics)
///<< "Invalid NURBS curve order: " << order << dnend;
return;
}
if (!_cvs.empty()) {
///DWARNING(dnparametrics)
///<< "Cannot change NURBS curve order on a nonempty curve." << dnend;
return;
}
_order = order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_order
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
int NurbsCurve::
get_order() const {
return _order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_num_cvs
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
int NurbsCurve::
get_num_cvs() const {
return _cvs.size();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::insert_cv
// Access: Public, Scheme
// Description: Inserts a new CV into the middle of the curve at the
// indicated parametric value. This doesn't change the
// shape or timing of the curve; however, it is
// irreversible: if the new CV is immediately removed,
// the curve will be changed. Returns the index of the
// newly created CV.
////////////////////////////////////////////////////////////////////
int NurbsCurve::
insert_cv(double t) {
if (_cvs.empty()) {
return append_cv(0.0, 0.0, 0.0);
}
if (t <= 0) {
t = 0.0;
}
int k = FindCV(t);
if (k < 0) {
return append_cv(_cvs.back()._p);
}
// Now we are inserting a knot between k-1 and k. We'll adjust the
// CV's according to Bohm's rule.
// First, get the new values of all the CV's that will change.
// These are the CV's in the range [k - (_order-1), k-1].
LVector4f new_cvs[3];
int i;
for (i = 0; i < _order-1; i++) {
int nk = i + k - (_order-1);
double ti = GetKnot(nk);
double d = GetKnot(nk + _order-1) - ti;
if (d == 0.0) {
new_cvs[i] = _cvs[nk-1]._p;
} else {
double a = (t - ti) / d;
new_cvs[i] = (1.0-a)*_cvs[nk-1]._p + a*_cvs[nk]._p;
}
}
// Now insert the new CV
_cvs.insert(_cvs.begin() + k-1, CV());
// Set all the new position values
for (i = 0; i < _order-1; i++) {
int nk = i + k - (_order-1);
_cvs[nk]._p = new_cvs[i];
}
// And set the new knot value.
_cvs[k-1]._t = t;
return k-1;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::append_cv
// Access: Public, Scheme
// Description: Adds a new CV to the end of the curve. Creates a new
// knot value by adding 1 to the last knot value.
// Returns the index of the new CV.
////////////////////////////////////////////////////////////////////
int NurbsCurve::
append_cv(float x, float y, float z) {
return append_cv(LVector4f(x, y, z, 1.0));
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::remove_cv
// Access: Public, Scheme
// Description: Removes the indicated CV from the curve. Returns
// true if the CV index was valid, false otherwise.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
remove_cv(int n) {
if (n < 0 || n >= _cvs.size()) {
return false;
}
_cvs.erase(_cvs.begin() + n);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::remove_all_cvs
// Access: Public, Scheme
// Description: Removes all CV's from the curve.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
remove_all_cvs() {
_cvs.erase(_cvs.begin(), _cvs.end());
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::set_cv_point
// Access: Public, Scheme
// Description: Repositions the indicated CV. Returns true if there
// is such a CV, false otherwise.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
set_cv_point(int n, float x, float y, float z) {
if (n < 0 || n >= _cvs.size()) {
return false;
}
float w = _cvs[n]._p[3];
_cvs[n]._p.set(x*w, y*w, z*w, w);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_cv_point
// Access: Public, Scheme
// Description: Returns the position of the indicated CV.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
get_cv_point(int n, LVector3f &v) const {
if (n < 0 || n >= _cvs.size()) {
v = zero;
} else {
v = (const LVector3f &)_cvs[n]._p / _cvs[n]._p[3];
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_cv_point
// Access: Public, Scheme
// Description: Returns the position of the indicated CV.
////////////////////////////////////////////////////////////////////
const LVector3f &NurbsCurve::
get_cv_point(int n) const {
if (n < 0 || n >= _cvs.size()) {
return zero;
} else {
static LVector3f result;
result = (LVector3f &)_cvs[n]._p / _cvs[n]._p[3];
return result;
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::set_cv_weight
// Access: Public, Scheme
// Description: Sets the weight of the indicated CV.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
set_cv_weight(int n, float w) {
if (n < 0 || n >= _cvs.size()) {
return false;
}
_cvs[n]._p *= (w / _cvs[n]._p[3]);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_cv_weight
// Access: Public, Scheme
// Description: Returns the weight of the indicated CV.
////////////////////////////////////////////////////////////////////
float NurbsCurve::
get_cv_weight(int n) const {
if (n < 0 || n >= _cvs.size()) {
return 0.0;
}
return _cvs[n]._p[3];
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::set_knot
// Access: Public, Scheme
// Description: Sets the value of the indicated knot. There are
// get_num_cvs()+_order-1 knot values, but the first
// _order-1 and the last _order-1 knot values cannot be
// changed. It is also an error to set a knot value
// outside the range of its neighbors.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
set_knot(int n, double t) {
if (n < _order || n-1 >= _cvs.size()) {
return false;
}
_cvs[n-1]._t = t;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::get_knot
// Access: Public, Scheme
// Description: Returns the value of the indicated knot. There are
// get_num_cvs()+_order-1 knot values.
////////////////////////////////////////////////////////////////////
double NurbsCurve::
get_knot(int n) const {
return GetKnot(n);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::print
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
void NurbsCurve::
print() const {
switch (get_curve_type()) {
case PCT_T:
cout << "Time-warping ";
break;
case PCT_XYZ:
cout << "XYZ ";
break;
case PCT_HPR:
cout << "HPR ";
break;
default:
break;
}
cout << "NurbsCurve, order " << _order << ", " << get_num_cvs()
<< " CV's. t ranges from 0 to " << get_max_t() << ".\n";
cout << "CV's:\n";
int i;
for (i = 0; i < _cvs.size(); i++) {
LVector3f p = (const LVector3f &)_cvs[i]._p / _cvs[i]._p[3];
cout << i << ") " << p << ", weight " << _cvs[i]._p[3] << "\n";
}
cout << "Knots: ";
for (i = 0; i < _cvs.size()+_order; i++) {
cout << " " << GetKnot(i);
}
cout << "\n" << flush;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::print_cv
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
void NurbsCurve::
print_cv(int n) const {
if (n < 0 || n >= _cvs.size()) {
cout << "No such CV: " << n << "\n";
} else {
LVector3f p = (const LVector3f &)_cvs[n]._p / _cvs[n]._p[3];
cout << "CV " << n << ": " << p << ", weight "
<< _cvs[n]._p[3] << "\n";
}
cout << flush;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::recompute
// Access: Public, Scheme
// Description: Recalculates the curve basis according to the latest
// position of the CV's, knots, etc. Until this
// function is called, adjusting the NURBS parameters
// will have no visible effect on the curve. Returns
// true if the resulting curve is valid, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
recompute() {
_segs.erase(_segs.begin(), _segs.end());
double knots[8];
LVector4f cvs[4];
if (_cvs.size() > _order-1) {
for (int cv = 0; cv < _cvs.size()-(_order-1); cv++) {
if (GetKnot(cv+_order-1) < GetKnot(cv+_order)) {
// There are _order consecutive CV's that define each segment,
// beginning at cv. Collect the CV's and knot values that define
// this segment.
int c;
for (c = 0; c < _order; c++) {
cvs[c] = _cvs[c+cv]._p;
}
for (c = 0; c < _order+_order; c++) {
knots[c] = GetKnot(c+cv);
}
insert_curveseg(_segs.size(), new CubicCurveseg(_order, knots, cvs),
knots[_order] - knots[_order-1]);
}
}
}
return !_segs.empty();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::normalize_tlength
// Access: Public, Scheme
// Description: Recomputes the knot vector so that the curve is
// nearly uniformly spaced in parametric time. That is,
// calc_length(0, t) == t (approximately) for all t in
// [0, get_max_t()]. This is only an approximation; its
// precision depends on the placement of the knots.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
normalize_tlength() {
int num_knots = _cvs.size() + _order;
double *new_t = (double *)alloca(sizeof(double) * num_knots);
int i;
double last_t = 0.0;
double last_new_t = 0.0;
for (i = 0; i < num_knots; i++) {
double this_t = get_knot(i);
if (this_t == last_t) {
// Keep the same knot value.
new_t[i] = last_new_t;
} else {
// Compute a new knot value that represents the distance on the
// curve since the last knot.
last_new_t += calc_length(last_t, this_t);
new_t[i] = last_new_t;
last_t = this_t;
}
}
// Now set all the knot values at once.
for (i = 0; i < num_knots; i++) {
set_knot(i, new_t[i]);
}
}
#if 0
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::adjust_pt
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
void NurbsCurve::
adjust_pt(double t,
float px, float py, float pz,
float tx, float ty, float tz) {
const ParametricCurve *curve;
bool result = find_curve(curve, t);
if (!result) {
cerr << " no curve segment at t\n";
return;
}
// Figure out which CV's contributed to this segment.
int seg = 0;
dnassert(_cvs.size() > _order-1);
int cv = 0;
for (cv = 0; cv < _cvs.size()-(_order-1); cv++) {
if (GetKnot(cv+_order-1) < GetKnot(cv+_order)) {
if (seg == _last_ti) {
break;
}
seg++;
}
}
// Now copy the cvs and knots in question.
double knots[8];
LVector4f cvs[4];
int c;
for (c = 0; c < 4; c++) {
cvs[c] = (c < _order) ? _cvs[c+cv]._p : LVector4f(0.0, 0.0, 0.0, 0.0);
}
for (c = 0; c < _order+_order; c++) {
knots[c] = GetKnot(c+cv);
}
dnassert(_order>=1 && _order<=4);
LMatrix4f B;
compute_nurbs_basis(_order, knots, B);
LMatrix4f Bi;
if (!Bi.invertFull(B)) {
cerr << "Cannot invert B!\n";
return;
}
// We can rebuild a curve segment given four arbitrary properties of
// the segment: any point along the curve, any tangent along the
// curve, any control point. Given any four such properties, a
// single cubic curve segment is defined.
// We now want to rebuild the curve segment with the following four
// properties: the same first control point, the same last control
// point, and the supplied point and tangent at the indicated value
// of t. To do this, we build a matrix T such that:
// Column 0 of T is the same as column 0 of B^(-1)
// This refers to the first control point.
// Column 1 of T is the vector [ t^3 t^2 t 1 ]
// This refers to the point on the curve at t.
// Column 2 of T is the vector [ 3t^2 2t 1 0 ]
// This refers to the tangent to the curve at t.
// Column 3 of T is the same as column 3 of B^(-1)
// This refers to the last control point.
LMatrix4f T = Bi;
T.setCol(1, t*t*t, t*t, t, 1.0);
T.setCol(2, 3.0*t*t, 2.0*t, 1.0, 0.0);
LMatrix4f Ti;
if (!Ti.invertFull(T)) {
cerr << "Cannot invert T!\n";
}
// Now we build the matrix P such that P represents the solution of
// T, above, when T is applied to the geometry and basis matrices.
// That is, P = G * B * T.
// Column 0 of P is the first control point.
// Column 1 of P is the (new) desired point on the curve at t.
// Column 2 of P is the (new) desired tangent to the curve at t.
// Column 3 of P is the last control point.
LMatrix4f P;
P.setCol(0, cvs[0][0], cvs[0][1], cvs[0][2], cvs[0][3]);
P.setCol(1, px, py, pz, 1.0);
P.setCol(2, tx, ty, tz, 0.0);
P.setCol(3, cvs[3][0], cvs[3][1], cvs[3][2], cvs[3][3]);
// Now we simply solve for G to get G = P * T^(-1) * B^(-1).
LMatrix4f G = P * Ti * Bi;
// Now extract the new CV's from the new G matrix, and restore them
// to the curve.
for (c = 0; c < _order; c++) {
LVector4f &s = _cvs[c+cv]._p;
G.getCol(c, &s[0], &s[1], &s[2], &s[3]);
}
}
#endif
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::rebuild_curveseg
// Access: Public, Virtual
// Description: Rebuilds the current curve segment (as selected by
// the most recent call to find_curve()) according to
// the specified properties (see
// CubicCurveseg::compute_seg). Returns true if
// possible, false if something goes horribly wrong.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
rebuild_curveseg(int rtype0, double t0, const LVector4f &v0,
int rtype1, double t1, const LVector4f &v1,
int rtype2, double t2, const LVector4f &v2,
int rtype3, double t3, const LVector4f &v3) {
// Figure out which CV's contributed to this segment.
int seg = 0;
///dnassert(_cvs.size() > _order-1);
int cv = 0;
for (cv = 0; cv < _cvs.size()-(_order-1); cv++) {
if (GetKnot(cv+_order-1) < GetKnot(cv+_order)) {
if (seg == _last_ti) {
break;
}
seg++;
}
}
// Now copy the cvs and knots in question.
LMatrix4f G;
double knots[8];
int c;
// We only need to build the geometry matrix if at least one of the
// properties depends on the original value.
if ((rtype0 | rtype1 | rtype2 | rtype3) & RT_KEEP_ORIG) {
for (c = 0; c < 4; c++) {
static const LVector4f zero(0.0, 0.0, 0.0, 0.0);
const LVector4f &s = (c < _order) ? _cvs[c+cv]._p : zero;
G.set_col(c, s);
}
}
// But we always need the knot vector to determine the basis matrix.
for (c = 0; c < _order+_order; c++) {
knots[c] = GetKnot(c+cv);
}
LMatrix4f B;
compute_nurbs_basis(_order, knots, B);
LMatrix4f Bi;
Bi = invert(B);
if (!CubicCurveseg::compute_seg(rtype0, t0, v0,
rtype1, t1, v1,
rtype2, t2, v2,
rtype3, t3, v3,
B, Bi, G)) {
return false;
}
// Now extract the new CV's from the new G matrix, and restore them
// to the curve.
for (c = 0; c < _order; c++) {
_cvs[c+cv]._p = G.get_col(c);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::write_egg
// Access: Public, Scheme
// Description: Writes an egg description of the nurbs curve to the
// specified output file. Creates the file if it does
// not exist; appends to the end of it if it does.
// Returns true if the file is successfully written.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
write_egg(const char *filename) {
const char *basename = strrchr(filename, '/');
basename = (basename==NULL) ? filename : basename+1;
ofstream out(filename, ios::app);
return write_egg(out, basename);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::write_egg
// Access: Public, Scheme
// Description: Writes an egg description of the nurbs curve to the
// specified output stream. Returns true if the file is
// successfully written.
////////////////////////////////////////////////////////////////////
bool NurbsCurve::
write_egg(ostream &out, const char *basename) {
if (get_name().empty()) {
// If we don't have a name, come up with one.
int len = strlen(basename);
if (len>4 && strcmp(basename+len-4, ".egg")==0) {
len -= 4;
}
char *name = (char *)alloca(len + 5);
strncpy(name, basename, len);
switch (_curve_type) {
case PCT_XYZ:
strcpy(name+len, "_xyz");
break;
case PCT_HPR:
strcpy(name+len, "_hpr");
break;
case PCT_T:
strcpy(name+len, "_t");
break;
default:
name[len] = '\0';
};
set_name(name);
}
Output(out);
if (out) {
return true;
} else {
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::splice
// Access: Public, Scheme
// Description: Joins the indicated curve onto the end of this curve,
// beginning at the indicated time (which must be
// greater than or equal to max_t). Normally, the first
// point of the new curve will be the same as the last
// point of this curve, but if they are different, the
// curves will automatically connect; however, the
// connection may not be smooth and terminal point of
// the original curve may be lost.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
splice(double t, const NurbsCurve &other) {
if (other._order != _order) {
///DWARNING(dnparametrics)
///<< "Cannot splice NURBS curves of different orders!" << dnend;
return;
}
double old_t = get_max_t();
if (t < old_t) {
///DWARNING(dnparametrics)
///<< "Invalid splicing in the middle of a curve!" << dnend;
t = old_t;
}
// First, define a vector of all the current CV's except the last
// one.
vector<CV> new_cvs(_cvs);
if (!new_cvs.empty()) {
new_cvs.pop_back();
}
// Now add all the new CV's.
int cv;
for (cv = 0; cv < other._cvs.size(); cv++) {
CV new_cv(other._cvs[cv]);
if (cv+1 < _order) {
new_cv._t = old_t;
} else {
new_cv._t += t;
}
new_cvs.push_back(new_cv);
}
// Now assign that vector.
_cvs = new_cvs;
recompute();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::Output
// Access: Public
// Description: Formats the Nurbs curve for output to an Egg file.
////////////////////////////////////////////////////////////////////
void NurbsCurve::
Output(ostream &out, int indent) const {
Indent(out, indent)
<< "<VertexPool> " << get_name() << ".pool {\n";
int cv;
for (cv = 0; cv < _cvs.size(); cv++) {
Indent(out, indent+2) << "<Vertex> " << cv << " { "
<< _cvs[cv]._p << " }\n";
}
Indent(out, indent) << "}\n";
Indent(out, indent) << "<NURBSCurve> " << get_name() << " {\n";
if (_curve_type!=PCT_NONE) {
Indent(out, indent+2) << "<Char*> type { ";
switch (_curve_type) {
case PCT_XYZ:
out << "XYZ";
break;
case PCT_HPR:
out << "HPR";
break;
case PCT_T:
out << "T";
break;
};
out << " }\n";
}
Indent(out, indent+2) << "<Order> { " << _order << " }\n";
Indent(out, indent+2) << "<Knots> {";
int k;
int num_knots = _cvs.size() + _order;
for (k = 0; k < num_knots; k++) {
if (k%6 == 0) {
out << "\n";
Indent(out, indent+4);
}
out << GetKnot(k) << " ";
}
out << "\n";
Indent(out, indent+2) << "}\n";
Indent(out, indent+2) << "<VertexRef> {";
for (cv = 0; cv < _cvs.size(); cv++) {
if (cv%10 == 1) {
out << "\n";
Indent(out, indent+3);
}
out << " " << cv;
}
out << "\n";
Indent(out, indent+4) << "<Ref> { " << get_name() << ".pool }\n";
Indent(out, indent+2) << "}\n";
Indent(out, indent) << "}\n";
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::Destructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
NurbsCurve::
~NurbsCurve() {
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurve::FindCV
// Access: Protected
// Description: Finds the first knot whose value is >= t, or -1 if t
// is beyond the end of the curve.
////////////////////////////////////////////////////////////////////
int NurbsCurve::
FindCV(double t) {
int i;
for (i = _order-1; i < _cvs.size(); i++) {
if (_cvs[i]._t >= t) {
return i+1;
}
}
return -1;
}

View File

@ -0,0 +1,164 @@
// Filename: nurbsCurve.h
// Created by: drose (27Feb98)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
#ifndef NURBSCURVE_H
#define NURBSCURVE_H
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "curve.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////#define LVector3f pfVec3
//typedef pfVec3 LVector3f;
class HermiteCurve;
////////////////////////////////////////////////////////////////////
// Class : NurbsCurve
// Description : A Nonuniform Rational B-Spline.
//
// This class is actually implemented as a
// PiecewiseCurve made up of several CubicCurvesegs,
// each of which is created using the nurbs_basis()
// method. The list of CV's and knots is kept here,
// within the NurbsCurve class.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA NurbsCurve : public PiecewiseCurve {
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
NurbsCurve();
NurbsCurve(const ParametricCurve &hc);
NurbsCurve(int order, int num_cvs,
const double knots[], const LVector4f cvs[]);
void set_order(int order);
int get_order() const;
int get_num_cvs() const;
int get_num_knots() const {
return _cvs.size() + _order;
}
int insert_cv(double t);
int append_cv(float x, float y, float z);
inline int append_cv(const LVector3f &v) {
return append_cv(LVector4f(v[0], v[1], v[2], 1.0));
}
inline int append_cv(const LVector4f &v) {
_cvs.push_back(CV(v, GetKnot(_cvs.size())+1.0));
return _cvs.size()-1;
}
bool remove_cv(int n);
void remove_all_cvs();
bool set_cv_point(int n, float x, float y, float z);
inline bool set_cv_point(int n, const LVector3f &v) {
return set_cv_point(n, v[0], v[1], v[2]);
}
void get_cv_point(int n, LVector3f &v) const;
const LVector3f &get_cv_point(int n) const;
bool set_cv_weight(int n, float w);
float get_cv_weight(int n) const;
bool set_knot(int n, double t);
double get_knot(int n) const;
void print() const;
void print_cv(int n) const;
bool recompute();
void normalize_tlength();
bool write_egg(const char *filename);
bool write_egg(ostream &out, const char *basename);
void splice(double t, const NurbsCurve &other);
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
public:
virtual bool
rebuild_curveseg(int rtype0, double t0, const LVector4f &v0,
int rtype1, double t1, const LVector4f &v1,
int rtype2, double t2, const LVector4f &v2,
int rtype3, double t3, const LVector4f &v3);
CubicCurveseg *get_curveseg(int ti) {
return (CubicCurveseg *)PiecewiseCurve::get_curveseg(ti);
}
double
GetKnot(int n) const {
if (n < _order || _cvs.empty()) {
return 0.0;
} else if (n-1 >= _cvs.size()) {
return _cvs.back()._t;
} else {
return _cvs[n-1]._t;
}
}
void Output(ostream &out, int indent=0) const;
protected:
virtual ~NurbsCurve();
int FindCV(double t);
int _order;
class CV {
public:
CV() {}
CV(const LVector4f &p, double t) : _p(p), _t(t) {}
LVector4f _p;
double _t;
};
vector<CV> _cvs;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
PiecewiseCurve::init_type();
register_type(_type_handle, "NurbsCurve",
PiecewiseCurve::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#endif

View File

@ -0,0 +1,313 @@
// Filename: nurbsCurveDrawer.C
// Created by: drose (27Feb98)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "nurbsCurveDrawer.h"
#include "luse.h"
#include "parametrics.h"
#include "typedWriteableReferenceCount.h"
#include "namable.h"
#include <math.h>
TypeHandle NurbsCurveDrawer::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::Constructor
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
NurbsCurveDrawer::
NurbsCurveDrawer(NurbsCurve *curve) : ParametricCurveDrawer(curve) {
set_cv_color(1.0, 0.0, 0.0);
set_hull_color(1.0, 0.5, 0.5);
set_knot_color(0.0, 0.0, 1.0);
_cvs.set_thickness(4.0);
_hull.set_thickness(1.0);
_knots.set_thickness(4.0);
_show_cvs = true;
_show_hull = true;
_show_knots = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::Destructor
// Access: Public, Scheme, Virtual
// Description:
////////////////////////////////////////////////////////////////////
NurbsCurveDrawer::
~NurbsCurveDrawer() {
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_cv_color
// Access: Public, Scheme
// Description: Specifies the color of the CV's.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_cv_color(float r, float g, float b) {
_cv_color.set(r, g, b);
_cvs.set_color(r, g, b);
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_knot_color
// Access: Public, Scheme
// Description: Specifies the color of the knots.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_knot_color(float r, float g, float b) {
_knot_color.set(r, g, b);
_knots.set_color(r, g, b);
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_hull_color
// Access: Public, Scheme
// Description: Specifies the color of the convex hull.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_hull_color(float r, float g, float b) {
_hull_color.set(r, g, b);
_hull.set_color(r, g, b);
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::draw
// Access: Public, Scheme, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
draw() {
NurbsCurve *nurbs = (NurbsCurve *)_curve;
// Make sure the curve is fresh.
nurbs->recompute();
// First, draw the curve itself.
if (!ParametricCurveDrawer::draw()) {
return false;
}
int i;
if (_show_knots) {
_num_cvs = nurbs->get_num_cvs();
_knotnums.erase(_knotnums.begin(), _knotnums.end());
double lt = -1.0;
int ki = -1;
for (i = 0; i < _num_cvs; i++) {
double t = nurbs->GetKnot(i);
if (t != lt) {
lt = t;
LVector3f knot_pos, knot_tan;
nurbs->get_pt(nurbs->GetKnot(i), knot_pos, knot_tan);
_knots.move_to(_mapper(knot_pos, knot_tan, t));
ki++;
}
_knotnums.push_back(ki);
}
_knots.create(_geom_node, _frame_accurate);
}
if (_show_cvs) {
_num_cvs = nurbs->get_num_cvs();
for (i = 0; i < _num_cvs; i++) {
_cvs.move_to(_mapper(nurbs->get_cv_point(i), LVector3f(0.0, 0.0, 0.0),
nurbs->GetKnot(i+1)));
}
_cvs.create(_geom_node, _frame_accurate);
}
if (_show_hull) {
_num_cvs = nurbs->get_num_cvs();
for (i = 0; i < _num_cvs; i++) {
_hull.draw_to(_mapper(nurbs->get_cv_point(i), LVector3f(0.0, 0.0, 0.0),
nurbs->GetKnot(i+1)));
}
_hull.create(_geom_node, _frame_accurate);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::recompute
// Access: Public, Scheme, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
recompute(double t1, double t2, ParametricCurve *curve) {
return draw();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_show_cvs
// Access: Public, Scheme
// Description: Sets the flag that hides or shows the CV's.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_show_cvs(bool flag) {
_show_cvs = flag;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::get_show_cvs
// Access: Public, Scheme
// Description: Returns the current state of the show-CV's flag.
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
get_show_cvs() const {
return _show_cvs;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_show_hull
// Access: Public, Scheme
// Description: Sets the flag that hides or shows the convex hull.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_show_hull(bool flag) {
_show_hull = flag;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::get_show_hull
// Access: Public, Scheme
// Description: Returns the current state of the show-hull flag.
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
get_show_hull() const {
return _show_hull;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::set_show_knots
// Access: Public, Scheme
// Description: Sets the flag that hides or shows the knots.
////////////////////////////////////////////////////////////////////
void NurbsCurveDrawer::
set_show_knots(bool flag) {
_show_knots = flag;
if (_drawn) {
draw();
}
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::get_show_knots
// Access: Public, Scheme
// Description: Returns the current state of the show-knots flag.
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
get_show_knots() const {
return _show_knots;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::hilight
// Access: Public, Scheme
// Description: Hilights a particular CV by showing it and its knot
// in a different color. Returns true if the CV exists
// and has been drawn, false otherwise.
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
hilight(int n, float hr, float hg, float hb) {
// If there's no curve, do nothing and return false.
if (_curve==NULL || !_curve->is_valid()) {
return false;
}
if (n < 0 || n >= _cvs.get_num_vertices()) {
// Also return false if we're out of range.
return false;
}
NurbsCurve *nurbs = (NurbsCurve *)_curve;
if (_show_cvs) {
_cvs.set_vertex_color(n, hr, hg, hb);
}
if (_show_knots) {
///dnassert(_knotnums[n] >= 0 && _knotnums[n] < _knots.get_num_vertices());
_knots.set_vertex_color(_knotnums[n], hr, hg, hb);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveDrawer::unhilight
// Access: Public, Scheme
// Description: Removes the hilight previously set on a CV.
////////////////////////////////////////////////////////////////////
bool NurbsCurveDrawer::
unhilight(int n) {
if (_curve==NULL || !_curve->is_valid()) {
return false;
}
if (n < 0 || n >= _cvs.get_num_vertices()) {
return false;
}
NurbsCurve *nurbs = (NurbsCurve *)_curve;
if (_show_cvs) {
_cvs.set_vertex_color(n, _cv_color[0], _cv_color[1], _cv_color[2]);
}
if (_show_knots) {
///dnassert(_knotnums[n] >= 0 && _knotnums[n] < _knots.get_num_vertices());
_knots.set_vertex_color(_knotnums[n],
_knot_color[0], _knot_color[1], _knot_color[2]);
}
return true;
}

View File

@ -0,0 +1,96 @@
// Filename: nurbsCurveDrawer.h
// Created by: drose (27Feb98)
//
////////////////////////////////////////////////////////////////////
// Copyright (C) 1992,93,94,95,96,97 Walt Disney Imagineering, Inc.
//
// These coded instructions, statements, data structures and
// computer programs contain unpublished proprietary information of
// Walt Disney Imagineering and are protected by Federal copyright
// law. They may not be disclosed to third parties or copied or
// duplicated in any form, in whole or in part, without the prior
// written consent of Walt Disney Imagineering Inc.
////////////////////////////////////////////////////////////////////
//
#ifndef NURBSCURVEDRAWER_H
#define NURBSCURVEDRAWER_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "curveDrawer.h"
#include "nurbsCurve.h"
#include "lineSegs.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Class : NurbsCurveDrawer
// Description : Draws a Nurbs curve, also drawing in the control
// vertices and tangent vectors.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA NurbsCurveDrawer : public ParametricCurveDrawer {
////////////////////////////////////////////////////////////////////
// Member functions visible to Scheme
////////////////////////////////////////////////////////////////////
PUBLISHED:
NurbsCurveDrawer(NurbsCurve *curve);
virtual ~NurbsCurveDrawer();
void set_cv_color(float r, float g, float b);
void set_hull_color(float r, float g, float b);
void set_knot_color(float r, float g, float b);
virtual bool draw();
virtual bool recompute(double t1, double t2, ParametricCurve *curve=NULL);
void set_show_cvs(bool flag);
bool get_show_cvs() const;
void set_show_hull(bool flag);
bool get_show_hull() const;
void set_show_knots(bool flag);
bool get_show_knots() const;
bool hilight(int n, float hr=1.0, float hg=1.0, float hb=0.0);
bool unhilight(int n);
////////////////////////////////////////////////////////////////////
// Member functions not visible to Scheme
////////////////////////////////////////////////////////////////////
protected:
LVector3f _cv_color, _hull_color, _knot_color;
int _num_cvs, _num_hull, _num_knots;
LineSegs _hull, _knots, _cvs;
vector<int> _knotnums;
bool _show_cvs, _show_hull, _show_knots;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ParametricCurveDrawer::init_type();
register_type(_type_handle, "NurbsCurveDrawer",
ParametricCurveDrawer::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#endif