6 //---------------------------------------------------------------------------
11 //-------------------------------------------------------------------------
13 // Exported out of get_n_neighborhood_step to make sure that neigh_n is const so
14 // that if we modify it, we still don't screw up this part: we should not modify
15 // neigh_n while we're iterating on it, because this is a set!
16 // TODO: this could actually be some kind of dilation on a graph.
17 template < typename NeighborCollection >
19 get_n_neighborhood_unitstep
21 std::set<std::size_t> const & neigh_n,
22 NeighborCollection const & neighs
25 typedef std::set<std::size_t> NeighN;
26 NeighN new_neigh_n = neigh_n;
28 for (typename NeighN::const_iterator in = neigh_n.begin(); in != neigh_n.end(); ++in)
29 //for (std::size_t j = 0; j < neigh_n.size(); ++j)
31 // for all neighbors of neighbors
32 //for (std::size_t k = 0; k < neighs[neigh_n[j]].size(); ++k)
33 for (std::size_t k = 0; k < neighs[*in].size(); ++k)
35 // add neighbor's neighbors to the neighborhood
36 //new_neigh_n.insert(neighs[neigh_n[j]][k]);
37 new_neigh_n.insert(neighs[*in][k]);
43 //-------------------------------------------------------------------------
45 template < typename NeighborCollection >
47 get_n_neighborhood_step
49 NeighborCollection const & neigh,
50 std::vector<std::set<std::size_t> > & neigh_n
53 assert(neigh.size() == neigh_n.size());
55 for (std::size_t i = 0; i < neigh_n.size(); ++i)
57 neigh_n[i] = get_n_neighborhood_unitstep(neigh_n[i], neigh);
61 //-------------------------------------------------------------------------
65 //---------------------------------------------------------------------------
67 template < typename NeighborCollection, typename NeighborCollectionOut >
71 NeighborCollection const & neigh, ///< [input] The 1-neighborhoods
72 NeighborCollectionOut & neigh_n_out, ///< [output] The computed n-neighborhood
73 unsigned int n ///< [input] the desired neighborhood width
76 std::vector<std::set<std::size_t> > neigh_n;
77 neigh_n.resize(neigh.size());
78 // initialize n-neighborhood by including the point itself
79 for (std::size_t i = 0; i < neigh_n.size(); ++i)
84 // TODO: clearly, this is not optimal for large neighborhoods.
85 for (unsigned int i = 0; i < n; ++i)
87 detail::get_n_neighborhood_step(neigh, neigh_n);
89 // finally, remove point
90 for (std::size_t i = 0; i < neigh_n.size(); ++i)
94 neigh_n_out.resize(neigh_n.size());
95 for (std::size_t i = 0; i < neigh_n.size(); ++i)
97 neigh_n_out[i].resize(neigh_n[i].size());
98 std::copy(neigh_n[i].begin(), neigh_n[i].end(), neigh_n_out[i].begin());
102 //---------------------------------------------------------------------------
104 template < typename TFaceCollection >
105 shared_ptr<std::vector<std::vector<typename TFaceCollection::value_type::value_type> > >
106 circular_neighborhoods(TFaceCollection const & faces, std::size_t nVertices)
108 typedef typename TFaceCollection::value_type::value_type VertexIndex;
109 typedef std::list<VertexIndex> Neighborhood;
111 // Allocate the result -- it should have as many elements as
112 // the number of vertices of the mesh.
113 std::vector<Neighborhood> res(nVertices);
114 // To check if the circular neighbor of a point is finished
115 // NB: we don't use a vector<bool> as it is apparently quite weird...
116 std::vector<unsigned char> isFinished(nVertices, 0);
117 // To check if everything is finished
118 bool allFinished = false;
120 // NB: the strategy here is quite dumb; basically, we loop through all triangles but will discard a neighbor
121 // if it is not the one that fits at the end of our chain. Thus, we have to loop again and again through
122 // this triangle list -- up to the maximum number of neighbors per point, that is, something like 14 times
123 // for brain meshes. Plus, during the last pass, nothing should change, i.e. we'll do an extra pass for
126 // TODO: actually we could insert front and back to be hopefully twice as fast...
132 for (typename TFaceCollection::const_iterator iFic = faces.begin(); iFic != faces.end(); ++iFic)
134 // for all couple of points on the face
135 typename TFaceCollection::value_type::const_iterator iFi1 = iFic->begin();
136 const_cyclic_iterator<typename TFaceCollection::value_type> iFi2(*iFic, iFi1+1);
138 // NB: We decide that iFi2 is the main point, and iFi1 is the neighbor of iFi2 we want to add.
139 // There is a reason why we do not also consider the reverse couple at the same time: this is to
140 // ensure that all circular neighbors are turning in the same order, if the triangles do so.
141 for (;iFi1 != iFic->end(); ++iFi1, ++iFi2)
143 //std::size_t i = getVertexNumber(mesh, *iFi2);
144 std::size_t i = *iFi2;
146 // Skip voxel if its neighborhood is already done
152 // Check size of the neighborhood
153 if (res[i].size() == 0)
155 // This is the first neighbor added: no need to check anything
156 res[i].push_back(*iFi1);
161 // We add the neighbor only if it is the "next" neighbor of the chain. That means
162 // that the last point of the neighbor chain has to be in the current face as well.
163 // Note also that we have to end as well: if this next neighbor also happens to be
164 // the first of the chain, we mark this voxel neighborhood as done.
166 // Loop through all face vertices
167 VertexIndex lastPoint = res[i].back();
168 typename TFaceCollection::value_type::const_iterator iFaceVertex = iFic->begin();
169 for (; iFaceVertex != iFic->end(); ++iFaceVertex)
171 if (*iFaceVertex == lastPoint)
173 // Check that the point we are about to add is not actually the first point
174 // of the circular neighborhood.
175 if (*iFi1 == res[i].front())
181 res[i].push_back(*iFi1);
192 //convert the result into a vector
193 shared_ptr<std::vector<std::vector<VertexIndex> > > res2(new std::vector<std::vector<VertexIndex> >);
194 allocate_sameSize(res, *res2);
195 //loop(*res2, res, Convert());
198 using namespace til::expr;
199 for (std::size_t i = 0; i < size(res); ++i)
201 detail::loop_xx(castTo(*_1, *_2), (*res2)[i], res[i]);
203 //detail::loop_xx(castTo(*_1, *_2), *res2, res);
208 //---------------------------------------------------------------------------
210 template < typename T >
214 std::vector<std::vector<T> > const & neighbors,
215 std::vector<std::pair<T, T> > & edges
218 typedef std::pair<std::size_t, std::size_t> Edge;
219 std::set<Edge> myedges;
221 std::size_t nNeighbors = 0;
223 for (std::size_t i = 0; i < neighbors.size(); ++i)
226 nNeighbors += neighbors.size();
228 for (std::size_t j = 0; j < neighbors[i].size(); ++j)
230 myedges.insert(make_sorted_pair(i, neighbors[i][j]));
233 // works if neighbors is symmetric only...
234 assert(nNeighbors == 2 * myedges.size());
235 // converting back into vector
236 edges.resize(myedges.size());
237 std::copy(myedges.begin(), myedges.end(), edges.begin());
240 //---------------------------------------------------------------------------
242 template < typename T >
244 Neighboring_faces<T>::operator()
246 std::vector<std::vector<T> > const & cneighs
247 , std::vector<numeric_array<T, 3> > const & faces
248 , std::vector<std::vector<T> > & neighborfaces
251 typedef numeric_array<T, 3> Vec3D;
252 typedef std::map<Vec3D, T, til::Lexicographical_compare<Vec3D> > Face_indices;
253 Face_indices face_indices;
254 for (std::size_t i = 0; i < faces.size(); ++i)
256 face_indices[sorted_vector(faces[i])] = i;
258 neighborfaces.resize(cneighs.size());
259 for (std::size_t i = 0; i < cneighs.size(); ++i)
261 // NB: this test should never fail, actually a well behaved neighborhood
262 // should have a size >= 3.
263 assert(cneighs[i].size() >= 2);
264 neighborfaces[i].resize(cneighs[i].size());
265 std::size_t nNeighs = cneighs[i].size();
266 for (std::size_t j = 0; j < nNeighs; ++j)
268 std::size_t j2 = (j+1) % nNeighs;
269 typename Face_indices::iterator pos;
270 pos = face_indices.find(sorted_vector<Vec3D>(i, cneighs[i][j], cneighs[i][j2]));
271 if (pos != face_indices.end())
273 neighborfaces[i][j] = pos->second;
277 throw InconsistentArguments();
283 //---------------------------------------------------------------------------