contrib/gel/vsol/vsol_digital_curve_3d.cxx
Go to the documentation of this file.
00001 // This is gel/vsol/vsol_digital_curve_3d.cxx
00002 #include "vsol_digital_curve_3d.h"
00003 //:
00004 // \file
00005 
00006 #include <vsol/vsol_point_3d.h>
00007 #include <vcl_iostream.h>
00008 #include <vgl/vgl_point_3d.h>
00009 #include <vgl/vgl_vector_3d.h>
00010 #include <vgl/vgl_distance.h>
00011 #include <vsl/vsl_vector_io.h>
00012 #include <vcl_cmath.h>
00013 #include <vcl_cassert.h>
00014 
00015 // Copy constructor
00016 vsol_digital_curve_3d::vsol_digital_curve_3d(const vsol_digital_curve_3d &other)
00017   : vsol_curve_3d(other), samples_()
00018 {
00019   for (vcl_vector<vsol_point_3d_sptr>::const_iterator itr=other.samples_.begin();
00020        itr != other.samples_.end();  ++itr)
00021     this->samples_.push_back(new vsol_point_3d(**itr));
00022 }
00023 
00024 //: Clone `this': creation of a new object and initialization
00025 // See Prototype pattern
00026 vsol_spatial_object_3d* vsol_digital_curve_3d::clone(void) const
00027 {
00028   return new vsol_digital_curve_3d(*this);
00029 }
00030 
00031 //: Return the first point of `this'
00032 vsol_point_3d_sptr vsol_digital_curve_3d::p0(void) const
00033 {
00034   if (samples_.empty())
00035     return NULL;
00036   else
00037     return samples_.front();
00038 }
00039 
00040 //: Return the last point of `this'
00041 vsol_point_3d_sptr vsol_digital_curve_3d::p1(void) const
00042 {
00043   if (samples_.empty())
00044     return NULL;
00045   else
00046     return samples_.back();
00047 }
00048 
00049 //: Return point `i'
00050 //  REQUIRE: valid_index(i)
00051 vsol_point_3d_sptr vsol_digital_curve_3d::point(unsigned int i) const
00052 {
00053   assert(valid_index(i));
00054   return samples_[i];
00055 }
00056 
00057 //: Interpolate a point on the curve given a floating point index
00058 //  Linear interpolation is used for now
00059 vgl_point_3d<double>
00060 vsol_digital_curve_3d::interp(double index) const
00061 {
00062   assert(index >= 0.0);
00063   assert(index <= double(samples_.size()-1));
00064 
00065   int i1 = (int)vcl_floor(index);
00066   if ( vcl_floor(index) == index )
00067     return samples_[i1]->get_p();
00068 
00069   int i2 = (int)vcl_ceil(index);
00070   double f = index - vcl_floor(index);
00071 
00072   vgl_point_3d<double> p1 = samples_[i1]->get_p();
00073   vgl_point_3d<double> p2 = samples_[i2]->get_p();
00074   return p1 + f*(p2-p1);
00075 }
00076 
00077 //: Has `this' the same points than `other' and in the same order ?
00078 bool vsol_digital_curve_3d::operator==(vsol_digital_curve_3d const& other) const
00079 {
00080   if (this==&other)
00081     return true;
00082   //check endpoint equality since that is cheaper then checking each vertex
00083   //and if it fails we are done
00084   bool epts_eq = vsol_curve_3d::endpoints_equal(other);
00085   if (!epts_eq)
00086     return false;
00087   //Do the polylines have the same number of vertices?
00088   if (samples_.size()!=other.samples_.size())
00089     return false;
00090   //The easy tests are done.  Now compare each vertex
00091   int n = samples_.size();
00092   for (int i=0; i<n; i++)
00093     if (*(samples_[i])!=*(other.samples_[i]))
00094       return false;
00095   return true;
00096 }
00097 
00098 //: spatial object equality
00099 bool vsol_digital_curve_3d::operator==(vsol_spatial_object_3d const& obj) const
00100 {
00101   return
00102     obj.cast_to_curve() && obj.cast_to_curve()->cast_to_digital_curve() &&
00103     *this == *obj.cast_to_curve()->cast_to_digital_curve();
00104 }
00105 
00106 //: Return the length of `this'
00107 double vsol_digital_curve_3d::length(void) const
00108 {
00109   double curve_length = 0.0;
00110   for ( vcl_vector<vsol_point_3d_sptr>::const_iterator itr=samples_.begin();
00111         itr+1 != samples_.end();  ++itr )
00112   {
00113     curve_length += ((*(itr+1))->get_p() - (*itr)->get_p()).length();
00114   }
00115   return curve_length;
00116 }
00117 
00118 //: Compute the bounding box of `this'
00119 void vsol_digital_curve_3d::compute_bounding_box(void) const
00120 {
00121   // valid under linear interpolation
00122   set_bounding_box(samples_[0]->x(), samples_[0]->y(), samples_[0]->z());
00123   for (unsigned int i=1; i<samples_.size(); ++i)
00124     add_to_bounding_box(samples_[i]->x(), samples_[i]->y(), samples_[i]->z());
00125 }
00126 
00127 //: Set the first point of the curve
00128 // Require: in(new_p0)
00129 void vsol_digital_curve_3d::set_p0(vsol_point_3d_sptr const& new_p0)
00130 {
00131   samples_.front() = new_p0;
00132 }
00133 
00134 //: Set the last point of the curve
00135 // Require: in(new_p1)
00136 void vsol_digital_curve_3d::set_p1(vsol_point_3d_sptr const& new_p1)
00137 {
00138   samples_.back() = new_p1;
00139 }
00140 
00141 //: Add another point to the curve
00142 void vsol_digital_curve_3d::add_vertex(vsol_point_3d_sptr const& new_p)
00143 {
00144   samples_.push_back(new_p);
00145 }
00146 
00147 // ================   Binary I/O Methods ========================
00148 
00149 //: Binary save self to stream.
00150 void vsol_digital_curve_3d::b_write(vsl_b_ostream &os) const
00151 {
00152   vsl_b_write(os, version());
00153   vsl_b_write(os, samples_);
00154 }
00155 
00156 
00157 //: Binary load self from stream
00158 void vsol_digital_curve_3d::b_read(vsl_b_istream &is)
00159 {
00160   if (!is)
00161     return;
00162 
00163   short ver;
00164   vsl_b_read(is, ver);
00165   switch (ver)
00166   {
00167    default:
00168     assert(!"vsol_digital_curve_3d I/O version should be 1");
00169    case 1:
00170     vsl_b_read(is, samples_);
00171   }
00172 }
00173 
00174 
00175 //: Return IO version number;
00176 short vsol_digital_curve_3d::version() const
00177 {
00178   return 1;
00179 }
00180 
00181 //: Print an ascii summary to the stream
00182 void vsol_digital_curve_3d::print_summary(vcl_ostream &os) const
00183 {
00184   os << *this;
00185 }
00186 
00187 
00188 //----------------------------------------------------------------
00189 // ================  External Methods ========================
00190 //----------------------------------------------------------------
00191 
00192 
00193 //: Binary save vsol_digital_curve_3d to stream.
00194 void
00195 vsl_b_write(vsl_b_ostream &os, vsol_digital_curve_3d const* p)
00196 {
00197   if (p==0) {
00198     vsl_b_write(os, false); // Indicate null pointer stored
00199   }
00200   else {
00201     vsl_b_write(os,true); // Indicate non-null pointer stored
00202     p->b_write(os);
00203   }
00204 }
00205 
00206 
00207 //: Binary load vsol_digital_curve_3d from stream.
00208 void
00209 vsl_b_read(vsl_b_istream &is, vsol_digital_curve_3d* &p)
00210 {
00211   delete p;
00212   bool not_null_ptr;
00213   vsl_b_read(is, not_null_ptr);
00214   if (not_null_ptr) {
00215     p = new vsol_digital_curve_3d();
00216     p->b_read(is);
00217   }
00218   else
00219     p = 0;
00220 }
00221 
00222 void vsol_digital_curve_3d::describe(vcl_ostream &strm, int blanking) const
00223 {
00224   if (blanking < 0) blanking = 0; while (blanking--) strm << ' ';
00225   strm << "[vsol_digital_curve_3d";
00226   for (unsigned int i=0; i<size(); ++i)
00227     strm << ' ' << *(point(i));
00228   strm << ']' << vcl_endl;
00229 }
00230 
00231 
00232 //: Return the floating point index of the point on the curve nearest to \p point
00233 double closest_index(vgl_point_3d<double> const& pt,
00234                      vsol_digital_curve_3d_sptr const& curve)
00235 {
00236   int index = 0;
00237   const unsigned int n = curve->size();
00238   double x1=curve->point(0)->x(), y1=curve->point(0)->y(), z1=curve->point(0)->z(),
00239          x2=curve->point(1)->x(), y2=curve->point(1)->y(), z2=curve->point(1)->z();
00240   double d = vgl_distance2_to_linesegment(x1,y1,z1,x2,y2,z2,pt.x(),pt.y(),pt.z());
00241 
00242   // find the closest line segment on the curve
00243   for (unsigned int i=1; i+1<n; ++i)
00244   {
00245     x1=curve->point(i)->x();   y1=curve->point(i)->y();   z1=curve->point(i)->z();
00246     x2=curve->point(i+1)->x(); y2=curve->point(i+1)->y(); z2=curve->point(i+1)->z();
00247 
00248     // skip duplicate points
00249     if (x1 == x2 && y1 == y2 && z1 == z2)
00250       continue;
00251 
00252     double e = vgl_distance2_to_linesegment(x1,y1,z1,x2,y2,z2,pt.x(),pt.y(),pt.z());
00253     if (e < d) { d=e; index = i;}
00254   }
00255 
00256   // find the closest point on the closest line segment
00257   vgl_vector_3d<double> v1 = curve->point(index+1)->get_p() - curve->point(index)->get_p();
00258   vgl_vector_3d<double> v2 = pt - curve->point(index)->get_p();
00259   // project the point onto the line segment
00260   double fraction = dot_product(normalized(v1),v2) / v1.length();
00261   if (fraction < 0.0) fraction = 0.0;
00262   if (fraction > 1.0) fraction = 1.0;
00263 
00264   return (double)index + fraction;
00265 }
00266 
00267 
00268 //: Split the input curve into two pieces at the floating point index
00269 bool split(vsol_digital_curve_3d_sptr const& input,
00270            double index,
00271            vsol_digital_curve_3d_sptr &output1,
00272            vsol_digital_curve_3d_sptr &output2)
00273 {
00274   const unsigned int n = input->size();
00275   if (index <= 0.0 || index >= double(n-1))
00276     return false;
00277 
00278   vcl_vector<vsol_point_3d_sptr> vec1, vec2;
00279   vgl_point_3d<double> break_point = input->interp(index);
00280   vec2.push_back(new vsol_point_3d(break_point));
00281   for (unsigned int i=0; i<n; ++i) {
00282     if ( double(i) < index )
00283       vec1.push_back(input->point(i));
00284     if ( double(i) > index )
00285       vec2.push_back(input->point(i));
00286     // if index == i then ignore this point
00287   }
00288   vec1.push_back(new vsol_point_3d(break_point));
00289 
00290   output1 = new vsol_digital_curve_3d(vec1);
00291   output2 = new vsol_digital_curve_3d(vec2);
00292   return true;
00293 }