Selaa lähdekoodia

Mark requested curve fitting

Dave Schuyler 25 vuotta sitten
vanhempi
sitoutus
3f8e49bd1e

+ 460 - 0
panda/src/parametrics/curveFitter.cxx

@@ -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";
+  }
+}
+

+ 101 - 0
panda/src/parametrics/curveFitter.h

@@ -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

+ 987 - 0
panda/src/parametrics/hermiteCurve.cxx

@@ -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));
+    }
+  }
+}
+

+ 182 - 0
panda/src/parametrics/hermiteCurve.h

@@ -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