00001 // Filename: nurbsCurveResult.cxx 00002 // Created by: drose (04Dec02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "nurbsCurveResult.h" 00020 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: NurbsCurveResult::Constructor 00024 // Access: Public 00025 // Description: The constructor automatically builds up the result as 00026 // the product of the indicated set of basis matrices 00027 // and the indicated table of control vertex positions. 00028 //////////////////////////////////////////////////////////////////// 00029 NurbsCurveResult:: 00030 NurbsCurveResult(const NurbsMatrixVector &basis, int order, 00031 const LVecBase4f verts[], int num_vertices) { 00032 _last_segment = -1; 00033 00034 int num_segments = basis.get_num_segments(); 00035 for (int i = 0; i < num_segments; i++) { 00036 int vi = basis.get_vertex_index(i); 00037 nassertv(vi >= 0 && vi < num_vertices); 00038 00039 // Create a matrix from our (up to) four involved vertices. 00040 LMatrix4f geom; 00041 int ci = 0; 00042 while (ci < order) { 00043 geom.set_row(ci, verts[vi + ci]); 00044 ci++; 00045 } 00046 while (ci < 4) { 00047 geom.set_row(ci, LVecBase4f::zero()); 00048 ci++; 00049 } 00050 00051 // And compose this matrix with the segment to produce a new 00052 // matrix. 00053 _prod.compose_segment(basis, i, geom); 00054 } 00055 } 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: NurbsCurveResult::eval_segment_point 00059 // Access: Published 00060 // Description: Evaluates the point on the curve corresponding to the 00061 // indicated value in parametric time within the 00062 // indicated curve segment. t should be in the range 00063 // [0, 1]. 00064 // 00065 // The curve is internally represented as a number of 00066 // connected (or possibly unconnected) piecewise 00067 // continuous segments. The exact number of segments 00068 // for a particular curve depends on the knot vector, 00069 // and is returned by get_num_segments(). Normally, 00070 // eval_point() is used to evaluate a point along the 00071 // continuous curve, but when you care more about local 00072 // continuity, you can use eval_segment_point() to 00073 // evaluate the points along each segment. 00074 //////////////////////////////////////////////////////////////////// 00075 void NurbsCurveResult:: 00076 eval_segment_point(int segment, float t, LVecBase3f &point) const { 00077 const LMatrix4f &mat = _prod.get_matrix(segment); 00078 00079 float t2 = t*t; 00080 LVecBase4f tvec(t*t2, t2, t, 1.0f); 00081 LVecBase4f r = tvec * mat; 00082 point.set(r[0] / r[3], r[1] / r[3], r[2] / r[3]); 00083 } 00084 00085 //////////////////////////////////////////////////////////////////// 00086 // Function: NurbsCurveResult::eval_segment_tangent 00087 // Access: Published 00088 // Description: As eval_segment_point, but computes the tangent to 00089 // the curve at the indicated point. The tangent vector 00090 // will not necessarily be normalized, and could be 00091 // zero, particularly at the endpoints. 00092 //////////////////////////////////////////////////////////////////// 00093 void NurbsCurveResult:: 00094 eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const { 00095 const LMatrix4f &mat = _prod.get_matrix(segment); 00096 00097 float t2 = t*t; 00098 LVecBase4f tvec(t2, t, 1.0f, 0.0f); 00099 LVecBase4f r = tvec * mat; 00100 tangent.set(r[0], r[1], r[2]); 00101 } 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: NurbsCurveResult::find_segment 00105 // Access: Private 00106 // Description: Returns the index of the segment that contains the 00107 // indicated value of t, or -1 if no segment contains 00108 // this value. 00109 //////////////////////////////////////////////////////////////////// 00110 int NurbsCurveResult:: 00111 find_segment(float t) { 00112 // Trivially check the endpoints of the curve. 00113 if (t >= get_end_t()) { 00114 return _prod.get_num_segments() - 1; 00115 } else if (t <= get_start_t()) { 00116 return 0; 00117 } 00118 00119 // Check the last segment we searched for. Often, two consecutive 00120 // requests are for the same segment. 00121 if (_last_segment != -1 && (t >= _last_from && t < _last_to)) { 00122 return _last_segment; 00123 } 00124 00125 // Look for the segment the hard way. 00126 int segment = r_find_segment(t, 0, _prod.get_num_segments() - 1); 00127 if (segment != -1) { 00128 _last_segment = segment; 00129 _last_from = _prod.get_from(segment); 00130 _last_to = _prod.get_to(segment); 00131 } 00132 return segment; 00133 } 00134 00135 //////////////////////////////////////////////////////////////////// 00136 // Function: NurbsCurveResult::r_find_segment 00137 // Access: Private 00138 // Description: Recursively searches for the segment that contains 00139 // the indicated value of t by performing a binary 00140 // search. This assumes the segments are stored in 00141 // increasing order of t, and they don't overlap. 00142 //////////////////////////////////////////////////////////////////// 00143 int NurbsCurveResult:: 00144 r_find_segment(float t, int top, int bot) const { 00145 if (bot < top) { 00146 // Not found. 00147 return -1; 00148 } 00149 int mid = (top + bot) / 2; 00150 nassertr(mid >= 0 && mid < _prod.get_num_segments(), -1); 00151 00152 float from = _prod.get_from(mid); 00153 float to = _prod.get_to(mid); 00154 if (from > t) { 00155 // Too high, try lower. 00156 return r_find_segment(t, top, mid - 1); 00157 00158 } else if (to <= t) { 00159 // Too low, try higher. 00160 return r_find_segment(t, mid + 1, bot); 00161 00162 } else { 00163 // Here we are! 00164 return mid; 00165 } 00166 }