1 // This is gel/vifa/vifa_int_faces_adj_attr.cxx
2 #include "vifa_int_faces_adj_attr.h"
3 
vifa_int_faces_adj_attr()4 vifa_int_faces_adj_attr::vifa_int_faces_adj_attr()
5     : vifa_int_faces_attr(), seed_(nullptr), seed_attr_(nullptr) {
6   init();
7   ComputeAttributes();
8 }
9 
10 vifa_int_faces_adj_attr::
vifa_int_faces_adj_attr(const vtol_intensity_face_sptr & seed,int depth,int size_filter,vdgl_fit_lines_params * fitter_params,vifa_group_pgram_params * gpp_s,vifa_group_pgram_params * gpp_w,vifa_coll_lines_params * cpp,vifa_norm_params * np,vifa_int_face_attr_factory * factory,float junk_area_percentage)11 vifa_int_faces_adj_attr(const vtol_intensity_face_sptr&     seed,
12                         int                          depth,
13                         int                          size_filter,
14                         vdgl_fit_lines_params*       fitter_params,
15                         vifa_group_pgram_params*     gpp_s,
16                         vifa_group_pgram_params*     gpp_w,
17                         vifa_coll_lines_params*      cpp,
18                         vifa_norm_params*            np,
19                         vifa_int_face_attr_factory*  factory,
20                         float                        junk_area_percentage)
21   : vifa_int_faces_attr(fitter_params, gpp_s, gpp_w, cpp, np, factory),
22     closure_valid_(false),
23     seed_(seed),
24     seed_attr_(nullptr),
25     depth_(depth),
26     size_filter_(size_filter),
27     junk_area_percentage_(junk_area_percentage),
28     junk_count_(0)
29 {
30   init();
31   ComputeAttributes();
32 }
33 
34 vifa_int_faces_adj_attr::
vifa_int_faces_adj_attr(const vtol_intensity_face_sptr & seed,int depth,iface_list & neighborhood,int size_filter,vdgl_fit_lines_params * fitter_params,vifa_group_pgram_params * gpp_s,vifa_group_pgram_params * gpp_w,vifa_coll_lines_params * cpp,vifa_norm_params * np,vifa_int_face_attr_factory * factory,float junk_area_percentage)35 vifa_int_faces_adj_attr(const vtol_intensity_face_sptr&     seed,
36                         int                          depth,
37                         iface_list&                  neighborhood,
38                         int                          size_filter,
39                         vdgl_fit_lines_params*       fitter_params,
40                         vifa_group_pgram_params*     gpp_s,
41                         vifa_group_pgram_params*     gpp_w,
42                         vifa_coll_lines_params*      cpp,
43                         vifa_norm_params*            np,
44                         vifa_int_face_attr_factory*  factory,
45                         float                        junk_area_percentage)
46   : vifa_int_faces_attr(neighborhood, fitter_params, gpp_s, gpp_w, cpp, np, factory),
47     closure_valid_(false), // still need to filter on size!
48     seed_(seed),
49     seed_attr_(nullptr),
50     depth_(depth),
51     size_filter_(size_filter),
52     junk_area_percentage_(junk_area_percentage),
53     junk_count_(0)
54 {
55   init();
56   ComputeAttributes();
57 }
58 
59 void vifa_int_faces_adj_attr::
SetSeed(const vtol_intensity_face_sptr & seed)60 SetSeed(const vtol_intensity_face_sptr&  seed)
61 {
62   seed_ = seed;
63   closure_valid_ = false;
64   seed_attr_ = factory_new_attr(seed_);
65 }
66 
67 iface_list& vifa_int_faces_adj_attr::
GetFaces()68 GetFaces()
69 {
70   if (!closure_valid_)
71   {
72     faces_.clear();
73     this->compute_closure();
74   }
75 
76   return faces_;
77 }
78 
79 // Caller must delete returned list when finished
80 iface_list*  vifa_int_faces_adj_attr::
GetFaceList()81 GetFaceList()
82 {
83   if (!closure_valid_)
84   {
85     faces_.clear();
86     this->compute_closure();
87   }
88 
89   auto* v = new iface_list;
90   for (auto & face : faces_)
91   {
92     v->push_back(face);
93   }
94 
95   return v;
96 }
97 
98 bool vifa_int_faces_adj_attr::
ComputeAttributes()99 ComputeAttributes()
100 {
101   if (!closure_valid_)
102     this->compute_closure();
103 
104   if (vifa_int_faces_attr::ComputeAttributes())
105   {
106     // Seed is not included in faces_ or attribute histograms
107     seed_attr_ = factory_new_attr(seed_);
108     vifa_int_face_attr*  seed_attr_ptr = seed_attr_.ptr();
109 
110     // Compute ratio of seed to neighbors for each hist attribute
111     for (int i = 0; i < this->NumHistAttributes(); i++)
112     {
113       float  seed_val = (seed_attr_ptr->*(attr_get_funcs[i]))();
114 
115       // Instead of x/y, compute (x+1)/(y+1) since y may be near zero
116 
117       float  hist_mean = GetMeanAttr(i);
118       if (hist_mean < attr_min_vals[i])
119         hist_mean = attr_min_vals[i];
120       mean_ratios_[i] = (seed_val + 1) / (hist_mean + 1);
121 
122       float  hist_min = GetMinAttr(i);
123       if (hist_min < attr_min_vals[i])
124         hist_min = attr_min_vals[i];
125       min_ratios_[i] = (seed_val + 1) / (hist_min + 1);
126     }
127 
128     attributes_valid_ = true;
129   }
130 
131   return valid_p();
132 }
133 
134 int vifa_int_faces_adj_attr::
NeighborhoodSize()135 NeighborhoodSize()
136 {
137   compute_closure();
138   return faces_.size();
139 }
140 
141 // Populate a vector containing all attributes, including inherited ones.
142 bool vifa_int_faces_adj_attr::
GetAttributes(std::vector<float> & attrs)143 GetAttributes(std::vector<float>& attrs)
144 {
145   if (vifa_int_faces_attr::GetAttributes(attrs))
146     return this->vifa_int_faces_adj_attr::GetNativeAttributes(attrs);
147   else
148     return false;
149 }
150 
151 // Append the attribute names to a vector in the same order as
152 // GetAttributes.  KEEP IN SYNC WITH GetAttributes!!!
153 void vifa_int_faces_adj_attr::
GetAttributeNames(std::vector<std::string> & names)154 GetAttributeNames(std::vector<std::string>& names)
155 {
156   vifa_int_faces_attr::GetAttributeNames(names);
157 
158   for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
159   {
160     std::string  name(attr_names[i]);
161     names.push_back("ratio" + name);
162   }
163 
164   for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
165   {
166     std::string  name(attr_names[i]);
167     names.push_back("minRatio" + name);
168   }
169 }
170 
171 // Populate a vector containing attributes native to this class (not
172 // inherited).  KEEP IN SYNC WITH GETNAMES ABOVE!
173 // Assumes that
174 bool vifa_int_faces_adj_attr::
GetNativeAttributes(std::vector<float> & attrs)175 GetNativeAttributes(std::vector<float>& attrs)
176 {
177   if (!this->ComputeAttributes())
178   {
179     std::cerr << "Couldn't compute group adj attributes?\n";
180     return false;
181   }
182 
183   for (int i = 0; i < this->NumHistAttributes(); i++)
184   {
185     attrs.push_back(this->GetRatioAttr(i));
186   }
187 
188   for (int i = 0; i < this->NumHistAttributes(); i++)
189   {
190     attrs.push_back(this->GetMinRatioAttr(i));
191   }
192 
193   // what about Collinearity()???
194 
195   return true;
196 }
197 
198 bool vifa_int_faces_adj_attr::
compute_closure()199 compute_closure()
200 {
201 //  std::cout << " In ifsaa::compute_closure()...\n";
202 
203   if (!closure_valid_)
204   {
205     if (faces_.empty())
206     {
207 //      std::cout << "faces_ is empty -- rebuilding\n";
208 
209       if ((seed_) && (depth_ != BAD_DEPTH))
210       {
211         // Temporarily add the seed to the list (front), preventing the
212         // neighborhood construction from adding it back accidentally.
213         faces_.push_back(seed_);
214 
215         // Build the neighborhood (recursively)
216         this->compute_closure_step(0, seed_);
217 
218         // Remove the seed, leaving the true neighborhood
219         faces_.erase(faces_.begin());
220       }
221     }
222 
223 //    std::cout << faces_.size() << " face(s)" << endl;
224 
225     float    original_area = 0;
226     float    junk_area = 0;
227     int      original_nbrhood_size = faces_.size();
228     float    area_threshold = (seed_->Npix() * junk_area_percentage_);
229     iface_list  keep_faces;
230     for (auto & face : faces_)
231     {
232       original_area += face->Npix();
233 
234       if (face->Npix() >= area_threshold)
235         keep_faces.push_back(face);
236       else
237       {
238         junk_count_++;
239         junk_area += face->Npix();
240       }
241     }
242 
243 //    std::cout << keep_faces.size() << " keep_face(s)" << endl;
244 
245     faces_ = keep_faces;
246     junk_percent_ = (float)junk_count_ / original_nbrhood_size;
247     junk_area_ratio_ = junk_area / original_area;
248     closure_valid_ = true;
249   }
250 
251 #if 0
252   std::cout << "Final faces_: " << faces_.size() << std::endl;
253 
254   for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
255     std::cout << "  (" << (*f)->Xo() << ", " << (*f)->Yo() << "), "
256              << (*f)->Npix() << " pixels\n";
257 #endif
258 
259 //  std::cout << "Leaving ifsaa::compute_closure()\n";
260 
261   return closure_valid_;
262 }
263 
264 float vifa_int_faces_adj_attr::
Collinearity()265 Collinearity()
266 {
267   compute_closure();
268   get_collinear_lines();
269 
270   float    u_len = 0.0f;
271   float    w_len = 0.0f;
272   float    coll = 0.0f;
273   edge_list edges; seed_->edges(edges);
274 
275   for (auto & edge : edges)
276   {
277     vtol_edge_2d*  e = edge->cast_to_edge_2d();
278 
279     if (e)
280     {
281       vifa_coll_lines_sptr  clr = get_line_along_edge(e);
282 
283       if (clr)
284       {
285         u_len += float(e->curve()->length());
286         w_len += float(clr->spanning_length());
287       }
288     }
289   }
290 
291   if (u_len > 0.0f)
292     coll = w_len / u_len;
293 
294   return coll;
295 }
296 
297 // Get the ratio of a vifa_int_face_attr attribute to the seed.
298 float vifa_int_faces_adj_attr::
GetRatioAttr(int attr_index)299 GetRatioAttr(int attr_index)
300 {
301   return mean_ratios_[attr_index];
302 }
303 
304 // Get the ratio of the seed's vifa_int_face_attr to the minimum neighbor
305 float vifa_int_faces_adj_attr::
GetMinRatioAttr(int attr_index)306 GetMinRatioAttr(int attr_index)
307 {
308   return min_ratios_[attr_index];
309 }
310 
311 void vifa_int_faces_adj_attr::
init()312 init()
313 {
314   junk_percent_ = 0.0f;
315   junk_area_ratio_ = 0.0f;
316 
317   int    n = NumHistAttributes();
318   mean_ratios_.reserve(n);
319   min_ratios_.reserve(n);
320 
321   // initialize to -1.
322   for (int i = 0; i < n; i++)
323     mean_ratios_[i] = min_ratios_[i] = -1;
324 }
325 
326 bool vifa_int_faces_adj_attr::
add_unique_face(iface_list & facelist,const vtol_intensity_face_sptr & face,int size_filter)327 add_unique_face(iface_list&               facelist,
328                 const vtol_intensity_face_sptr&  face,
329                 int                       size_filter)
330 {
331   for (auto & check : facelist)
332   {
333     if ((check.ptr()->Xo() == face->Xo()) &&
334         (check.ptr()->Yo() == face->Yo()))
335       return false;
336   }
337 
338   if (face->Npix() >= size_filter)
339   {
340     facelist.push_back(face);
341     return true;
342   }
343 
344   return false;
345 }
346 
347 void vifa_int_faces_adj_attr::
compute_closure_step(int current_depth,vtol_intensity_face_sptr seed)348 compute_closure_step(int                       current_depth,
349                      vtol_intensity_face_sptr  seed)
350 {
351 #ifdef CCS_DEBUG
352   std::cout << "ccs: depth " << current_depth << " of " << depth_;
353 
354   if (seed)
355     std::cout << " at seed " << seed->Xo() << ", " << seed->Yo();
356   else
357     std::cout << " with null seed";
358 #endif
359 
360   if ((current_depth >= depth_) || (!seed))
361   {
362 #ifdef CCS_DEBUG
363     std::cout << "...bailing\n";
364 #endif
365     return;
366   }
367 #ifdef CCS_DEBUG
368   else
369     std::cout << std::endl;
370 #endif
371 
372   // Get all the faces adjacent to the seed face
373   iface_list*  adj_faces = get_adjacent_faces(seed);
374   if (adj_faces)
375   {
376     // For each adjacent face...
377     auto fi = adj_faces->begin();
378     for (; fi != adj_faces->end(); fi++)
379     {
380       vtol_intensity_face_sptr  adj_face_sptr = (*fi);
381 
382       // Try to add the adjacent face to the master face list
383       if (this->add_unique_face(faces_, adj_face_sptr, size_filter_))
384       {
385         // It's a new face, so recursively find its neighbors
386         this->compute_closure_step(current_depth + 1, adj_face_sptr);
387       }
388     }
389 
390     delete adj_faces;
391   }
392   else
393     std::cerr << "vifsaa::compute_closure_step(): No adj. faces found!\n";
394 }
395 
396 vtol_intensity_face_sptr vifa_int_faces_adj_attr::
get_adjacent_face_at_edge(vtol_intensity_face_sptr & known_face,vtol_edge_2d * e)397 get_adjacent_face_at_edge(vtol_intensity_face_sptr&  known_face,
398                           vtol_edge_2d*              e)
399 {
400   vtol_intensity_face_sptr  adj_face = nullptr;
401   face_list faces; e->faces(faces);
402 
403   // Expect only one or two intensity faces for 2-D case
404   if (faces.size() == 2)
405   {
406     vtol_intensity_face*  f1 = faces[0]->cast_to_intensity_face();
407     vtol_intensity_face*  f2 = faces[1]->cast_to_intensity_face();
408 
409     if (f1 && f2 && *known_face == *f1)
410       adj_face = f2;
411     else if (f1 && f2 && *known_face == *f2)
412       adj_face = f1;
413     else
414     {
415       // Known face does not contain the
416       // given edge -- leave result NULL
417     }
418   }
419 
420   return adj_face;
421 }
422 
423 iface_list* vifa_int_faces_adj_attr::
get_adjacent_faces(vtol_intensity_face_sptr & known_face)424 get_adjacent_faces(vtol_intensity_face_sptr&  known_face)
425 {
426   iface_list*    faces = nullptr;
427 
428   if (known_face.ptr())
429   {
430     edge_list edges; known_face->edges(edges);
431     faces = new iface_list;
432 
433     for (auto & edge : edges)
434     {
435       vtol_edge_2d* e = edge->cast_to_edge_2d();
436       if (e)
437       {
438         vtol_intensity_face_sptr  other_f =
439           this->get_adjacent_face_at_edge(known_face, e);
440 
441         if (other_f.ptr())
442           this->add_unique_face(*faces, other_f, 0);
443       }
444     }
445   }
446 
447   return faces;
448 }
449