1 // This is gel/vdgl/vdgl_interpolator_linear.cxx
2 //:
3 // \file
4 
5 #include <iostream>
6 #include <cmath>
7 #include "vdgl_interpolator_linear.h"
8 #include <vdgl/vdgl_edgel_chain.h>
9 #include <vsol/vsol_point_2d.h>
10 #include "vgl/vgl_point_2d.h"
11 #ifdef _MSC_VER
12 #  include "vcl_msvc_warnings.h"
13 #endif
14 #include "vnl/vnl_numeric_traits.h"
15 #include "vnl/vnl_math.h"
16 #include <cassert>
17 
18 
vdgl_interpolator_linear(const vdgl_edgel_chain_sptr & chain)19 vdgl_interpolator_linear::vdgl_interpolator_linear( const vdgl_edgel_chain_sptr& chain)
20   : vdgl_interpolator( chain)
21 {
22   recompute_all();
23 }
24 
25 vdgl_interpolator_linear::~vdgl_interpolator_linear() = default;
26 
closest_point_on_curve(vsol_point_2d_sptr p)27 vsol_point_2d_sptr vdgl_interpolator_linear::closest_point_on_curve ( vsol_point_2d_sptr p )
28 {
29   double min_distance = -1.0;
30   int index = -1;
31   for ( unsigned int i=0; i< chain_->size(); ++i)
32   {
33     vgl_point_2d<double> curve_point = chain_->edgel(i).get_pt();
34     double d = p->distance ( vsol_point_2d ( curve_point ) );
35     if ( min_distance < 0 || d < min_distance )
36     {
37       index = i;
38       min_distance = d;
39     }
40   }
41   if ( index == -1 )
42     return nullptr;
43   else
44     return new vsol_point_2d ( chain_->edgel(index).get_pt() );
45 }
46 
47 
get_x(const double index)48 double vdgl_interpolator_linear::get_x( const double index)
49 {
50   assert(index >= 0 && index < chain_->size());
51   int a = int(index); // round down
52   double d = index- a;
53 
54   double ae = chain_->edgel(a).get_x();
55   if (d==0) return ae; // exactly at an edgel
56   double be = chain_->edgel(a+1).get_x();
57 
58   return be*d+ae*(1-d);
59 }
60 
61 
get_y(const double index)62 double vdgl_interpolator_linear::get_y( const double index)
63 {
64   assert(index >= 0 && index < chain_->size());
65   int a = int(index); // round down
66   double d = index- a;
67 
68   double ae = chain_->edgel(a).get_y();
69   if (d==0) return ae; // exactly at an edgel
70   double be = chain_->edgel(a+1).get_y();
71 
72   return be*d+ae*(1-d);
73 }
74 
75 //: linearly interpolate the gradient magnitude
76 //
get_grad(const double index)77 double vdgl_interpolator_linear::get_grad( const double index)
78 {
79   assert(index >= 0 && index < chain_->size());
80   int a = int(index); // round down
81   double d = index-a;
82 
83   double ae = chain_->edgel(a).get_grad();
84   if (d==0) return ae; // exactly at an edgel
85   double be = chain_->edgel(a+1).get_grad();
86 
87   return be*d+ae*(1-d);
88 }
89 
90 //: linearly interpolate the gradient direction
91 //
get_theta(const double index)92 double vdgl_interpolator_linear::get_theta( const double index)
93 {
94   assert(index >= 0 && index < chain_->size());
95   int a = int(index); // round down
96   double d = index-a;
97 
98   double ae = chain_->edgel(a).get_theta();
99   if (d==0) return ae; // exactly at an edgel
100   double be = chain_->edgel(a+1).get_theta();
101 
102   return be*d+ae*(1-d);
103 }
104 
105 //: Compute the angle using two adjacent edgels
106 //  (TargetJr used different computations at internal points and at endpoints
107 //  For endpoints the geometric tangent was used, but image gradient directions
108 //  were used for internal points on the chain.)
109 //  Here we use direct geometric angle computation for all points
110 //  The image-based directions are likely less accurate
111 //
get_tangent_angle(const double index)112 double vdgl_interpolator_linear::get_tangent_angle( const double index)
113 {
114   int N = chain_->size();
115   assert(index >= 0 && index <= chain_->size() - 1);
116   if (N==1)
117   {
118     std::cout << " vdgl_interpolator_linear::get_theta(..) -"
119              << " can't compute angle for a chain with one edgel\n";
120     return 0;
121   }
122   int a = int(index); // round down
123   // if index is exactly at N-1, a+1 is invalid, so take the preceding interval:
124   if (a == N-1) --a;
125   assert(a>=0 && a<N-1); // just in case... this should not happen.
126   double xi = (*chain_)[a].x(), yi = (*chain_)[a].y();
127   double xip = (*chain_)[a+1].x(), yip = (*chain_)[a+1].y();
128   double angle = vnl_math::deg_per_rad*std::atan2((yip-yi), (xip-xi));
129   return angle;
130 }
131 
132 
get_curvature(const double index)133 double vdgl_interpolator_linear::get_curvature( const double index)
134 {
135   int a = int(index); // round down
136 
137   if ( a == index ) // if exactly at an edgel, curvature is undefined
138     return vnl_numeric_traits<double>::maxval;
139   else
140     return 0; // curvature of straight line segments is always zero
141 }
142 
143 
get_length()144 double vdgl_interpolator_linear::get_length()
145 {
146   // length is cached (because it's expensive to compute)
147   if ( older( chain_.ptr()))
148     recompute_all();
149 
150   return lengthcache_;
151 }
152 
153 
get_min_x()154 double vdgl_interpolator_linear::get_min_x()
155 {
156   if ( older( chain_.ptr()))
157     recompute_all();
158 
159   return minxcache_;
160 }
161 
162 
get_max_x()163 double vdgl_interpolator_linear::get_max_x()
164 {
165   if ( older( chain_.ptr()))
166     recompute_all();
167 
168   return maxxcache_;
169 }
170 
171 
get_min_y()172 double vdgl_interpolator_linear::get_min_y()
173 {
174   if ( older( chain_.ptr()))
175     recompute_all();
176 
177   return minycache_;
178 }
179 
180 
get_max_y()181 double vdgl_interpolator_linear::get_max_y()
182 {
183   if ( older( chain_.ptr()))
184     recompute_all();
185 
186   return maxycache_;
187 }
188 
189 // cache maintenance
190 
recompute_all()191 void vdgl_interpolator_linear::recompute_all()
192 {
193   recompute_length();
194   recompute_bbox();
195 
196   touch();
197 }
198 
recompute_length()199 void vdgl_interpolator_linear::recompute_length()
200 {
201   lengthcache_= 0;
202 
203   for ( unsigned int i=0; i< chain_->size(); ++i)
204   {
205     unsigned int j = i==0 ? chain_->size()-1 : i-1;
206     vgl_point_2d<double> p1= chain_->edgel(j).get_pt();
207     vgl_point_2d<double> p2= chain_->edgel(i).get_pt();
208 
209     lengthcache_ += length(p2-p1);
210   }
211 }
212 
recompute_bbox()213 void vdgl_interpolator_linear::recompute_bbox()
214 {
215   if ( chain_->size() == 0 )
216   {
217     minxcache_=  maxxcache_= minycache_= maxycache_ = 0.0;
218     return;
219   }
220   minxcache_= chain_->edgel( 0).get_x();
221   maxxcache_= chain_->edgel( 0).get_x();
222   minycache_= chain_->edgel( 0).get_y();
223   maxycache_= chain_->edgel( 0).get_y();
224 
225   for (unsigned int i=1; i< chain_->size(); ++i)
226   {
227     if (chain_->edgel(i).get_x()< minxcache_) minxcache_= chain_->edgel(i).get_x();
228     if (chain_->edgel(i).get_x()> maxxcache_) maxxcache_= chain_->edgel(i).get_x();
229     if (chain_->edgel(i).get_y()< minycache_) minycache_= chain_->edgel(i).get_y();
230     if (chain_->edgel(i).get_y()> maxycache_) maxycache_= chain_->edgel(i).get_y();
231   }
232 }
233