Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
detect_features.C
Go to the documentation of this file.
1 /* *******************************************************************
2  * Rocstar Simulation Suite *
3  * Copyright@2015, Illinois Rocstar LLC. All rights reserved. *
4  * *
5  * Illinois Rocstar LLC *
6  * Champaign, IL *
7  * www.illinoisrocstar.com *
8  * sales@illinoisrocstar.com *
9  * *
10  * License: See LICENSE file in top level of distribution package or *
11  * http://opensource.org/licenses/NCSA *
12  *********************************************************************/
13 /* *******************************************************************
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES *
16  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR *
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
21  * USE OR OTHER DEALINGS WITH THE SOFTWARE. *
22  *********************************************************************/
23 // $Id: detect_features.C,v 1.7 2008/12/06 08:45:28 mtcampbe Exp $
24 
25 #include "FaceOffset_3.h"
26 #include "../Rocblas/include/Rocblas.h"
27 #include "../Rocsurf/include/Rocsurf.h"
28 #include <algorithm>
29 
31 
32 void FaceOffset_3::
33 filter_and_identify_ridge_edges( bool filter_curves)
34 {
35  // Calculate boundary normals
36  _surf->update_bd_normals( _facenormals, false);
37 
38  COM::Attribute *maxdianglev =
39  _buf->new_attribute( "FO_maxdianglev", 'n', COM_DOUBLE, 1, "");
40  _buf->resize_array( maxdianglev, 0);
41 
42  double t=-pi;
43  Rocblas::copy_scalar( &t, maxdianglev);
44 
45  COM::Attribute *mindianglev =
46  _buf->new_attribute( "FO_mindianglev", 'n', COM_DOUBLE, 1, "");
47  _buf->resize_array( mindianglev, 0);
48  t=pi;
49  Rocblas::copy_scalar( &t, mindianglev);
50 
51  COM::Attribute *maxtrnangv =
52  _buf->new_attribute( "FO_maxtrnangv", 'n', COM_DOUBLE, 1, "");
53  _buf->resize_array( maxtrnangv, 0);
54 
55  t=-2;
56  Rocblas::copy_scalar( &t, maxtrnangv);
57 
58  COM::Attribute *mintrnangv =
59  _buf->new_attribute( "FO_mintrnangv", 'n', COM_DOUBLE, 1, "");
60  _buf->resize_array( mintrnangv, 0);
61  t=2;
62  Rocblas::copy_scalar( &t, mintrnangv);
63 
64  COM::Attribute *neighbor_features =
65  _buf->new_attribute( "FO_neighbor_features", 'n', COM_CHAR, 1, "");
66  _buf->resize_array( neighbor_features, 0);
67 
68  COM::Attribute *qsedges =
69  _buf->new_attribute( "FO_qsedges", 'e', COM_CHAR, 1, "");
70  _buf->resize_array( qsedges, 0);
71  _buf->init_done( false);
72 
73  int zero=0;
75 
76  // Clear ridge edges
77  _edges.clear(); _edges.resize( _panes.size());
78 
79  bool to_filter = filter_curves && _panes.size() == 1 && !COMMPI_Initialized();
80 
81  // Loop through the panes and its real faces
82  std::vector< COM::Pane*>::iterator it = _panes.begin();
83  Manifold::PM_iterator pm_it=_surf->pm_begin();
84 
85  int nedges=0, nvertices=0;
86  std::vector<std::map<Edge_ID, double> > edge_maps( _panes.size());
87  std::vector<std::map<Edge_ID, double> > diangle_maps( _panes.size());
88 
89  for ( int i=0, local_npanes = _panes.size();
90  i<local_npanes; ++i, ++it, ++pm_it) {
91  COM::Pane *pane = *it;
92  std::map< Edge_ID, double> &emap_pn = edge_maps[i];
93  std::map< Edge_ID, double> &diangle_pn = diangle_maps[i];
94 
95  nvertices += pane->size_of_real_nodes();
96 
97  // Obtain nodal coordinates of current pane, assuming contiguous layout
98  const Point_3 *pnts = reinterpret_cast<Point_3*>
99  (pane->attribute(COM_NC)->pointer());
100 
101  const Vector_3 *es = reinterpret_cast<const Vector_3*>
102  ( pane->attribute(_eigvecs->id())->pointer());
103  char *tranks = reinterpret_cast<char*>
104  ( pane->attribute(_tangranks->id())->pointer());
105  char *strong = reinterpret_cast<char*>
106  ( pane->attribute(_strong->id())->pointer());
107  double *minvs = reinterpret_cast<double*>
108  ( pane->attribute(mindianglev->id())->pointer());
109  double *maxvs = reinterpret_cast<double*>
110  ( pane->attribute(maxdianglev->id())->pointer());
111  double *minta = reinterpret_cast<double*>
112  ( pane->attribute(mintrnangv->id())->pointer());
113  double *maxta = reinterpret_cast<double*>
114  ( pane->attribute(maxtrnangv->id())->pointer());
115  Vector_3 *fnrms = reinterpret_cast<Vector_3*>
116  ( pane->attribute(_facenormals->id())->pointer());
117 
118  // Loop through real elements of the current pane
119  Element_node_enumerator ene( pane, 1);
120  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
121  int ne=ene.size_of_edges(), uindex=ene[ne-1]-1, vindex=ene[0]-1, windex=0;
122  nedges += ne;
123 
124  for ( int k=0; k<ne; ++k, uindex=vindex, vindex=windex) {
125  windex = ene[ (k+1)%ne]-1;
126 
127  Edge_ID eid(j+1,k), eid_opp = pm_it->get_opposite_real_edge( eid);
128 
129  // Consider border edges as flat and skip them when identifying ridges
130  if ( pm_it->is_physical_border_edge( eid_opp))
131  { ++nedges; continue; }
132 
133  Vector_3 tng = pnts[ windex] - pnts[vindex];
134  tng.normalize();
135  double feg = es[3*vindex+2]* tng;
136 
137  // Safeguard strong angles.
138  // Important: We assume this computation gives identical results
139  // for eid and eid_opp near the thresholds.
140  const Vector_3 &n1 = fnrms[j];
141  const Vector_3 &n2 = eid_opp.is_border() ?
142  pm_it->get_bd_normal( eid_opp) : fnrms[eid_opp.eid()-1];
143  double costheta = n1*n2;
144  if ( costheta>1) costheta = 1;
145  else if (costheta<-1) costheta = -1;
146 
147  double fangle = std::acos( costheta);
148  if ( fangle > _tol_angle_strong) {
149  // Upgrade vertices.
150  if ( tranks[vindex]==2) tranks[vindex] = 1;
151  if ( tranks[windex]==2) tranks[windex] = 1;
152 
153  if ( fangle>pi*0.505 && fangle !=pi)
154  strong[vindex] = strong[windex] = 2;
155  else
156  strong[vindex] = strong[windex] = 1;
157 
158  std::map< Edge_ID, double>::iterator rit = diangle_pn.find(eid);
159  // Make sure the fangle is used consistently.
160  if ( rit == diangle_pn.end()) diangle_pn[eid] = fangle;
161  else fangle = rit->second;
162 
163  if ( feg>0) {
164  if ( fangle > maxvs[vindex]) maxvs[vindex] = fangle;
165  if ( feg > maxta[vindex]) maxta[vindex] = feg;
166  emap_pn[ eid] = feg;
167  }
168  else {
169  if ( -fangle<minvs[vindex]) minvs[vindex] = -fangle;
170  if ( feg < minta[vindex]) minta[vindex] = feg;
171 
172  emap_pn[ eid] = feg;
173  }
174  }
175  else if ( fangle > _tol_angle_weak) {
176  if ( feg > 0) {
177  if ( fangle > maxvs[vindex]) maxvs[vindex] = fangle;
178  if ( feg > maxta[vindex]) maxta[vindex] = feg;
179  }
180  else {
181  if ( -fangle < minvs[vindex]) minvs[vindex] = -fangle;
182  if ( feg < minta[vindex]) minta[vindex] = feg;
183  }
184 
185  // Save the current edge for comparison
186  diangle_pn[eid] = fangle; emap_pn[ eid] = feg;
187  }
188  } // for k (edges)
189  } // for j (elements)
190  } // for i (panes)
191 
192  if ( to_filter)
193  std::cout << "There are " << nedges/2 << " edges and "
194  << nvertices << " vertices " << std::endl;
195 
196  // Reduce on shared nodes for mindianglev and maxdianglev
197  _surf->reduce_on_shared_nodes( mindianglev, Manifold::OP_MIN);
198  _surf->reduce_on_shared_nodes( maxdianglev, Manifold::OP_MAX);
199 
200  _surf->reduce_on_shared_nodes( mintrnangv, Manifold::OP_MIN);
201  _surf->reduce_on_shared_nodes( maxtrnangv, Manifold::OP_MAX);
202  _surf->reduce_on_shared_nodes( _strong, Manifold::OP_MAX);
203 
204  // Count the number of incident strongly attached edges.
205  it = _panes.begin();
206  pm_it=_surf->pm_begin();
207  Rocblas::copy_scalar( &zero, neighbor_features);
208 
209  for ( int i=0, local_npanes = _panes.size(); i<local_npanes;
210  ++i, ++it, ++pm_it) {
211  COM::Pane *pane = *it;
212  std::map< Edge_ID, double> &emap_pn = edge_maps[i];
213  std::map< Edge_ID, double> &diangle_pn = diangle_maps[i];
214 
215  const double *minvs = reinterpret_cast<double*>
216  ( pane->attribute(mindianglev->id())->pointer());
217  const double *maxvs = reinterpret_cast<double*>
218  ( pane->attribute(maxdianglev->id())->pointer());
219  const double *minta = reinterpret_cast<double*>
220  ( pane->attribute(mintrnangv->id())->pointer());
221  double *maxta = reinterpret_cast<double*>
222  ( pane->attribute(maxtrnangv->id())->pointer());
223 
224  char *tranks = reinterpret_cast<char*>
225  ( pane->attribute(_tangranks->id())->pointer());
226  char *nnf = reinterpret_cast<char*>
227  ( pane->attribute(neighbor_features->id())->pointer());
228 
229  COM_assertion( emap_pn.size() == diangle_pn.size());
230  // Loop through ebuf and put ridges edges onto emap_pn
231  for ( std::map< Edge_ID, double>::iterator eit=emap_pn.begin(),
232  rit=diangle_pn.begin(), eend=emap_pn.end(); eit!=eend; ++eit, ++rit) {
233  Edge_ID eid = eit->first;
234  double feg = eit->second, fangle = rit->second;
235 
236  COM_assertion(! eid.is_border());
237  Element_node_enumerator ene( pane, eid.eid());
238  int vi = eid.lid(), vindex = ene[vi]-1;
239 
240  // Determine the number of strongly attached edges
241  if ( !tranks[vindex] || tranks[vindex] == char(-1) || fangle > _tol_angle_strong ||
242  ( feg < 0 && fangle == -minvs[vindex] ||
243  feg > 0 && fangle == maxvs[vindex]) &&
244  ( feg < -_tol_cos_osta && feg == minta[vindex] ||
245  feg > _tol_cos_osta && feg == maxta[vindex])) {
246  ++nnf[vindex];
247  }
248  } // for eit
249  } // for i
250 
251  _surf->reduce_on_shared_nodes( neighbor_features, Manifold::OP_SUM);
252 
253  it = _panes.begin();
254  pm_it=_surf->pm_begin();
255 
256  for ( int i=0, local_npanes = _panes.size(); i<local_npanes;
257  ++i, ++it, ++pm_it) {
258  COM::Pane *pane = *it;
259  std::map< Edge_ID, double> &emap_pn = edge_maps[i];
260  std::map< Edge_ID, double> &diangle_pn = diangle_maps[i];
261  std::set< Edge_ID> &eset_pn = _edges[i];
262 
263  const double *minvs = reinterpret_cast<double*>
264  ( pane->attribute(mindianglev->id())->pointer());
265  const double *maxvs = reinterpret_cast<double*>
266  ( pane->attribute(maxdianglev->id())->pointer());
267  const double *minta = reinterpret_cast<double*>
268  ( pane->attribute(mintrnangv->id())->pointer());
269  double *maxta = reinterpret_cast<double*>
270  ( pane->attribute(maxtrnangv->id())->pointer());
271 
272  char *strong = reinterpret_cast<char*>
273  ( pane->attribute(_strong->id())->pointer());
274  char *tranks = reinterpret_cast<char*>
275  ( pane->attribute(_tangranks->id())->pointer());
276  char *qses = reinterpret_cast<char*>
277  ( pane->attribute(qsedges->id())->pointer());
278  char *nnf = reinterpret_cast<char*>
279  ( pane->attribute(neighbor_features->id())->pointer());
280 
281  COM_assertion( emap_pn.size() == diangle_pn.size());
282  // Loop through ebuf and put ridges edges onto emap_pn
283  for ( std::map< Edge_ID, double>::const_iterator eit=emap_pn.begin(),
284  rit=diangle_pn.begin(), eend=emap_pn.end(); eit!=eend; ++eit, ++rit) {
285  Edge_ID eid = eit->first, eid_opp = pm_it->get_opposite_real_edge( eid);
286  COM_assertion( !eid.is_border());
287  double feg = eit->second, fangle = rit->second, feg_opp;
288 
289  Element_node_enumerator ene( pane, eid.eid());
290  int vi=eid.lid(), ne = ene.size_of_edges();
291  int vindex = ene[vi]-1, windex = ene[ (vi+1)%ne]-1;
292 
293  if ( (nnf[vindex] && nnf[windex]) &&
294  ( strong[vindex] || !tranks[vindex] || tranks[vindex] == char(-1) ||
295  feg < 0 && fangle == -minvs[vindex] ||
296  feg > 0 && fangle == maxvs[vindex] ||
297  feg < -_tol_cos_osta && feg == minta[vindex] ||
298  feg > _tol_cos_osta && feg == maxta[vindex]) ||
299  nnf[vindex]==2 && nnf[windex]==2 &&
300  ( (feg_opp=emap_pn.find( eid_opp)->second)< 0 &&
301  fangle == -minvs[windex] ||
302  feg_opp > 0 && fangle == maxvs[windex]) &&
303  ( feg_opp < -_tol_cos_osta && feg_opp == minta[windex] ||
304  feg_opp > _tol_cos_osta && feg_opp == maxta[windex])) {
305  eset_pn.insert( eid);
306  qses[ eid.eid()-1] |= (1<<eid.lid());
307  }
308  } // for eit
309  } // for i
310 
311  // Update border-edge count
312  _surf->update_bdedge_bitmap( qsedges);
313 
314  // Select the edges whose both half-edges are quasi-strong.
315  it = _panes.begin();
316  pm_it=_surf->pm_begin();
317 
318  for ( int i=0, local_npanes = _panes.size(); i<local_npanes;
319  ++i, ++it, ++pm_it) {
320  std::set< Edge_ID> &eset_pn = _edges[i];
321 
322  // Select quasi-strong edges
323  for ( std::set< Edge_ID>::iterator eit=eset_pn.begin();
324  eit!=eset_pn.end();) {
325  Edge_ID eid = *eit, eid_opp = pm_it->get_opposite_real_edge( eid);
326 
327  if ( !eid_opp.is_border() && eset_pn.find(eid_opp)==eset_pn.end() ||
328  eid_opp.is_border() && !pm_it->get_bdedge_flag( eid_opp)) {
329  std::set< Edge_ID>::iterator to_delete = eit;
330  ++eit;
331  eset_pn.erase( to_delete);
332  }
333  else
334  ++eit;
335  }
336  }
337 
338  // Note: neighbor_features is used as buffers in reclassify_ridge_vertices
339  reclassify_ridge_vertices( 0, 1, neighbor_features,
340  _tangranks, to_filter);
341 
342  // Currently the filtering step does not yet work in parallel.
343  // Filter out obscure-ended ridges. Currently supports only sequential meshes
344  if ( to_filter) for ( ;;) {
345  std::vector< ObscendSet > obscends;
346 
347  int nobscended=build_ridge_neighbor_list( maxtrnangv,mintrnangv, edge_maps,
348  maxdianglev,mindianglev,
349  diangle_maps, obscends);
350  if ( nobscended==0) break;
351 
352  bool dropped = filter_obscended_ridge( edge_maps, diangle_maps, obscends);
353  if ( !dropped) break;
354 
355  reclassify_ridge_vertices( 0, 0, neighbor_features, _tangranks, 1);
356  }
357  // Reclassify ridge edges to upgrade potentially missing corners.
358  reclassify_ridge_vertices( 1, 0, neighbor_features, _tangranks, to_filter);
359 
361  // Update vertices on constraint boundary.
363  // Reclassify ridge edges to upgrade potentially missing corners.
364  reclassify_ridge_vertices(1, 1, neighbor_features, _ctangranks, to_filter);
365 
366  int nredges=0; // Number of ridge edges
367  // Export ridge edges into list
368  it = _panes.begin();
369  pm_it=_surf->pm_begin();
370  for ( int i=0, local_npanes = _panes.size();
371  i<local_npanes; ++i, ++it, ++pm_it) {
372  COM::Pane *pane = *it;
373  std::set< Edge_ID> &eset_pn = _edges[i];
374 
375  // Allocate memory for _ridges and save them.
376  COM::Attribute *att_rdg = pane->attribute(_ridges->id());
377 
378  int n=eset_pn.size();
379  att_rdg->allocate( 2, std::max(n,att_rdg->size_of_items()), 0);
380  int *rdgs = reinterpret_cast<int*>
381  ( pane->attribute(_ridges->id())->pointer()), ii=0;
382 
383  for ( std::set< Edge_ID>::const_iterator eit=eset_pn.begin();
384  eit!=eset_pn.end(); ++eit) {
385  // Make sure that eid_opp is not border
386  Edge_ID eid = *eit, eid_opp = pm_it->get_opposite_real_edge( eid);
387 
388  // Obtain vertex indices.
389  Element_node_enumerator ene( pane, eid.eid());
390  int vindex = eid.lid(), neighbor = (vindex+1)%ene.size_of_edges();
391  vindex = ene[vindex]; neighbor=ene[neighbor];
392 
393  if ( vindex<neighbor || eid_opp.is_border())
394  { rdgs[ii++] = vindex; rdgs[ii++] = neighbor; }
395  }
396 
397  att_rdg->set_size( ii/2);
398  nredges += att_rdg->size_of_items();
399  }
400 
401  if ( to_filter)
402  std::cout << "Found " << nredges << " ridge edges " << std::endl;
403 
404  // Deallocate mindianglev and maxdianglev
405  _buf->delete_attribute( qsedges->name());
406  _buf->delete_attribute( neighbor_features->name());
407  _buf->delete_attribute( mintrnangv->name());
408  _buf->delete_attribute( maxtrnangv->name());
409  _buf->delete_attribute( mindianglev->name());
410  _buf->delete_attribute( maxdianglev->name());
411  _buf->init_done( false);
412 }
413 
414 int FaceOffset_3::
415 insert_boundary_edges( COM::Attribute *tr_attr) {
416  std::vector< COM::Pane*>::iterator it = _panes.begin(), iend=_panes.end();
417  Manifold::PM_iterator pm_it=_surf->pm_begin();
418 
419  int inserted=0;
420  // Loop through the panes and its real elements
421  for ( int i=0; it!=iend; ++i, ++it, ++pm_it) {
422  COM::Pane *pane = *it;
423  std::set< Edge_ID> &eset_pn = _edges[i];
424 
425  char *tranks = reinterpret_cast<char*>
426  ( pane->attribute(tr_attr->id())->pointer());
427  const char *val_bndry=(const char*)pane->attribute
428  (_cnstr_bndry_edges->id())->pointer();
429 
430  // Loop through real elements of the current pane
431  Element_node_enumerator ene( pane, 1);
432  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
433  for ( int k=0, ne=ene.size_of_edges(); k<ne; ++k) {
434  Edge_ID eid(j+1,k), eid_opp = pm_it->get_opposite_real_edge( eid);
435 
436  // If a vertex has mixed geometric and topological edges,
437  // set it to be a corner
438  if ( pm_it->is_physical_border_edge( eid_opp) ||
439  (val_bndry && (val_bndry[j] & (1<<k)))) {
440  int vindex = ene[k]-1;
441 
442  if (tranks[ vindex]==2 || eset_pn.find(eid)==eset_pn.end()) {
443  if ( tranks[ vindex]==1) tranks[ vindex] = 0;
444  eset_pn.insert(eid); ++inserted;
445  }
446  }
447  } // for k
448  } // for j
449  } // for it
450 
451  int inserted_total = inserted;
452  if ( COMMPI_Initialized()) {
453  MPI_Allreduce( &inserted, &inserted_total, 1, MPI_INT, MPI_SUM,
454  _buf->get_communicator());
455  }
456 
457  return inserted_total;
458 }
459 
460 void FaceOffset_3::
461 reclassify_ridge_vertices( const bool upgrade_corners,
462  const bool upgrade_ridge,
463  COM::Attribute *neighbor_feas,
464  COM::Attribute *tr_attr,
465  bool to_filter) {
466 
467  COM::Attribute *vecsums_buf = NULL;
468  if ( upgrade_corners) {
469  vecsums_buf = _buf->new_attribute( "FO_vecsums_buf", 'n', COM_DOUBLE, 3, "");
470  _buf->resize_array( vecsums_buf, 0);
471  }
472 
473  int zero=0;
474  Rocblas::copy_scalar( &zero, neighbor_feas);
475 
476  Vector_3 *pnts=NULL, *vss=NULL;
477  // Loop through the panes and the candidate edges to count incident edges
478  std::vector< COM::Pane*>::iterator it = _panes.begin();
479  Manifold::PM_iterator pm_it=_surf->pm_begin();
480  for ( int ii=0, local_npanes = _panes.size();
481  ii<local_npanes; ++ii, ++it, ++pm_it) {
482  COM::Pane *pane = *it;
483  char *nnf = reinterpret_cast<char*>
484  ( pane->attribute(neighbor_feas->id())->pointer());
485  if ( upgrade_corners) {
486  pnts = reinterpret_cast<Vector_3*>
487  (pane->attribute(COM_NC)->pointer());
488  vss = reinterpret_cast<Vector_3*>
489  (pane->attribute(vecsums_buf->id())->pointer());
490  }
491 
492  std::set< Edge_ID> &eset_pn = _edges[ii];
493  for ( std::set< Edge_ID>::const_iterator eit=eset_pn.begin(),
494  eend = eset_pn.end(); eit!=eend; ++eit) {
495  Edge_ID eid = *eit; COM_assertion(!eid.is_border());
496  Element_node_enumerator ene( pane, eid.eid());
497  int lid = eid.lid(), vindex = ene[lid]-1;
498  ++nnf[vindex];
499 
500  Edge_ID eid_opp = pm_it->get_opposite_real_edge( eid);
501  bool is_border_edge = pm_it->is_physical_border_edge( eid_opp);
502  if ( is_border_edge)
503  ++nnf[ ene[(lid+1)%ene.size_of_edges()]-1];
504 
505  if ( upgrade_corners) {
506  int windex = ene[(lid+1)%ene.size_of_edges()]-1;
507  Vector_3 diff = pnts[ windex] - pnts[vindex];
508  vss[vindex] += diff.normalize();
509 
510  if ( is_border_edge) vss[windex] -= diff;
511  }
512  }
513  }
514  _surf->reduce_on_shared_nodes( neighbor_feas, Manifold::OP_SUM);
515 
516  if ( upgrade_corners)
517  _surf->reduce_on_shared_nodes( vecsums_buf, Manifold::OP_SUM);
518 
519  double tol_sqsin = 4*( 1 - _tol_cos_osta*_tol_cos_osta);
520  int ncrns = 0; // Number of corners
521  // Loop through all vertices to upgrade all the vertices incident on
522  // one or more than two ridge edges.
523  it = _panes.begin();
524  for ( int ii=0, local_npanes = _panes.size(); ii<local_npanes; ++ii, ++it) {
525  COM::Pane *pane = *it;
526  char *nnf = reinterpret_cast<char*>
527  ( pane->attribute(neighbor_feas->id())->pointer());
528  char *tranks = reinterpret_cast<char*>
529  ( pane->attribute(tr_attr->id())->pointer());
530  if ( upgrade_corners)
531  vss = reinterpret_cast<Vector_3*>
532  (pane->attribute(vecsums_buf->id())->pointer());
533 
534  for ( int j=0, nj=pane->size_of_real_nodes(); j<nj; ++j) {
535  if ( upgrade_corners && ( nnf[j]>=3 || nnf[j] == 2 &&
536  vss[j].squared_norm() >= tol_sqsin))
537  tranks[j] = 0; // Upgrade joints to corners
538  else if ( nnf[j] == 0 && std::abs(tranks[j]) == 1)
539  tranks[j] = 2; // Downgrade ridge vertices without neighbors
540  else if ( upgrade_ridge && tranks[j] == 2 && nnf[j] >= 2 ||
541  upgrade_corners && tranks[j] == -1)
542  tranks[j] = 1; // Upgrade ridge vertices with two or more neighbors
543 
544  ncrns += !tranks[j];
545  }
546  }
547 
548  // Reduce tangranks to ensure shared nodes have the same value across panes
549  _surf->reduce_on_shared_nodes( tr_attr, Manifold::OP_MIN);
550 
551  if ( upgrade_corners) {
552  _buf->delete_attribute( vecsums_buf->name());
553  _buf->init_done( false);
554 
555  if ( to_filter)
556  std::cout << "Found " << ncrns << " corner vertices" << std::endl;
557  }
558 }
559 
561  RidgeNeighbor( int v, Edge_ID e) : vid(v), eid(e) {}
562 
563  int vid;
565 };
566 
567 // Construct the neighbor vertices of ridges.
568 // This routine only supports single-pane meshes.
569 int FaceOffset_3::
570 build_ridge_neighbor_list( const COM::Attribute *maxtrnangv,
571  const COM::Attribute *mintrnangv,
572  const std::vector<std::map<Edge_ID, double> > &edge_maps,
573  const COM::Attribute *maxdianglev,
574  const COM::Attribute *mindianglev,
575  const std::vector<std::map<Edge_ID, double> > &diangle_maps,
576  std::vector< ObscendSet > &obscends) {
577 
578  COM_assertion( _panes.size()==1); // Precondition
579 
580  // Loop through the panes and ridge edges
581  Manifold::PM_iterator pm_it=_surf->pm_begin();
582  COM::Pane *pane = _panes[0];
583 
584  // Build ACH list
585  typedef std::map< int, std::list< RidgeNeighbor> > ACH_Lists;
586  ACH_Lists ach; // ACH list
587 
588  const std::set< Edge_ID> &eset_pn = _edges[0]; // List of ridge edges
589  for ( std::set< Edge_ID>::const_iterator eit=eset_pn.begin(),
590  eend=eset_pn.end(); eit!=eend; ++eit) {
591  // Make sure that eid_opp is not border
592  Edge_ID eid = *eit, eid_opp = pm_it->get_opposite_real_edge( eid);
593  COM_assertion( eset_pn.find(eid_opp)!=eset_pn.end() &&
594  !eid.is_border());
595  Element_node_enumerator ene( pane, eid.eid());
596  int lid=eid.lid(), neighbor = (lid+1)%ene.size_of_edges();
597 
598  // Fill in ridge-neighbor into _ridgeneighbors.
599  int vid = ene[lid], neighbor_id=ene[neighbor];
600  ach[vid].push_back( RidgeNeighbor( neighbor_id, eid));
601  }
602 
603  // initialize storage
604  int zero=0;
606  obscends.clear(); obscends.resize( _panes.size());
607 
608  // Check ACH list and build rdgngbs
609  RidgeNeighbor *rdgngbs = reinterpret_cast<RidgeNeighbor*>
610  ( pane->attribute(_ridgeneighbors->id())->pointer());
611  const Point_3 *pnts = reinterpret_cast<Point_3*>
612  (pane->attribute(COM_NC)->pointer());
613  const char *tranks = reinterpret_cast<char*>
614  ( pane->attribute(_tangranks->id())->pointer());
615  const double *minvs = reinterpret_cast<double*>
616  ( pane->attribute(mindianglev->id())->pointer());
617  const double *maxvs = reinterpret_cast<double*>
618  ( pane->attribute(maxdianglev->id())->pointer());
619  const double *minta = reinterpret_cast<double*>
620  (pane->attribute(mintrnangv->id())->pointer());
621  const double *maxta = reinterpret_cast<double*>
622  ( pane->attribute(maxtrnangv->id())->pointer());
623  char *strong = reinterpret_cast<char*>
624  ( pane->attribute(_strong->id())->pointer());
625  const std::map< Edge_ID, double> &diangle_pn = diangle_maps[0];
626  const std::map< Edge_ID, double> &emap_pn = edge_maps[0];
627  ObscendSet &obscend_pn = obscends[0];
628 
629  for ( ACH_Lists::iterator ach_it = ach.begin(); ach_it!=ach.end(); ++ach_it) {
630  // Check angle defect and turning angle
631  int vid= ach_it->first, index = (vid-1)*2;
632  int nedges = ach_it->second.size();
633  std::list< RidgeNeighbor>::iterator ait = ach_it->second.begin();
634 
635  if (nedges>2) {
636  // Insert into rdgngbs
637  for (; ait!=ach_it->second.end(); ) {
638  // Remove non-joint halfedges
639  Edge_ID eid = ait->eid;
640  double fangle = diangle_pn.find( eid)->second;
641  double feg = emap_pn.find( eid)->second;
642 
643  // If disjoint, then add edge into obscend_pn.
644  if ( fangle < _tol_eangle &&
645  ( strong[vid-1] || tranks[vid-1]==1 &&
646  ( (-feg < _tol_cos_osta || feg != minta[vid-1]) &&
647  ( feg < _tol_cos_osta || feg != maxta[vid-1]) ||
648  ( feg<0 || fangle != maxvs[vid-1]) &&
649  ( feg>0 || fangle != -minvs[vid-1]))) ||
650  fangle < _tol_angle_strong &&
651  ( strong[vid-1]==2 || tranks[vid-1]==1 &&
652  ( std::abs(feg) < _tol_cos_osta ||
653  feg != minta[vid-1] && feg != maxta[vid-1]) &&
654  ( feg<0 || fangle != maxvs[vid-1]) &&
655  ( feg>0 || fangle != -minvs[vid-1]))) {
656  obscend_pn[ ait->eid] = std::make_pair( vid, ait->vid);
657  ait = ach_it->second.erase( ait);
658  }
659  else
660  ++ait;
661  }
662 
663  rdgngbs[index].vid = 0; rdgngbs[index+1].vid = -1;
664  }
665 
666  // Classify dangling and semi-joint halfedges
667  ait = ach_it->second.begin();
668  if ( nedges == 1) {
669  // Insert into obscure list to indicate dangling edges
670  rdgngbs[index] = *ait; rdgngbs[index+1].vid=0;
671  Edge_ID eid = ait->eid;
672  double fangle = diangle_pn.find( eid)->second;
673 
674  if ( fangle < _tol_angle_strong || tranks[vid-1])
675  obscend_pn[ eid] = std::make_pair( ach_it->first, ait->vid);
676  }
677  else if ( nedges == 2) {
678  std::list< RidgeNeighbor>::iterator ait2 = ait; ++ait2;
679  int v1 = ait->vid, v2 = ait2->vid;
680  double fangle1 = diangle_pn.find( ait->eid)->second;
681  double fangle2 = diangle_pn.find( ait2->eid)->second;
682 
683  if ( (fangle1<_tol_angle_strong || fangle2<_tol_angle_strong) &&
684  ( !tranks[vid-1] || eval_angle
685  ( pnts[v1-1]-pnts[vid-1], pnts[vid-1]-pnts[v2-1]) > _tol_turn_angle)) {
686  // Do not insert the edges into rdgngbs but insert into obscend_pn
687  obscend_pn[ ait->eid] = std::make_pair( vid, v1);
688  obscend_pn[ ait2->eid] = std::make_pair( vid, v2);
689  }
690  else if (!rdgngbs[index+1].vid)
691  { rdgngbs[index] = *ait; rdgngbs[index+1] = *ait2; }
692  }
693  }
694 
695  int n_obscended = obscends[0].size();
696  std::cerr << "There are " << n_obscended
697  << " obscure-ended edges" << std::endl;
698  return n_obscended;
699 }
700 
701 bool FaceOffset_3::
702 filter_obscended_ridge( const std::vector<std::map<Edge_ID, double> > &edge_maps,
703  const std::vector<std::map<Edge_ID, double> > &diangle_maps,
704  const std::vector< ObscendSet > &obscends) {
705  // Loop through the panes and ridge edges
706  std::vector< COM::Pane*>::iterator it = _panes.begin();
707  Manifold::PM_iterator pm_it=_surf->pm_begin();
708  int local_npanes = _panes.size();
709  std::vector< ObscendSet > todelete(local_npanes);
710 
711  for ( int i=0; i<local_npanes; ++i, ++it, ++pm_it) {
712  const ObscendSet &obscend_pn = obscends[i];
713  ObscendSet &todelete_pn = todelete[i];
714  if ( obscend_pn.empty()) continue;
715 
716  COM::Pane *pane = *it;
717  const char *tranks = reinterpret_cast<char*>
718  ( pane->attribute(_tangranks->id())->pointer());
719  char *strong = reinterpret_cast<char*>
720  ( pane->attribute(_strong->id())->pointer());
721  const RidgeNeighbor *rdgngbs = reinterpret_cast<RidgeNeighbor*>
722  ( pane->attribute(_ridgeneighbors->id())->pointer());
723  const std::map< Edge_ID, double> &diangle_pn = diangle_maps[i];
724 
725  for ( ObscendSet::const_iterator rit=obscend_pn.begin(),
726  rend=obscend_pn.end(); rit!=rend; ++rit) {
727  // Loop through edges to count
728  int cur=rit->second.first, next=rit->second.second, start=cur;
729 
730  Edge_ID eid = rit->first;
731  bool is_dangling = ( rdgngbs[ (cur-1)*2].vid==next &&
732  !rdgngbs[ (cur-1)*2+1].vid ||
733  !rdgngbs[ (cur-1)*2].vid &&
734  !rdgngbs[ (cur-1)*2+1].vid);
735  bool is_not_joint1 = ( rdgngbs[ (cur-1)*2].vid!=next &&
736  rdgngbs[ (cur-1)*2+1].vid!=next), is_not_joint2=false;
737 
738  if ( !is_dangling && !is_not_joint1) continue;
739  bool is_corner=false, is_strong1=strong[cur-1] || !tranks[cur-1];
740  bool is_strong2=strong[next-1] || !tranks[next-1];
741 
742  int count_ks = 0;
743  for ( ;!(is_corner = !tranks[next-1]) && next && next!=start; ) {
744  count_ks += diangle_pn.find( eid)->second>_tol_kangle;
745 
746  int index = (next-1)*2;
747  if ( rdgngbs[ index].vid == cur) {
748  cur = next; next = rdgngbs[index+1].vid; eid = rdgngbs[index+1].eid;
749  is_strong2=strong[next-1] || !tranks[next-1];
750  is_not_joint2 = false;
751  }
752  else {
753  Edge_ID eid_opp = pm_it->get_opposite_real_edge( eid);
754 
755  is_not_joint2 = (rdgngbs[ index+1].vid!=cur) &&
756  (obscend_pn.find(eid_opp) != obscend_pn.end());
757 
758  if ( rdgngbs[ index+1].vid == cur) {
759  cur = next; next = rdgngbs[index].vid; eid = rdgngbs[ index].eid;
760  is_strong2=strong[next-1] || !tranks[next-1];
761  }
762  else
763  { cur = next; next = 0; }
764  }
765  }
766 
767  // Check whether the edge is quasi-obscure.
768  if ( (is_dangling || is_not_joint1 && is_not_joint2) && count_ks<=_tol_kstrong ||
769  is_strong1 && is_strong2 && count_ks==0) {
770  todelete_pn.insert( *rit);
771  }
772  }
773  }
774 
775  return remove_obscure_curves( todelete);
776 }
777 
778 // Remove edges in quasi-obscure curves from candidate-edge list.
779 int FaceOffset_3::
780 remove_obscure_curves( const std::vector< ObscendSet > &obscends) {
781  // Loop through the panes and ridge edges
782  Manifold::PM_iterator pm_it=_surf->pm_begin();
783 
784  // Remove quasi-obscure edges.
785  int dropped = 0;
786  for ( int i=0, local_npanes = _panes.size();
787  i<local_npanes; ++i, ++pm_it) {
788  std::set< Edge_ID> &eset_pn = _edges[i];
789  const ObscendSet &obscend_pn = obscends[i];
790  COM::Pane *pane = _panes[i];
791 
792  char *tranks = reinterpret_cast<char*>
793  ( pane->attribute(_tangranks->id())->pointer());
794  const RidgeNeighbor *rdgngbs = reinterpret_cast<RidgeNeighbor*>
795  ( pane->attribute(_ridgeneighbors->id())->pointer());
796 
797  std::cout << "There are " << obscend_pn.size()
798  << " obscure curves. " << std::endl;
799 
800  for ( ObscendSet::const_iterator rit=obscend_pn.begin(),
801  rend=obscend_pn.end(); rit!=rend; ++rit) {
802  dropped += eset_pn.erase( rit->first);
803  eset_pn.erase( pm_it->get_opposite_real_edge( rit->first));
804 
805  int cur = rit->second.first, next = rit->second.second, start=cur;
806  for ( ; tranks[next-1]; ) {
807  int index = (next-1)*2;
808  Edge_ID eid;
809 
810  if ( rdgngbs[ index].vid == cur)
811  { cur = next; next = rdgngbs[index+1].vid; eid = rdgngbs[ index+1].eid; }
812  else if ( rdgngbs[ index+1].vid == cur)
813  { cur = next; next = rdgngbs[index].vid; eid = rdgngbs[ index].eid; }
814  else
815  { cur = next; next = 0; }
816  if ( next==0 || next==start) break;
817 
818  dropped += eset_pn.erase( eid);
819  eset_pn.erase( pm_it->get_opposite_real_edge( eid));
820  }
821  }
822  }
823 
824  if ( dropped)
825  std::cerr << "Dropped " << dropped << " false candidate edges. " << std::endl;
826 
827  return dropped;
828 }
829 
831 
832 
833 
834 
835 
836 
COM::Attribute * _ridgeneighbors
Definition: FaceOffset_3.h:422
COM::Window * _buf
int insert_boundary_edges(COM::Attribute *tr_attr)
#define COM_assertion(EX)
Error checking utility similar to the assert macro of the C language.
An adaptor for enumerating node IDs of an element.
#define PROP_END_NAMESPACE
Definition: propbasic.h:29
double _tol_kangle
Definition: FaceOffset_3.h:388
j indices k indices k
Definition: Indexing.h:6
void filter_and_identify_ridge_edges(bool filter_curves)
Filter out isolated ridge vertices and identify ridge edges.
#define PROP_BEGIN_NAMESPACE
Definition: propbasic.h:28
double _tol_cos_osta
Definition: FaceOffset_3.h:391
MAP::Facet_ID Edge_ID
Definition: Manifold_2.h:49
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
C/C++ Data types.
Definition: roccom_basic.h:129
COM::Attribute * _tangranks
Definition: FaceOffset_3.h:417
Vector_3 & normalize()
Definition: mapbasic.h:114
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed free of to any person **obtaining a copy of this software and associated documentation to deal with the Software without including without limitation the rights to and or **sell copies of the and to permit persons to whom the **Software is furnished to do subject to the following this list of conditions and the following disclaimers ****Redistributions in binary form must reproduce the above **copyright this list of conditions and the following **disclaimers in the documentation and or other materials **provided with the distribution ****Neither the names of the Center for Simulation of Advanced the University of nor the names of its **contributors may be used to endorse or promote products derived **from this Software without specific prior written permission ****THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY **EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES **OF FITNESS FOR A PARTICULAR PURPOSE AND **NONINFRINGEMENT IN NO EVENT SHALL THE CONTRIBUTORS OR **COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR **ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE **USE OR OTHER DEALINGS WITH THE SOFTWARE v
Definition: roccomf90.h:20
std::vector< COM::Pane * > _panes
COM::Attribute * _eigvecs
Definition: FaceOffset_3.h:407
double _tol_angle_strong
Definition: FaceOffset_3.h:385
RidgeNeighbor(int v, Edge_ID e)
double _tol_eangle
Definition: FaceOffset_3.h:389
**********************************************************************Rocstar Simulation Suite Illinois Rocstar LLC All rights reserved ****Illinois Rocstar LLC IL **www illinoisrocstar com **sales illinoisrocstar com WITHOUT WARRANTY OF ANY **EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES **OF FITNESS FOR A PARTICULAR PURPOSE AND **NONINFRINGEMENT IN NO EVENT SHALL THE CONTRIBUTORS OR **COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR **Arising OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE **USE OR OTHER DEALINGS WITH THE SOFTWARE **********************************************************************INTERFACE SUBROUTINE knode iend
double _tol_angle_weak
Definition: FaceOffset_3.h:384
int size_of_edges() const
Number of edges per element.
blockLoc i
Definition: read.cpp:79
void reclassify_ridge_vertices(const bool upgrade_corners, const bool upgrade_ridge, COM::Attribute *neighbor_feas, COM::Attribute *tr_attr, bool to_filter)
std::map< Edge_ID, std::pair< int, int > > ObscendSet
Definition: FaceOffset_3.h:40
Manifold * _surf
int build_ridge_neighbor_list(const COM::Attribute *maxtrnangv, const COM::Attribute *mintrnangv, const std::vector< std::map< Edge_ID, double > > &edge_maps, const COM::Attribute *maxranglev, const COM::Attribute *minranglev, const std::vector< std::map< Edge_ID, double > > &rangle_maps, std::vector< ObscendSet > &obscends)
Build the list of ridge nighbors and obtain a list of weak-ended vertices Return the number of obscen...
const NT & n
static double eval_angle(const Vector_3 &v1, const Vector_3 &v2)
Definition: FaceOffset_3.h:323
COM::Attribute * _ridges
Definition: FaceOffset_3.h:421
COM::Attribute * _cnstr_bndry_edges
static void copy_scalar(const void *x, Attribute *y)
Operation wrapper for copy (x is a scalar pointer).
Definition: op2args.C:583
j indices j
Definition: Indexing.h:6
static const double pi
Definition: FaceOffset_3.h:429
std::vector< std::set< Edge_ID > > _edges
Definition: FaceOffset_3.h:427
NT abs(const NT &x)
Definition: number_utils.h:130
static void copy(const Attribute *x, Attribute *y)
Wrapper for copy.
Definition: op2args.C:333
CImg< _cimg_Tfloat > acos(const CImg< T > &instance)
Definition: CImg.h:6051
void next()
Go to the next element within the connectivity tables of a pane.
void int * nj
Definition: read.cpp:74
Some basic geometric data types.
Definition: mapbasic.h:54
int remove_obscure_curves(const std::vector< ObscendSet > &obscends)
int COMMPI_Initialized()
Definition: commpi.h:168
COM::Attribute * _strong
Definition: FaceOffset_3.h:420
double _tol_turn_angle
Definition: FaceOffset_3.h:392
bool filter_obscended_ridge(const std::vector< std::map< Edge_ID, double > > &edge_maps, const std::vector< std::map< Edge_ID, double > > &diangl_maps, const std::vector< ObscendSet > &obscends)
Filter out weak-ended curves.
here we put it at the!beginning of the common block The point to point and collective!routines know about but MPI_TYPE_STRUCT as yet does not!MPI_STATUS_IGNORE and MPI_STATUSES_IGNORE are similar objects!Until the underlying MPI library implements the C version of these are declared as arrays of MPI_STATUS_SIZE!The types and are OPTIONAL!Their values are zero if they are not available Note that!using these reduces the portability of MPI_IO INTEGER MPI_BOTTOM INTEGER MPI_DOUBLE_PRECISION INTEGER MPI_LOGICAL INTEGER MPI_2REAL INTEGER MPI_2DOUBLE_COMPLEX INTEGER MPI_LB INTEGER MPI_WTIME_IS_GLOBAL INTEGER MPI_GROUP_EMPTY INTEGER MPI_SUM
COM::Attribute * _facenormals
Definition: FaceOffset_3.h:412
COM::Attribute * _ctangranks
Definition: FaceOffset_3.h:418