Mark requested curve fitting
This commit is contained in:
parent
f450390286
commit
3f8e49bd1e
|
|
@ -0,0 +1,460 @@
|
|||
// Filename: curveFitter.C
|
||||
// Created by: drose (17Sep98)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 "pointerTo.h"
|
||||
////#include "pandabase.h"
|
||||
|
||||
#include "curveFitter.h"
|
||||
#include "config_parametrics.h"
|
||||
#include "curve.h"
|
||||
#include "nurbsCurve.h"
|
||||
#include "hermiteCurve.h"
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
TypeHandle CurveFitter::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::reset
|
||||
// Access: Public
|
||||
// Description: Removes all the data points previously added to the
|
||||
// CurveFitter, and initializes it for a new curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
reset() {
|
||||
_data.erase(_data.begin(), _data.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::add_point
|
||||
// Access: Public
|
||||
// Description: Adds a single sample point.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
add_point(double t, const LVector3f &point) {
|
||||
DataPoint dp;
|
||||
dp._t = t;
|
||||
dp._point = point;
|
||||
_data.push_back(dp);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::sample
|
||||
// Access: Public
|
||||
// Description: Generates a series of data points by sampling the
|
||||
// given curve the indicated number of times. If even
|
||||
// is true, the sampled t value is taken from the actual
|
||||
// curve length, as opposed to the parametric length.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
sample(ParametricCurve *curve, int count, bool even) {
|
||||
double max_t = curve->get_max_t();
|
||||
double t, last_t, d;
|
||||
DataPoint dp;
|
||||
|
||||
last_t = 0.0;
|
||||
d = 0.0;
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
t = max_t * (double)i / (double)(count-1);
|
||||
curve->get_point(t, dp._point);
|
||||
|
||||
if (even) {
|
||||
d += curve->calc_length(last_t, t);
|
||||
dp._t = d;
|
||||
} else {
|
||||
dp._t = t;
|
||||
}
|
||||
|
||||
_data.push_back(dp);
|
||||
last_t = t;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::generate_even
|
||||
// Access: Public
|
||||
// Description: Generates a set of data points whose x coordinate is
|
||||
// evenly distributed across the indicated distance and
|
||||
// parametric time. Useful before a call to
|
||||
// compute_timewarp().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
generate_even(int count, double net_distance, double net_time) {
|
||||
double t, d;
|
||||
DataPoint dp;
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
t = net_time * (double)i / (double)(count-1);
|
||||
d = net_distance * (double)i / (double)(count-1);
|
||||
|
||||
dp._point.set(d, 0.0, 0.0);
|
||||
dp._t = t;
|
||||
_data.push_back(dp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::wrap_hpr
|
||||
// Access: Public
|
||||
// Description: Assumes the data points collected represent a set of
|
||||
// HPR coordinates. Resets each data point so that the
|
||||
// maximum delta between any two consecutive points is
|
||||
// 180 degrees, which should prevent incorrect HPR
|
||||
// wrapping.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
wrap_hpr() {
|
||||
Data::iterator di;
|
||||
LVector3f last(0.0, 0.0, 0.0);
|
||||
LVector3f net(0.0, 0.0, 0.0);
|
||||
|
||||
for (di = _data.begin(); di != _data.end(); ++di) {
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
(*di)._point[i] += net[i];
|
||||
|
||||
while (((*di)._point[i] - last[i]) > 180.0) {
|
||||
(*di)._point[i] -= 360.0;
|
||||
net[i] -= 360.0;
|
||||
}
|
||||
|
||||
while (((*di)._point[i] - last[i]) < -180.0) {
|
||||
(*di)._point[i] += 360.0;
|
||||
net[i] += 360.0;
|
||||
}
|
||||
|
||||
last[i] = (*di)._point[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::compute_timewarp
|
||||
// Access: Public
|
||||
// Description: Assumes the data points already collected represent
|
||||
// the distance along a given curve at each unit of
|
||||
// parametric time (only the X coordinate is used).
|
||||
// Computes a new set of data points based on the
|
||||
// indicated curve that will serve as a timewarp to
|
||||
// produce this effect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
compute_timewarp(const ParametricCurve *xyz) {
|
||||
Data::iterator di;
|
||||
double last_t = 0.0;
|
||||
double last_d = 0.0;
|
||||
double last_ratio = 1.0;
|
||||
|
||||
for (di = _data.begin(); di != _data.end(); ++di) {
|
||||
double d = (*di)._point[0];
|
||||
double t = xyz->compute_t(last_t, d - last_d,
|
||||
last_t + last_ratio * (d - last_d),
|
||||
0.001);
|
||||
(*di)._point.set(t, 0.0, 0.0);
|
||||
|
||||
/*
|
||||
// Special HPR computation
|
||||
{
|
||||
LVector3f tangent;
|
||||
LMatrix4f mat;
|
||||
pfCoord c;
|
||||
static double last_h = 0.0;
|
||||
static double h_net = 0.0;
|
||||
|
||||
xyz->get_tangent(t, tangent);
|
||||
look_at(mat, tangent, LVector3f(0.0, 0.0, 1.0));
|
||||
mat.getOrthoCoord(&c);
|
||||
cerr << "Replacing R " << c.hpr[2] << " with " << (*di)._point[1] << "\n";
|
||||
c.hpr[2] = (*di)._point[1];
|
||||
c.hpr[0] += h_net;
|
||||
|
||||
// Check the wrap on the heading
|
||||
if ((c.hpr[0] - last_h) > 180.0) {
|
||||
c.hpr[0] -= 360.0;
|
||||
h_net -= 360.0;
|
||||
}
|
||||
|
||||
if ((c.hpr[0] - last_h) < -180.0) {
|
||||
c.hpr[0] += 360.0;
|
||||
h_net += 360.0;
|
||||
}
|
||||
|
||||
cerr << "H is " << c.hpr[0] << " h_net is " << h_net << "\n";
|
||||
last_h = c.hpr[0];
|
||||
|
||||
(*di)._point = c.hpr;
|
||||
(*di)._t = t;
|
||||
}
|
||||
*/
|
||||
|
||||
if (d != last_d) {
|
||||
last_ratio = (t - last_t) / (d - last_d);
|
||||
}
|
||||
last_t = t;
|
||||
last_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::sort_points
|
||||
// Access: Public
|
||||
// Description: Sorts all the data points in order by parametric
|
||||
// time, in case they were added in an incorrect order.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
sort_points() {
|
||||
sort(_data.begin(), _data.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::desample
|
||||
// Access: Public
|
||||
// Description: Removes sample points in order to reduce the
|
||||
// complexity of a sampled curve. Keeps one out of
|
||||
// every factor samples. Also keeps the first and the
|
||||
// last samples.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
desample(double factor) {
|
||||
int in, out;
|
||||
double count = factor;
|
||||
|
||||
out = 0;
|
||||
for (in = 0; in < _data.size()-1; in++) {
|
||||
if (count >= factor) {
|
||||
_data[out] = _data[in];
|
||||
out++;
|
||||
count -= factor;
|
||||
}
|
||||
count += 1.0;
|
||||
}
|
||||
|
||||
_data[out] = _data.back();
|
||||
out++;
|
||||
|
||||
_data.erase(_data.begin() + out, _data.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::compute_tangents
|
||||
// Access: Public
|
||||
// Description: Once a set of points has been built, and prior to
|
||||
// calling MakeHermite() or MakeNurbs(),
|
||||
// ComputeTangents() must be called to set up the
|
||||
// tangents correctly (unless the tangents were defined
|
||||
// as the points were added).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
compute_tangents(double scale) {
|
||||
// If the head and tail points match up, close the curve.
|
||||
bool closed =
|
||||
(_data.front()._point.almost_equal(_data.back()._point, 0.001));
|
||||
|
||||
int i;
|
||||
int len = _data.size();
|
||||
|
||||
// First, get all the points in the middle, excluding endpoints.
|
||||
// These are handled the same whether we are closing the curve or
|
||||
// not.
|
||||
for (i = 1; i < len-1; i++) {
|
||||
_data[i]._tangent =
|
||||
(_data[i+1]._point - _data[i-1]._point) * scale /
|
||||
(_data[i+1]._t - _data[i-1]._t);
|
||||
}
|
||||
|
||||
// Now handle the endpoints.
|
||||
if (closed) {
|
||||
_data[0]._tangent = _data[len-1]._tangent =
|
||||
(_data[1]._point - _data[len-2]._point) * scale /
|
||||
((_data[1]._t - _data[0]._t) + (_data[len-1]._t - _data[len-2]._t));
|
||||
|
||||
} else {
|
||||
_data[0]._tangent =
|
||||
(_data[1]._point - _data[0]._point) * scale /
|
||||
((_data[1]._t - _data[0]._t) * 2.0);
|
||||
_data[len-1]._tangent =
|
||||
(_data[len-1]._point - _data[len-2]._point) * scale /
|
||||
((_data[len-1]._t - _data[len-2]._t) * 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::make_hermite
|
||||
// Access: Public
|
||||
// Description: Converts the current set of data points into a
|
||||
// Hermite curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurve *CurveFitter::
|
||||
make_hermite() const {
|
||||
HermiteCurve *hc = new HermiteCurve;
|
||||
|
||||
Data::const_iterator di;
|
||||
for (di = _data.begin(); di != _data.end(); ++di) {
|
||||
int n = hc->insert_cv((*di)._t);
|
||||
hc->set_cv_type(n, HC_SMOOTH);
|
||||
hc->set_cv_point(n, (*di)._point);
|
||||
hc->set_cv_in(n, (*di)._tangent);
|
||||
hc->set_cv_out(n, (*di)._tangent);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::make_nurbs
|
||||
// Access: Public
|
||||
// Description: Converts the current set of data points into a
|
||||
// NURBS curve. This gives a smoother curve than
|
||||
// produced by MakeHermite().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NurbsCurve *CurveFitter::
|
||||
make_nurbs() const {
|
||||
if (_data.size() < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
NurbsCurve *nc = new NurbsCurve;
|
||||
nc->set_order(4);
|
||||
|
||||
// First, we need four CV's to get started.
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->set_knot(4, _data[1]._t);
|
||||
|
||||
nc->recompute();
|
||||
LVector3f junk;
|
||||
nc->get_point(nc->get_max_t(), junk); // Reference the last segment.
|
||||
const LVector3f &p0 = _data[0]._point;
|
||||
LVector3f t0 = _data[0]._tangent * 2.0;
|
||||
LVector3f t1 = _data[1]._tangent * 2.0;
|
||||
const LVector3f &p1 = _data[1]._point;
|
||||
|
||||
nc->rebuild_curveseg(RT_POINT, 0.0, pfVec4(p0[0], p0[1], p0[2], 1.0),
|
||||
RT_TANGENT, 0.0, pfVec4(t0[0], t0[1], t0[2], 0.0),
|
||||
RT_TANGENT, 1.0, pfVec4(t1[0], t1[1], t1[2], 0.0),
|
||||
RT_POINT, 1.0, pfVec4(p1[0], p1[1], p1[2], 1.0));
|
||||
|
||||
int i;
|
||||
for (i = 2; i < _data.size(); i++) {
|
||||
cerr << "Adding point " << i << "\n";
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->set_knot(i + 3, _data[i]._t);
|
||||
nc->recompute();
|
||||
nc->get_point(nc->get_max_t(), junk);
|
||||
|
||||
/*
|
||||
const LVector3f &p0 = _data[i-1]._point;
|
||||
const LVector3f &t0 = _data[i-1]._tangent;
|
||||
const LVector3f &p1 = _data[i]._point;
|
||||
const LVector3f &t1 = _data[i]._tangent;
|
||||
|
||||
nc->rebuild_curveseg(RT_POINT, 0.0, pfVec4(p0[0], p0[1], p0[2], 1.0),
|
||||
RT_TANGENT, 0.0, pfVec4(t0[0], t0[1], t0[2], 0.0),
|
||||
RT_TANGENT, 1.0, pfVec4(t1[0], t1[1], t1[2], 0.0),
|
||||
RT_POINT, 1.0, pfVec4(p1[0], p1[1], p1[2], 1.0));
|
||||
*/
|
||||
|
||||
const LVector3f &pi = _data[i]._point;
|
||||
nc->rebuild_curveseg(RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_POINT, 1.0, pfVec4(pi[0], pi[1], pi[2], 1.0));
|
||||
}
|
||||
|
||||
/*
|
||||
nc->append_cv(LVector3f(0.0, 0.0, 0.0));
|
||||
nc->recompute();
|
||||
nc->get_point(nc->get_max_t(), junk);
|
||||
const LVector3f &pi = _data[_data.size()-1]._point;
|
||||
nc->rebuild_curveseg(RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_CV | RT_KEEP_ORIG, 0.0, pfVec4(),
|
||||
RT_CV, 0.0, pfVec4(pi[0], pi[1], pi[2], 1.0));
|
||||
*/
|
||||
|
||||
nc->recompute();
|
||||
return nc;
|
||||
|
||||
#else
|
||||
|
||||
// We start with the HermiteCurve produced above, then convert it to
|
||||
// NURBS form.
|
||||
PT(HermiteCurve) hc = new HermiteCurve();
|
||||
NurbsCurve *nc = new NurbsCurve(*hc);
|
||||
|
||||
// Now we even out the knots to smooth out the curve and make
|
||||
// everything c2 continuous.
|
||||
|
||||
int num_knots = nc->get_num_knots();
|
||||
|
||||
// We expect this to be a 4th order curve, since we just converted
|
||||
// it from a Hermite.
|
||||
assert(nc->get_order() == 4);
|
||||
assert(num_knots > 0);
|
||||
|
||||
// Now the knot sequence goes something like this:
|
||||
// 0 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 4
|
||||
|
||||
// We'll consider pairs of knot values beginning at position 3 and
|
||||
// every third position thereafter. We just even out these values
|
||||
// between their two neighbors.
|
||||
|
||||
int i;
|
||||
double k1, k2 = nc->get_knot(num_knots-1);
|
||||
for (i = 3; i < num_knots - 4; i += 3) {
|
||||
k1 = nc->get_knot(i-1);
|
||||
k2 = nc->get_knot(i+2);
|
||||
nc->set_knot(i, (k1 + k1 + k2) / 3.0);
|
||||
nc->set_knot(i+1, (k1 + k2 + k2) / 3.0);
|
||||
}
|
||||
|
||||
// The last knot must have the terminal value.
|
||||
nc->set_knot(num_knots-4, k2);
|
||||
|
||||
// Finally, recompute the curve.
|
||||
nc->recompute();
|
||||
|
||||
return nc;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::print
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
print() const {
|
||||
output(cerr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CurveFitter::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CurveFitter::
|
||||
output(ostream &out) const {
|
||||
Data::const_iterator di;
|
||||
|
||||
for (di = _data.begin(); di != _data.end(); ++di) {
|
||||
out << (*di) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// Filename: curveFitter.h
|
||||
// Created by: drose (17Sep98)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 CURVEFITTER_H
|
||||
#define CURVEFITTER_H
|
||||
|
||||
#include <typedef.h>
|
||||
////#include <linMathOutput.h>
|
||||
#include "luse.h"
|
||||
#include <vector>
|
||||
////#include <Performer/pr/pfLinMath.h>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
class HermiteCurve;
|
||||
class NurbsCurve;
|
||||
class ParametricCurve;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CurveFitter
|
||||
// Description :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CurveFitter {
|
||||
PUBLISHED:
|
||||
void reset();
|
||||
void add_point(double t, const LVector3f &point);
|
||||
|
||||
void sample(ParametricCurve *curve, int count, bool even);
|
||||
void generate_even(int count, double net_distance, double net_time);
|
||||
|
||||
void wrap_hpr();
|
||||
void compute_timewarp(const ParametricCurve *xyz);
|
||||
void sort_points();
|
||||
void desample(double factor);
|
||||
|
||||
void compute_tangents(double scale);
|
||||
HermiteCurve *make_hermite() const;
|
||||
NurbsCurve *make_nurbs() const;
|
||||
|
||||
void print() const;
|
||||
|
||||
public:
|
||||
void output(ostream &out) const;
|
||||
|
||||
class DataPoint {
|
||||
public:
|
||||
DataPoint() : _t(0.0), _point(0.0, 0.0, 0.0), _tangent(0.0, 0.0, 0.0) { }
|
||||
void output(ostream &out) const {
|
||||
out << "Time " << _t << " point " << _point << " tan " << _tangent;
|
||||
}
|
||||
|
||||
int operator < (const DataPoint &other) const {
|
||||
return _t < other._t;
|
||||
}
|
||||
|
||||
double _t;
|
||||
LVector3f _point;
|
||||
LVector3f _tangent;
|
||||
};
|
||||
|
||||
typedef vector<DataPoint> Data;
|
||||
Data _data;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
register_type(_type_handle, "CurveFitter");
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
inline ostream &operator << (ostream &out, const CurveFitter::DataPoint &dp) {
|
||||
dp.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline ostream &operator << (ostream &out, const CurveFitter &cf) {
|
||||
cf.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,987 @@
|
|||
// Filename: hermiteCurve.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 "hermiteCurve.h"
|
||||
#include "config_parametrics.h"
|
||||
#include "luse.h"
|
||||
|
||||
////#include <initReg.h>
|
||||
#include <math.h>
|
||||
#include <fstream>
|
||||
////#include <alloca.h>
|
||||
////#include <Performer/pf/pfBuffer.h>
|
||||
////#include <DConfig.h>
|
||||
////#include <perfalloc.h>
|
||||
////#include <pfb_util.h>
|
||||
using namespace std;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Statics
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypeHandle HermiteCurve::_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: show_vec3
|
||||
// Description: This function writes a LVector3f, with a specified
|
||||
// number of significant dimensions.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
static ostream &
|
||||
show_vec3(ostream &out, int indent, const LVector3f &v, int num_dimensions) {
|
||||
Indent(out, indent) << v[0];
|
||||
for (int i = 1; i<num_dimensions; i++) {
|
||||
out << " " << v[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurveCV::
|
||||
HermiteCurveCV() {
|
||||
_name = NULL;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::copy_constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurveCV::
|
||||
HermiteCurveCV(const HermiteCurveCV &c) :
|
||||
_p(c._p), _in(c._in), _out(c._out),
|
||||
_type(c._type) {
|
||||
if (c._name==NULL) {
|
||||
_name = NULL;
|
||||
} else {
|
||||
_name = new char[strlen(c._name)+1];
|
||||
strcpy(_name, c._name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurveCV::
|
||||
~HermiteCurveCV() {
|
||||
if (_name != NULL) {
|
||||
delete [] _name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::set_in
|
||||
// Access: Public
|
||||
// Description: Sets the CV's in tangent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurveCV::
|
||||
set_in(const LVector3f &in) {
|
||||
_in = in;
|
||||
/*
|
||||
double l;
|
||||
switch (_type) {
|
||||
case HC_G1:
|
||||
l = _in.length();
|
||||
if (l!=0.0) {
|
||||
_out = _in * _out.length() / l;
|
||||
}
|
||||
break;
|
||||
|
||||
case HC_SMOOTH:
|
||||
_out = _in;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::set_out
|
||||
// Access: Public
|
||||
// Description: Sets the CV's out tangent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurveCV::
|
||||
set_out(const LVector3f &out) {
|
||||
_out = out;
|
||||
/*
|
||||
double l;
|
||||
switch (_type) {
|
||||
case HC_G1:
|
||||
l = _out.length();
|
||||
if (l!=0.0) {
|
||||
_in = _out * _in.length() / l;
|
||||
}
|
||||
break;
|
||||
|
||||
case HC_SMOOTH:
|
||||
_in = _out;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::set_type
|
||||
// Access: Public
|
||||
// Description: Sets the continuity type of the CV. Values may be
|
||||
// HC_CUT, indicating a discontinous break in the curve,
|
||||
// HC_FREE, for unconstrained in and out tangents,
|
||||
// HC_G1, for in and out tangents constrained to be
|
||||
// collinear, and HC_SMOOTH, for in and out tangents
|
||||
// constrained to be equal. Other than HC_CUT, these
|
||||
// are for documentation only; setting this has no
|
||||
// direct effect on the tangents.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurveCV::
|
||||
set_type(int type) {
|
||||
_type = type;
|
||||
/*
|
||||
switch (_type) {
|
||||
case HC_G1:
|
||||
_out = _out.length() * _in;
|
||||
break;
|
||||
|
||||
case HC_SMOOTH:
|
||||
_out = _in;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::set_name
|
||||
// Access: Public
|
||||
// Description: Sets the name associated with the CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurveCV::
|
||||
set_name(const char *name) {
|
||||
if (_name != NULL) {
|
||||
delete [] _name;
|
||||
_name = NULL;
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
_name = new char[strlen(name)+1];
|
||||
strcpy(_name, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurveCV::Output
|
||||
// Access: Public
|
||||
// Description: Formats the CV for output to an egg file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurveCV::
|
||||
Output(ostream &out, int indent, int num_dimensions,
|
||||
bool show_in, bool show_out,
|
||||
double scale_in, double scale_out) const {
|
||||
if (show_in) {
|
||||
Indent(out, indent) << "<Vertex> {\n";
|
||||
show_vec3(out, indent+2, _p - scale_in * _in / 3.0,
|
||||
num_dimensions) << "\n";
|
||||
Indent(out, indent) << "}\n";
|
||||
}
|
||||
|
||||
Indent(out, indent) << "<Vertex> {\n";
|
||||
show_vec3(out, indent+2, _p, num_dimensions) << "\n";
|
||||
|
||||
Indent(out, indent+2) << "<Char*> continuity-type { ";
|
||||
switch (_type) {
|
||||
case HC_CUT:
|
||||
out << "Cut";
|
||||
break;
|
||||
|
||||
case HC_FREE:
|
||||
out << "Free";
|
||||
break;
|
||||
|
||||
case HC_G1:
|
||||
out << "G1";
|
||||
break;
|
||||
|
||||
case HC_SMOOTH:
|
||||
out << "Smooth";
|
||||
break;
|
||||
};
|
||||
out << " }\n";
|
||||
|
||||
Indent(out, indent) << "}\n";
|
||||
|
||||
if (show_out) {
|
||||
Indent(out, indent) << "<Vertex> {\n";
|
||||
show_vec3(out, indent+2, _p + scale_out * _out / 3.0,
|
||||
num_dimensions) << "\n";
|
||||
Indent(out, indent) << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::Constructor
|
||||
// Access: Public, Scheme
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurve::
|
||||
HermiteCurve() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::Constructor
|
||||
// Access: Public, Scheme
|
||||
// Description: Constructs a Hermite from the indicated (possibly
|
||||
// non-hermite) curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurve::
|
||||
HermiteCurve(const ParametricCurve &nc) {
|
||||
if (!nc.convert_to_hermite(*this)) {
|
||||
parametrics_cat->warning()
|
||||
<< "Cannot make a Hermite from the indicated curve."
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_num_cvs
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the number of CV's in the curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int HermiteCurve::
|
||||
get_num_cvs() const {
|
||||
return _points.size();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::insert_cv
|
||||
// Access: Public, Scheme
|
||||
// Description: Inserts a new CV at the given parametric point along
|
||||
// the curve. If this parametric point is already on
|
||||
// the curve, the CV is assigned an index between its
|
||||
// two neighbors and the indices of all following CV's
|
||||
// are incremented by 1; its in and out tangents are
|
||||
// chosen to keep the curve consistent. If the new
|
||||
// parametric point is beyond the end of the existing
|
||||
// curve, the curve is extended to meet it and the new
|
||||
// CV's position, in tangent, and out tangent are set to
|
||||
// zero.
|
||||
//
|
||||
// The index number of the new CV is returned.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int HermiteCurve::
|
||||
insert_cv(double t) {
|
||||
if (!is_valid() || t >= get_max_t()) {
|
||||
int n = append_cv(HC_SMOOTH, 0.0, 0.0, 0.0);
|
||||
set_cv_tstart(n, t);
|
||||
return n;
|
||||
}
|
||||
|
||||
t = min(max(t, 0.0), get_max_t());
|
||||
|
||||
int n = find_cv(t);
|
||||
nassertr(n+1<get_num_cvs(), 0);
|
||||
|
||||
HermiteCurveCV cv;
|
||||
LVector3f tan;
|
||||
cv._type = HC_SMOOTH;
|
||||
get_pt(t, cv._p, tan);
|
||||
cv._out = cv._in = tan / 2.0;
|
||||
|
||||
_points.insert(_points.begin() + n + 1, cv);
|
||||
bool result =
|
||||
insert_curveseg(n, new CubicCurveseg, t - get_cv_tstart(n));
|
||||
nassertr(result, 0);
|
||||
|
||||
recompute_basis();
|
||||
invalidate_all();
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::append_cv
|
||||
// Access: Public, Scheme
|
||||
// Description: Adds a new CV to the end of the curve. The new CV is
|
||||
// given initial in/out tangents of 0. The return value
|
||||
// is the index of the new CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int HermiteCurve::
|
||||
append_cv(int type, float x, float y, float z) {
|
||||
HermiteCurveCV cv;
|
||||
cv.set_type(type);
|
||||
cv.set_point(LVector3f(x, y, z));
|
||||
cv.set_in(zero);
|
||||
cv.set_out(zero);
|
||||
_points.push_back(cv);
|
||||
if (_points.size()>1) {
|
||||
bool result =
|
||||
insert_curveseg(_segs.size(), new CubicCurveseg, 1.0);
|
||||
nassertr(result, 0);
|
||||
}
|
||||
|
||||
recompute_basis();
|
||||
invalidate_all();
|
||||
|
||||
return _points.size()-1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::remove_cv
|
||||
// Access: Public, Scheme
|
||||
// Description: Removes the given CV from the curve. Returns true if
|
||||
// the CV existed, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
remove_cv(int n) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_points.erase(_points.begin() + n);
|
||||
if (_segs.size()>0) {
|
||||
remove_curveseg(_segs.size()-1);
|
||||
}
|
||||
|
||||
recompute_basis();
|
||||
invalidate_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::remove_all_cvs
|
||||
// Access: Public, Scheme
|
||||
// Description: Removes all CV's from the curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
remove_all_cvs() {
|
||||
_points.erase(_points.begin(), _points.end());
|
||||
remove_all_curvesegs();
|
||||
|
||||
invalidate_all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_type
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the given CV's continuity type. Legal values
|
||||
// are HC_CUT, HC_FREE, HC_G1, or HC_SMOOTH.
|
||||
//
|
||||
// Other than HC_CUT, these have no effect on the actual
|
||||
// curve; it remains up to user software to impose the
|
||||
// constraints these imply.
|
||||
//
|
||||
// HC_CUT implies a disconnection of the curve; HC_FREE
|
||||
// imposes no constraints on the tangents; HC_G1
|
||||
// forces the tangents to be collinear, and HC_SMOOTH
|
||||
// forces the tangents to be identical. Setting type
|
||||
// type to HC_G1 or HC_SMOOTH may adjust the out
|
||||
// tangent to match the in tangent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_type(int n, int type) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed_cut = false;
|
||||
|
||||
if (type!=_points[n]._type) {
|
||||
changed_cut = (type==HC_CUT || _points[n]._type==HC_CUT);
|
||||
_points[n].set_type(type);
|
||||
}
|
||||
|
||||
invalidate_cv(n, changed_cut);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_point
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the given CV's position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_point(int n, float x, float y, float z) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
_points[n].set_point(LVector3f(x, y, z));
|
||||
invalidate_cv(n, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_in
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the given CV's in tangent. Depending on the
|
||||
// continuity type, this may also adjust the out
|
||||
// tangent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_in(int n, float x, float y, float z) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
_points[n].set_in(LVector3f(x, y, z));
|
||||
invalidate_cv(n, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_out
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the given CV's out tangent. Depending on the
|
||||
// continuity type, this may also adjust the in
|
||||
// tangent.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_out(int n, float x, float y, float z) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
_points[n].set_out(LVector3f(x, y, z));
|
||||
invalidate_cv(n, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_tstart
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the given CV's parametric starting time.
|
||||
// This may affect the shape of the curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_tstart(int n, double tstart) {
|
||||
if (n<=0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
if (fabs(tstart - get_cv_tstart(n)) > 0.0001) {
|
||||
set_tlength(n-1, tstart - get_tstart(n-1));
|
||||
recompute_basis();
|
||||
invalidate_all();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::set_cv_name
|
||||
// Access: Public, Scheme
|
||||
// Description: Changes the name associated with a particular CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
set_cv_name(int n, const char *name) {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return false;
|
||||
}
|
||||
_points[n].set_name(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_type
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the given CV's continuity type, HC_CUT,
|
||||
// HC_FREE, HC_G1, or HC_SMOOTH, or 0 if there is
|
||||
// no such CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int HermiteCurve::
|
||||
get_cv_type(int n) const {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _points[n]._type;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_point
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the position of the given CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const LVector3f &HermiteCurve::
|
||||
get_cv_point(int n) const {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return zero;
|
||||
}
|
||||
|
||||
return _points[n]._p;
|
||||
}
|
||||
void HermiteCurve::
|
||||
get_cv_point(int n, LVector3f &v) const {
|
||||
v = get_cv_point(n);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_in
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the in tangent of the given CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const LVector3f &HermiteCurve::
|
||||
get_cv_in(int n) const {
|
||||
if (n<0 || n>=_points.size() || _points[n-1]._type==HC_CUT) {
|
||||
return zero;
|
||||
}
|
||||
|
||||
return _points[n]._in;
|
||||
}
|
||||
void HermiteCurve::
|
||||
get_cv_in(int n, LVector3f &v) const {
|
||||
v = get_cv_in(n);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_out
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the out tangent of the given CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const LVector3f &HermiteCurve::
|
||||
get_cv_out(int n) const {
|
||||
if (n<0 || n>=_points.size() || _points[n]._type==HC_CUT) {
|
||||
return zero;
|
||||
}
|
||||
|
||||
return _points[n]._out;
|
||||
}
|
||||
void HermiteCurve::
|
||||
get_cv_out(int n, LVector3f &v) const {
|
||||
v = get_cv_out(n);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_tstart
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the starting point in parametric space of the
|
||||
// given CV.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
double HermiteCurve::
|
||||
get_cv_tstart(int n) const {
|
||||
if (n<0) {
|
||||
return 0.0;
|
||||
} else if (n>=_points.size()) {
|
||||
return get_max_t();
|
||||
}
|
||||
|
||||
return get_tstart(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::get_cv_name
|
||||
// Access: Public, Scheme
|
||||
// Description: Returns the name of the given CV, or NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const char *HermiteCurve::
|
||||
get_cv_name(int n) const {
|
||||
if (n<0 || n>=_points.size()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _points[n]._name;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::Print
|
||||
// Access: Public, Scheme
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
Print() const {
|
||||
ostream& out = parametrics_cat->info();
|
||||
|
||||
switch (get_curve_type()) {
|
||||
case PCT_T:
|
||||
out << "Time-warping ";
|
||||
break;
|
||||
|
||||
case PCT_XYZ:
|
||||
out << "XYZ ";
|
||||
break;
|
||||
|
||||
case PCT_HPR:
|
||||
out << "HPR ";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out
|
||||
<< "HermiteCurve, " << get_num_cvs() << " CV's. t ranges from 0 to "
|
||||
<< get_max_t()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::print_cv
|
||||
// Access: Public, Scheme
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
print_cv(int n) const {
|
||||
ostream& out = parametrics_cat->info();
|
||||
out << "CV";
|
||||
if (get_cv_name(n)!=NULL) {
|
||||
out << " " << get_cv_name(n);
|
||||
}
|
||||
|
||||
out << " at t = " << get_cv_tstart(n)
|
||||
<< "\npoint = " << get_cv_point(n)
|
||||
<< "\nin = " << get_cv_in(n) << " out = " << get_cv_out(n)
|
||||
<< "\ncontinuity type = ";
|
||||
|
||||
switch (get_cv_type(n)) {
|
||||
case HC_CUT:
|
||||
out << "Cut";
|
||||
break;
|
||||
|
||||
case HC_FREE:
|
||||
out << "Free";
|
||||
break;
|
||||
|
||||
case HC_G1:
|
||||
out << "G1";
|
||||
break;
|
||||
|
||||
case HC_SMOOTH:
|
||||
out << "Smooth";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out << "\n" << endl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::write_egg
|
||||
// Access: Public, Scheme
|
||||
// Description: Writes an egg description of the hermite 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 HermiteCurve::
|
||||
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: HermiteCurve::write_egg
|
||||
// Access: Public, Scheme
|
||||
// Description: Writes an egg description of the hermite curve to the
|
||||
// specified output stream. Returns true if the file is
|
||||
// successfully written.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HermiteCurve::
|
||||
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: HermiteCurve::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 HermiteCurve::
|
||||
rebuild_curveseg(int, double, const LVector4f &,
|
||||
int, double, const LVector4f &,
|
||||
int, double, const LVector4f &,
|
||||
int, double, const LVector4f &) {
|
||||
cerr << "rebuild_curveseg not implemented for this curve type.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::Output
|
||||
// Access: Public
|
||||
// Description: Formats the Hermite curve for output to an Egg file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
Output(ostream &out, int indent) const {
|
||||
Indent(out, indent)
|
||||
<< "<VertexPool> " << get_name() << ".pool {\n";
|
||||
|
||||
int i;
|
||||
for (i = 0; i<_points.size(); i++) {
|
||||
bool show_in = (i!=0);
|
||||
bool show_out = (i!=_points.size()-1);
|
||||
_points[i].Output(out, indent+2, _num_dimensions,
|
||||
show_in, show_out,
|
||||
show_in ? get_tlength(i-1) : 0.0,
|
||||
show_out ? get_tlength(i) : 0.0);
|
||||
}
|
||||
Indent(out, indent) << "}\n";
|
||||
|
||||
Indent(out, indent) << "<BezierCurve> " << 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) << "<TLengths> {";
|
||||
if (_points.size() > 1) {
|
||||
for (i = 0; i<_segs.size(); i++) {
|
||||
if (i%10 == 1) {
|
||||
out << "\n";
|
||||
Indent(out, indent+3);
|
||||
}
|
||||
out << " " << get_tlength(i);
|
||||
}
|
||||
}
|
||||
out << "\n";
|
||||
Indent(out, indent+2) << "}\n";
|
||||
|
||||
Indent(out, indent+2) << "<VertexRef> {";
|
||||
for (i = 1; i<=_points.size() * 3 - 2; i++) {
|
||||
if (i%10 == 1) {
|
||||
out << "\n";
|
||||
Indent(out, indent+3);
|
||||
}
|
||||
out << " " << i;
|
||||
}
|
||||
out << "\n";
|
||||
Indent(out, indent+4) << "<Ref> { " << get_name() << ".pool }\n";
|
||||
Indent(out, indent+2) << "}\n";
|
||||
|
||||
Indent(out, indent) << "}\n";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HermiteCurve::
|
||||
~HermiteCurve() {
|
||||
}
|
||||
|
||||
static void
|
||||
wrap_hpr(const LVector3f &hpr1, LVector3f &hpr2) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
while ((hpr2[i] - hpr1[i]) > 180.0) {
|
||||
hpr2[i] -= 360.0;
|
||||
}
|
||||
|
||||
while ((hpr2[i] - hpr1[i]) < -180.0) {
|
||||
hpr2[i] += 360.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::invalidate_cv
|
||||
// Access: Protected
|
||||
// Description: Recomputes the CV and its neighbors appropriately
|
||||
// after a change.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
invalidate_cv(int n, bool redo_all) {
|
||||
double t1 = 0.0, t2 = get_max_t();
|
||||
if (n>0 && _points[n-1]._type!=HC_CUT) {
|
||||
const HermiteCurveCV &p1 = _points[n-1];
|
||||
HermiteCurveCV p2(_points[n]);
|
||||
if (_curve_type == PCT_HPR) {
|
||||
wrap_hpr(p1._p, p2._p);
|
||||
}
|
||||
get_curveseg(n-1)->hermite_basis(p1, p2, get_tlength(n-1));
|
||||
t1 = get_cv_tstart(n-1);
|
||||
}
|
||||
|
||||
if (n+1 < _points.size()) {
|
||||
if (_points[n]._type==HC_CUT) {
|
||||
BezierSeg seg;
|
||||
seg._v[0] = seg._v[1] = seg._v[2] = seg._v[3] = _points[n]._p;
|
||||
get_curveseg(n)->bezier_basis(seg);
|
||||
} else {
|
||||
const HermiteCurveCV &p1 = _points[n];
|
||||
HermiteCurveCV p2(_points[n+1]);
|
||||
if (_curve_type == PCT_HPR) {
|
||||
wrap_hpr(p1._p, p2._p);
|
||||
}
|
||||
get_curveseg(n)->hermite_basis(p1, p2, get_tlength(n));
|
||||
t2 = get_cv_tstart(n+2);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid()) {
|
||||
if (redo_all) {
|
||||
invalidate_all();
|
||||
} else {
|
||||
invalidate(t1, t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::find_cv
|
||||
// Access: Protected
|
||||
// Description: Finds the CV immediately preceding the given value of
|
||||
// t.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int HermiteCurve::
|
||||
find_cv(double t) {
|
||||
nassertr(is_valid(), 0);
|
||||
|
||||
int n;
|
||||
for (n = 0; n<_segs.size(); n++) {
|
||||
if (_segs[n]._tend+0.00001 > t) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HermiteCurve::recompute_basis
|
||||
// Access: Protected
|
||||
// Description: Recomputes the coefficients for all the CV's in the
|
||||
// curve. This is intended to be called whenever the
|
||||
// CV's have been changed in some drastic way, and it's
|
||||
// safest just to recompute everything.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HermiteCurve::
|
||||
recompute_basis() {
|
||||
int n;
|
||||
for (n = 0; n<_segs.size(); n++) {
|
||||
if (_points[n]._type==HC_CUT) {
|
||||
BezierSeg seg;
|
||||
seg._v[0] = seg._v[1] = seg._v[2] = seg._v[3] = _points[n]._p;
|
||||
get_curveseg(n)->bezier_basis(seg);
|
||||
} else {
|
||||
const HermiteCurveCV &p1 = _points[n];
|
||||
HermiteCurveCV p2(_points[n+1]);
|
||||
if (_curve_type == PCT_HPR) {
|
||||
wrap_hpr(p1._p, p2._p);
|
||||
}
|
||||
get_curveseg(n)->hermite_basis(p1, p2, get_tlength(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
// Filename: hermiteCurve.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 HERMITECURVE_H
|
||||
#define HERMITECURVE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "curve.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Defines
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BEGIN_PUBLISH //[
|
||||
// Hermite curve continuity types.
|
||||
#define HC_CUT 1
|
||||
// The curve is disconnected at this point. All points between
|
||||
// this and the following CV are not part of the curve.
|
||||
|
||||
#define HC_FREE 2
|
||||
// Tangents are unconstrained. The curve is continuous, but its first
|
||||
// derivative is not. This is G0 geometric continuity.
|
||||
|
||||
#define HC_G1 3
|
||||
// Tangents are constrained to be collinear. The curve's derivative
|
||||
// is not continuous in parametric space, but its geometric slope is.
|
||||
// The distinction is mainly relevant in the context of animation
|
||||
// along the curve--when crossing the join point, direction of motion
|
||||
// will change continuously, but the speed of motion may change
|
||||
// suddenly. This is G1 geometric continuity.
|
||||
|
||||
#define HC_SMOOTH 4
|
||||
// Tangents are constrained to be identical. The curve and its first
|
||||
// derivative are continuous in parametric space. When animating
|
||||
// motion across the join point, speed and direction of motion will
|
||||
// change continuously. This is C1 parametric continuity.
|
||||
END_PUBLISH //]
|
||||
|
||||
class NurbsCurve;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : HermiteCurveCV
|
||||
// Description : A single CV of a Hermite curve. Hermite curve CV's
|
||||
// include an in and out tangent, as well as a position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class HermiteCurveCV {
|
||||
public:
|
||||
HermiteCurveCV();
|
||||
HermiteCurveCV(const HermiteCurveCV &c);
|
||||
~HermiteCurveCV();
|
||||
|
||||
void set_point(const LVector3f &point) { _p = point; }
|
||||
void set_in(const LVector3f &in);
|
||||
void set_out(const LVector3f &out);
|
||||
void set_type(int type);
|
||||
void set_name(const char *name);
|
||||
|
||||
void Output(ostream &out, int indent, int num_dimensions,
|
||||
bool show_in, bool show_out,
|
||||
double scale_in, double scale_out) const;
|
||||
|
||||
LVector3f _p, _in, _out;
|
||||
int _type;
|
||||
char *_name;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : HermiteCurve
|
||||
// Description : A parametric curve defined by a sequence of control
|
||||
// vertices, each with an in and out tangent.
|
||||
//
|
||||
// This class is actually implemented as a
|
||||
// PiecewiseCurve made up of several CubicCurvesegs,
|
||||
// each of which is created using the hermite_basis()
|
||||
// method. The HermiteCurve class itself keeps its own
|
||||
// list of the CV's that are used to define the curve
|
||||
// (since the CubicCurveseg class doesn't retain these).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class HermiteCurve : public PiecewiseCurve {
|
||||
PUBLISHED:
|
||||
HermiteCurve();
|
||||
HermiteCurve(const ParametricCurve &pc);
|
||||
|
||||
int get_num_cvs() const;
|
||||
|
||||
int insert_cv(double t);
|
||||
int append_cv(int type, float x, float y, float z);
|
||||
inline int append_cv(int type, const LVector3f &v) {
|
||||
return append_cv(type, v[0], v[1], v[2]);
|
||||
}
|
||||
|
||||
bool remove_cv(int n);
|
||||
void remove_all_cvs();
|
||||
|
||||
bool set_cv_type(int n, int type);
|
||||
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]);
|
||||
}
|
||||
bool set_cv_in(int n, float x, float y, float z);
|
||||
inline bool set_cv_in(int n, const LVector3f &v) {
|
||||
return set_cv_in(n, v[0], v[1], v[2]);
|
||||
}
|
||||
bool set_cv_out(int n, float x, float y, float z);
|
||||
inline bool set_cv_out(int n, const LVector3f &v) {
|
||||
return set_cv_out(n, v[0], v[1], v[2]);
|
||||
}
|
||||
bool set_cv_tstart(int n, double tstart);
|
||||
bool set_cv_name(int n, const char *name);
|
||||
|
||||
|
||||
int get_cv_type(int n) const;
|
||||
const LVector3f &get_cv_point(int n) const;
|
||||
void get_cv_point(int n, LVector3f &v) const;
|
||||
const LVector3f &get_cv_in(int n) const;
|
||||
void get_cv_in(int n, LVector3f &v) const;
|
||||
const LVector3f &get_cv_out(int n) const;
|
||||
void get_cv_out(int n, LVector3f &v) const;
|
||||
double get_cv_tstart(int n) const;
|
||||
const char *get_cv_name(int n) const;
|
||||
|
||||
void Print() const;
|
||||
void print_cv(int n) const;
|
||||
|
||||
bool write_egg(const char *filename);
|
||||
bool write_egg(ostream &out, const char *basename);
|
||||
|
||||
public:
|
||||
|
||||
CubicCurveseg *get_curveseg(int ti) {
|
||||
return (CubicCurveseg *)PiecewiseCurve::get_curveseg(ti);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
void Output(ostream &out, int indent=0) const;
|
||||
|
||||
virtual ~HermiteCurve();////
|
||||
protected:
|
||||
|
||||
void invalidate_cv(int n, bool redo_all);
|
||||
int find_cv(double t);
|
||||
void recompute_basis();
|
||||
|
||||
vector<HermiteCurveCV> _points;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
register_type(_type_handle, "HermiteCurve");
|
||||
}
|
||||
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
|
||||
Loading…
Reference in New Issue