libigl v2.5.0
Loading...
Searching...
No Matches
WindingNumberTree.h
Go to the documentation of this file.
1// This file is part of libigl, a simple c++ geometry processing library.
2//
3// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
4//
5// This Source Code Form is subject to the terms of the Mozilla Public License
6// v. 2.0. If a copy of the MPL was not distributed with this file, You can
7// obtain one at http://mozilla.org/MPL/2.0/.
8#ifndef IGL_WINDINGNUMBERTREE_H
9#define IGL_WINDINGNUMBERTREE_H
10#include <list>
11#include <map>
12#include <Eigen/Dense>
13#include "WindingNumberMethod.h"
14#include <cassert>
15#include <memory>
16
17namespace igl
18{
20 template <
21 typename Scalar,
22 typename Index>
24 {
25 public:
26 using Point = Eigen::Matrix<Scalar,1,3>;
27 // Method to use (see enum above)
28 //static double min_max_w;
29 static std::map<
30 std::pair<const WindingNumberTree*,const WindingNumberTree*>,
31 Scalar>
33 protected:
36 std::list<WindingNumberTree * > children;
37 typedef
38 Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
40 typedef
41 Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
43 // Base mesh vertices with duplicates removed (root will fill this in and
44 // then everyone's Vptr will point to it.
46 // Shared pointer to base mesh vertices
47 std::shared_ptr<MatrixXS> Vptr;
48 // Facets in this bounding volume
50 // Tessellated boundary curve
52 // Upper Bound on radius of enclosing ball
53 Scalar radius;
54 // (Approximate) center (of mass)
56 public:
57 inline WindingNumberTree();
58 // For root
59 template <typename DerivedV, typename DerivedF>
60 inline WindingNumberTree(
61 const Eigen::MatrixBase<DerivedV> & V,
62 const Eigen::MatrixBase<DerivedF> & F);
63 // For chilluns
64 inline WindingNumberTree(
67 inline virtual ~WindingNumberTree();
68 inline void delete_children();
69 template <typename DerivedV, typename DerivedF>
70 inline void set_mesh(
71 const Eigen::MatrixBase<DerivedV> & V,
72 const Eigen::MatrixBase<DerivedF> & F);
73 // Set method
74 inline void set_method( const WindingNumberMethod & m);
75 public:
76 // Grow the Tree recursively
77 inline virtual void grow();
78 // Determine whether a given point is inside the bounding
79 //
80 // Inputs:
81 // p query point
82 // Returns true if the point p is inside this bounding volume
83 inline virtual bool inside(const Point & p) const;
84 // Compute the (partial) winding number of a given point p
85 // According to method
86 //
87 // Inputs:
88 // p query point
89 // Returns winding number
90 inline Scalar winding_number(const Point & p) const;
91 // Same as above, but always computes winding number using exact method
92 // (sum over every facet)
93 inline Scalar winding_number_all(const Point & p) const;
94 // Same as above, but always computes using sum over tessllated boundary
95 inline Scalar winding_number_boundary(const Point & p) const;
105 //double winding_number_approx_simple(
106 // const Point & p,
107 // const double min_max_w);
108 // Print contents of Tree
109 //
110 // Optional input:
111 // tab tab to show depth
112 inline void print(const char * tab="");
113 // Determine max absolute winding number
114 //
115 // Inputs:
116 // p query point
117 // Returns max winding number of
118 inline virtual Scalar max_abs_winding_number(const Point & p) const;
119 // Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
120 // simple polyhedron
121 inline virtual Scalar max_simple_abs_winding_number(const Point & p) const;
122 // Compute or read cached winding number for point p with respect to mesh
123 // in bounding box, recursing according to approximation criteria
124 //
125 // Inputs:
126 // p query point
127 // that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
128 // Returns cached winding number
129 inline virtual Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
130 };
131}
132
133// Implementation
134
135#include "WindingNumberTree.h"
136#include "winding_number.h"
137#include "triangle_fan.h"
138#include "exterior_edges.h"
139
140#include "PI.h"
142
143#include <iostream>
144#include <limits>
145
146//template <typename Scalar, typename Index>
147//WindingNumberMethod WindingNumberTree<Scalar,Index>::method = EXACT_WINDING_NUMBER_METHOD;
148//template <typename Scalar, typename Index>
149//double WindingNumberTree<Scalar,Index>::min_max_w = 0;
150template <typename Scalar, typename Index>
151std::map< std::pair<const igl::WindingNumberTree<Scalar,Index>*,const igl::WindingNumberTree<Scalar,Index>*>, Scalar>
153
154template <typename Scalar, typename Index>
157 parent(NULL),
158 SV(),
159 F(),
160 cap(),
161 radius(std::numeric_limits<Scalar>::infinity()),
162 center(0,0,0)
163{
164}
165
166template <typename Scalar, typename Index>
167template <typename DerivedV, typename DerivedF>
169 const Eigen::MatrixBase<DerivedV> & _V,
170 const Eigen::MatrixBase<DerivedF> & _F):
172 parent(NULL),
173 SV(),
174 F(),
175 cap(),
176 radius(std::numeric_limits<Scalar>::infinity()),
177 center(0,0,0)
178{
179 set_mesh(_V,_F);
180}
181
182template <typename Scalar, typename Index>
183template <typename DerivedV, typename DerivedF>
185 const Eigen::MatrixBase<DerivedV> & _V,
186 const Eigen::MatrixBase<DerivedF> & _F)
187{
188 // Remove any exactly duplicate vertices
189 // Q: Can this ever increase the complexity of the boundary?
190 // Q: Would we gain even more by remove almost exactly duplicate vertices?
191 Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,1> SVI,SVJ;
192 igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
193 {
194 Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
196 triangle_fan(EE,cap);
197 }
198 // point Vptr to SV
199 Vptr = std::make_shared<MatrixXS>(SV);
200}
201
202template <typename Scalar, typename Index>
207 parent(&parent),
209 SV(),
210 F(_F),
211 cap()
212{
213 Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
215 triangle_fan(EE,cap);
216}
217
218template <typename Scalar, typename Index>
223
224template <typename Scalar, typename Index>
226{
227 // Delete children
228 typename std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
229 while(cit != children.end())
230 {
231 // clear the memory of this item
232 delete (* cit);
233 // erase from list, returns next element in iterator
234 cit = children.erase(cit);
235 }
236}
237
238template <typename Scalar, typename Index>
240{
241 this->method = m;
242 for(auto child : children)
243 {
244 child->set_method(m);
245 }
246}
247
248template <typename Scalar, typename Index>
250{
251 // Don't grow
252 return;
253}
254
255template <typename Scalar, typename Index>
257{
258 return true;
259}
260
261template <typename Scalar, typename Index>
262inline Scalar
264{
265 //cout<<"+"<<boundary.rows();
266 // If inside then we need to be careful
267 if(inside(p))
268 {
269 // If not a leaf then recurse
270 if(children.size()>0)
271 {
272 // Recurse on each child and accumulate
273 Scalar sum = 0;
274 for(
275 typename std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
276 cit != children.end();
277 cit++)
278 {
279 switch(method)
280 {
282 sum += (*cit)->winding_number(p);
283 break;
286 //if((*cit)->max_simple_abs_winding_number(p) > min_max_w)
287 //{
288 sum += (*cit)->winding_number(p);
289 //}
290 break;
291 default:
292 assert(false);
293 break;
294 }
295 }
296 return sum;
297 }else
298 {
299 return winding_number_all(p);
300 }
301 }else{
302 // Otherwise we can just consider boundary
303 // Q: If we using the "multipole" method should we also subdivide the
304 // boundary case?
305 if((cap.rows() - 2) < F.rows())
306 {
307 switch(method)
308 {
310 return winding_number_boundary(p);
312 {
313 Scalar dist = (p-center).norm();
314 // Radius is already an overestimate of inside
315 if(dist>1.0*radius)
316 {
317 return 0;
318 }else
319 {
320 return winding_number_boundary(p);
321 }
322 }
324 {
325 return parent->cached_winding_number(*this,p);
326 }
327 default: assert(false);break;
328 }
329 }else
330 {
331 // doesn't pay off to use boundary
332 return winding_number_all(p);
333 }
334 }
335 return 0;
336}
337
338template <typename Scalar, typename Index>
339inline Scalar
344
345template <typename Scalar, typename Index>
346inline Scalar
351
352//template <typename Scalar, typename Index>
353//inline double igl::WindingNumberTree<Scalar,Index>::winding_number_approx_simple(
354// const Point & p,
355// const double min_max_w)
356//{
357// using namespace std;
358// if(max_simple_abs_winding_number(p) > min_max_w)
359// {
360// return winding_number(p);
361// }else
362// {
363// cout<<"Skipped! "<<max_simple_abs_winding_number(p)<<"<"<<min_max_w<<endl;
364// return 0;
365// }
366//}
367
368template <typename Scalar, typename Index>
370{
371 // Print all facets
372 std::cout<<tab<<"["<<std::endl<<F<<std::endl<<"]";
373 // Print children
374 for(
375 typename std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
376 cit != children.end();
377 cit++)
378 {
379 std::cout<<","<<std::endl;
380 (*cit)->print((std::string(tab)+"").c_str());
381 }
382}
383
384template <typename Scalar, typename Index>
385inline Scalar
387{
388 return std::numeric_limits<Scalar>::infinity();
389}
390
391template <typename Scalar, typename Index>
392inline Scalar
394 const Point & /*p*/) const
395{
396 return std::numeric_limits<Scalar>::infinity();
397}
398
399template <typename Scalar, typename Index>
400inline Scalar
403 const Point & p) const
404{
405 // Simple metric for `is_far`
406 //
407 // this that
408 // --------
409 // ----- / | \ .
410 // / r \ / R \ .
411 // | p ! | | ! |
412 // \_____/ \ /
413 // \________/
414 //
415 //
416 // a = angle formed by trapazoid formed by raising sides with lengths r and R
417 // at respective centers.
418 //
419 // a = atan2(R-r,d), where d is the distance between centers
420
421 // That should be bigger (what about parent? what about sister?)
422 bool is_far = this->radius<that.radius;
423 if(is_far)
424 {
425 Scalar a = atan2(
426 that.radius - this->radius,
427 (that.center - this->center).norm());
428 assert(a>0);
429 is_far = (a<PI/8.0);
430 }
431
432 if(is_far)
433 {
434 // Not implemented yet
435 std::pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
436 // Need to compute it for first time?
437 if(cached.count(this_that)==0)
438 {
439 cached[this_that] =
441 }
442 return cached[this_that];
443 }else if(children.size() == 0)
444 {
445 // not far and hierarchy ended too soon: can't use cache
446 return that.winding_number_boundary(p);
447 }else
448 {
449 for(
450 typename std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
451 cit != children.end();
452 cit++)
453 {
454 if((*cit)->inside(p))
455 {
456 return (*cit)->cached_winding_number(that,p);
457 }
458 }
459 // Not inside any children? This can totally happen because bounding boxes
460 // are set to bound contained facets. So sibilings may overlap and their
461 // union may not contain their parent (though, their union is certainly a
462 // subset of their parent).
463 assert(false);
464 }
465 return 0;
466}
467
468#endif
Space partitioning tree for computing winding number hierarchically.
Definition WindingNumberTree.h:24
std::list< WindingNumberTree * > children
Definition WindingNumberTree.h:36
std::shared_ptr< MatrixXS > Vptr
Definition WindingNumberTree.h:47
WindingNumberMethod method
Definition WindingNumberTree.h:34
MatrixXF cap
Definition WindingNumberTree.h:51
virtual Scalar max_simple_abs_winding_number(const Point &p) const
Definition WindingNumberTree.h:393
virtual ~WindingNumberTree()
Definition WindingNumberTree.h:219
virtual Scalar max_abs_winding_number(const Point &p) const
Definition WindingNumberTree.h:386
void delete_children()
Definition WindingNumberTree.h:225
Eigen::Matrix< Index, Eigen::Dynamic, Eigen::Dynamic > MatrixXF
Definition WindingNumberTree.h:42
void set_method(const WindingNumberMethod &m)
Definition WindingNumberTree.h:239
Scalar winding_number_all(const Point &p) const
Definition WindingNumberTree.h:340
static std::map< std::pair< const WindingNumberTree *, const WindingNumberTree * >, Scalar > cached
Definition WindingNumberTree.h:32
void set_mesh(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F)
Definition WindingNumberTree.h:184
virtual bool inside(const Point &p) const
Definition WindingNumberTree.h:256
void print(const char *tab="")
Definition WindingNumberTree.h:369
MatrixXF F
Definition WindingNumberTree.h:49
WindingNumberTree()
Definition WindingNumberTree.h:155
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > MatrixXS
Definition WindingNumberTree.h:39
Point center
Definition WindingNumberTree.h:55
MatrixXS SV
Definition WindingNumberTree.h:45
virtual Scalar cached_winding_number(const WindingNumberTree &that, const Point &p) const
Definition WindingNumberTree.h:401
Eigen::Matrix< Scalar, 1, 3 > Point
Definition WindingNumberTree.h:26
Scalar winding_number(const Point &p) const
Definition WindingNumberTree.h:263
Scalar winding_number_boundary(const Point &p) const
Definition WindingNumberTree.h:347
virtual void grow()
Definition WindingNumberTree.h:249
Scalar radius
Definition WindingNumberTree.h:53
const WindingNumberTree * parent
Definition WindingNumberTree.h:35
Definition AABB.h:18
void remove_duplicate_vertices(const Eigen::MatrixBase< DerivedV > &V, const double epsilon, Eigen::PlainObjectBase< DerivedSV > &SV, Eigen::PlainObjectBase< DerivedSVI > &SVI, Eigen::PlainObjectBase< DerivedSVJ > &SVJ)
Remove duplicate vertices upto a uniqueness tolerance (epsilon).
void winding_number(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F, const Eigen::MatrixBase< DerivedO > &O, Eigen::PlainObjectBase< DerivedW > &W)
Computes the generalized winding number at each dim-dimensional query point in O with respect to the ...
WindingNumberMethod
Definition WindingNumberMethod.h:13
@ APPROX_SIMPLE_WINDING_NUMBER_METHOD
Definition WindingNumberMethod.h:17
@ APPROX_CACHE_WINDING_NUMBER_METHOD
Definition WindingNumberMethod.h:19
@ EXACT_WINDING_NUMBER_METHOD
Definition WindingNumberMethod.h:15
void exterior_edges(const Eigen::MatrixBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedE > &E)
Determines boundary "edges" and also edges with an odd number of occurrences where seeing edge (i,...
void triangle_fan(const Eigen::MatrixBase< DerivedE > &E, Eigen::PlainObjectBase< Derivedcap > &cap)
Given a list of faces tessellate all of the "exterior" edges forming another list of.
void sum(const Eigen::SparseMatrix< T > &X, const int dim, Eigen::SparseVector< T > &S)
Sum the columns or rows of a sparse matrix.
constexpr double PI
π
Definition PI.h:18
Definition PlainMatrix.h:18