00001 /********************************************************************** 00002 * bsimplex.C 00003 **********************************************************************/ 00004 #include "mesh/bsimplex.H" 00005 #include "mesh/simplex_filter.H" 00006 #include "mesh/simplex_array.H" 00007 00008 Bsimplex::IDtable Bsimplex::_table(1<<14); 00009 00010 Bsimplex::~Bsimplex() 00011 { 00012 if (_data_list) { 00013 _data_list->notify_simplex_deleted(); 00014 delete _data_list; 00015 _data_list = 0; 00016 } 00017 } 00018 00019 uint 00020 Bsimplex::generate_key() 00021 { 00022 // called once to generate the "key" for this simplex 00023 // (first time _key is accessed) 00024 00025 // XXX - change back to 1<<24 after verifying highest bit is no 00026 // longer being used in some hacky code somewhere like it was at 00027 // one point 00028 if (_table.num() >= ((1<<23) - 1)) { 00029 // can't allocate > 8 million IDs 00030 err_msg("Bsimplex::generate_key: error: key table is full"); 00031 } else { 00032 _key = _table.num(); 00033 _table += this; 00034 } 00035 return _key; 00036 } 00037 00038 void 00039 Bsimplex::notify_split(Bsimplex *new_simp) 00040 { 00041 // the simplex has split, introducing one or more new 00042 // simplices. this method, called once for each newly created 00043 // simplex, notifies simplex data of the original simplex 00044 // (i.e. this one) about the new simplex. that way the data or its 00045 // owner can decide to put some relevant data onto the new simplex 00046 // if that's appropriate. 00047 if (_data_list) 00048 _data_list->notify_split(new_simp); 00049 } 00050 00051 void 00052 Bsimplex::notify_xform(CWtransf& xf) 00053 { 00054 // a transform was applied to the vertices ... pass it on. 00055 if (_data_list) 00056 _data_list->notify_simplex_xformed(xf); 00057 } 00058 00059 void 00060 Bsimplex::geometry_changed() 00061 { 00062 // This is called for the following reasons. 00063 // 00064 // For a vertex: It moved. 00065 // 00066 // For an edge or face: 00067 // Its shape changed. I.e. one of its vertices moved. 00068 00069 // Notify associated data in case any of them care: 00070 if (_data_list) 00071 _data_list->notify_simplex_changed(); 00072 } 00073 00074 void 00075 Bsimplex::normal_changed() 00076 { 00077 // This is called for the following reasons. 00078 // 00079 // For a face: One of its vertices moved. 00080 // 00081 // For an edge or vertex: 00082 // An adjacent face changed shape, or was added or removed. 00083 00084 // Notify associated data in case any of them care: 00085 if (_data_list) 00086 _data_list->notify_normal_changed(); 00087 } 00088 00089 void 00090 Bsimplex::add_simplex_data(SimplexData* sd) 00091 { 00092 // Quietly ignore NULL pointers: 00093 if (!sd) 00094 return; 00095 00096 // React badly if an item with the same key already exists. 00097 // But cut a little slack if it's actually the same item: 00098 SimplexData* cur = find_data(sd->id()); 00099 if (cur) { 00100 if (cur == sd) { 00101 cerr << "Bsimplex::add_simplex_data: Warning: " 00102 << "attempt to add data twice -- ignored" 00103 << endl; 00104 return; 00105 } else assert(0); 00106 } 00107 00108 // Create the data list if needed: 00109 if (!_data_list) _data_list = new SimplexDataList(); assert(_data_list); 00110 00111 // Now go ahead: 00112 _data_list->add(sd); 00113 } 00114 00115 Bsimplex* 00116 Bsimplex::walk_to_target(CWpt& target, const SimplexFilter& f) const 00117 { 00118 assert(f.accept(this)); 00119 00120 // overview: do a local search over the mesh to get as 00121 // close as possible to the given target point. return 00122 // the simplex that is locally closest to the target. 00123 // however the mesh walk is restricted to traversing 00124 // simplices accepted by the given filter. 00125 00126 // first find the closest point on this simplex, and find the 00127 // corresponding "closest" simplex contained in this one. 00128 // e.g. if this is a face and the closest point is on the 00129 // boundary of the face, then it is on an edge or vertex; if 00130 // this is an edge, "closest" could be one of the vertices at 00131 // its endpoints. or it could be this simplex itself if the 00132 // closest point is not on the boundary. 00133 Wvec bc; 00134 double min_dist = dist(target,bc); 00135 Bsimplex* closest = bc2sim(bc); 00136 00137 // note: we can switch to a lower-dimension simplex 00138 // without getting closer to the target, but if we go to 00139 // a higher dimesion (e.g. edge to face) we require that 00140 // the distance to target decreases by some nonzero amount. 00141 00142 if (closest != this && f.accept(closest)) 00143 return closest->walk_to_target(target, f); // switch to lower-dim simplex 00144 closest = (Bsimplex*)this; 00145 00146 // can any neighbors get closer? 00147 Bsimplex_list nbrs = neighbors().filter(f); 00148 for (int i=0; i<nbrs.num(); i++) { 00149 double d = nbrs[i]->dist(target); 00150 if (d < min_dist - epsAbsMath()) { // get closer by nonzero amount 00151 min_dist = d; 00152 closest = nbrs[i]; 00153 } 00154 } 00155 00156 // return this if it is closest; 00157 // otherwise recurse to the neighbor that was closest: 00158 return (closest == this) ? closest : closest->walk_to_target(target, f); 00159 } 00160 00161 // end of file bsimplex.C