static Cell_handle findBestCell(const Vector_3 &direction, const Vertex_handle &infinity, const Cell_handle &startingCell) { DEBUG_START; /* FIXME: Maybe some hint will be useful here */ ASSERT(startingCell->has_vertex(infinity) && "Wrong input"); Cell_handle bestCell = startingCell; Cell_handle nextCell = bestCell; double maxProduct = calculateProduct(direction, bestCell, infinity); unsigned numIterations = 0; do { ++numIterations; bestCell = nextCell; ASSERT(bestCell->has_vertex(infinity) && "Wrong iteration"); int infinityIndex = bestCell->index(infinity); for (int i = 0; i < NUM_CELL_VERTICES; ++i) { if (i == infinityIndex) continue; Cell_handle neighbor = bestCell->neighbor(i); double product = calculateProduct(direction, neighbor, infinity); if (product > maxProduct) { nextCell = neighbor; maxProduct = product; } } } while (nextCell != bestCell); ASSERT(bestCell->has_vertex(infinity) && "Wrong result"); DEBUG_END; return bestCell; }
bool is_p_outside(const Point& q, const Triangulation& triang, const Cell_handle& start_cell, Cell_handle& c, int& u, int& v) { Triangulation::Locate_type lt; u = -1; v = -1; c = triang.locate(q, lt, u, v, start_cell); if( lt == Triangulation::OUTSIDE_AFFINE_HULL ) { cerr << "Point " << q << " is outside the affine hull." << endl; return true; } else if( lt == Triangulation::OUTSIDE_CONVEX_HULL ) return true; else { if( lt == Triangulation::CELL ) { if( c->outside ) return true; else return false; } else if( lt == Triangulation::FACET ) { Cell_handle _c = c->neighbor(u); if( c->outside && _c->outside ) return true; else return false; } else if( lt == Triangulation::EDGE ) { if( is_outside_VF(triang, Edge(c, u, v)) ) return true; else return false; } else { CGAL_assertion( lt == Triangulation::VERTEX ); return false; } } }
AlphaSimplex3D:: AlphaSimplex3D(const Delaunay3D::Facet& f, const SimplexSet& simplices, const Delaunay3D& Dt) { Cell_handle c = f.first; for (int i = 0; i < 4; ++i) if (i != f.second) Parent::add(c->vertex(i)); Cell_handle o = c->neighbor(f.second); int oi = o->index(c); VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin(); const DPoint& p1 = (*v++)->point(); const DPoint& p2 = (*v++)->point(); const DPoint& p3 = (*v)->point(); attached_ = false; if (!Dt.is_infinite(c->vertex(f.second)) && CGAL::side_of_bounded_sphere(p1, p2, p3, c->vertex(f.second)->point()) == CGAL::ON_BOUNDED_SIDE) attached_ = true; else if (!Dt.is_infinite(o->vertex(oi)) && CGAL::side_of_bounded_sphere(p1, p2, p3, o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE) attached_ = true; else alpha_ = CGAL::squared_radius(p1, p2, p3); if (attached_) { if (Dt.is_infinite(c)) alpha_ = simplices.find(AlphaSimplex3D(*o))->alpha(); else if (Dt.is_infinite(o)) alpha_ = simplices.find(AlphaSimplex3D(*c))->alpha(); else alpha_ = std::min(simplices.find(AlphaSimplex3D(*c))->alpha(), simplices.find(AlphaSimplex3D(*o))->alpha()); } }
// Constructs regular triangulation of weighted points. // Builds graph of cells with voids. Finds connected components of this graph (voids as clusters of cells). // For each component calculates total void volume and area. // Excludes roughs on the surface (components, connected to the infinite cell). bool regular_triangulation_voids(const Wpi_container& points, Voids_result &res) { typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Cell_handle> CellGraph; typedef typename boost::graph_traits<CellGraph>::vertex_descriptor GVertex; typedef typename boost::graph_traits<CellGraph>::vertex_iterator GVertex_iterator; Rt T; // regular triangulation CellGraph G; // Voronoi subgraph where cells_sqr_r > 0 and edges_sqr_r > 0 (cells and edges with voids) GVertex_iterator vi, vi_end; res.out_log << "Number of input points for RT : " << points.size() << std::endl; T.insert(points.begin(), points.end()); // insert all points in a row (this is faster than one insert() at a time). T.infinite_vertex()->info().atom_id = -1; // set special atom_id for dummy infinite triangulation vertex assert(T.dimension() == 3); /*res.out_log << "Is valid : " << T.is_valid() << std::endl;*/ res.out_log << "Number of vertices in RT : " << T.number_of_vertices() << std::endl; res.out_log << "Number of cells : " << T.number_of_cells() << std::endl; res.out_log << "Number of finite cells : " << T.number_of_finite_cells() << std::endl; /*res.out_log << "Inf. vert. atom id : " << T.infinite_vertex()->info().atom_id << std::endl;*/ // Add finite cells having sqr_r > 0 as graph verticies Finite_cells_iterator cit, cit_end = T.finite_cells_end(); for (cit = T.finite_cells_begin(); cit != cit_end; cit++) { if (cit->weighted_circumcenter().weight() > 0) // cached weighted circumcenter computation cit->id() = add_vertex(Cell_handle(cit), G); // store corresponding graph vertex descriptor in cell's id() } // store one of infinite cells in graph: it will represent all of them. It should be the last vertex in graph with maximal vertex_descriptor. const GVertex inf_graph_v = add_vertex(T.infinite_cell(), G); res.out_log << "inf_graph_v descriptor : " << inf_graph_v << std::endl; // Add graph edges connecting cells with void for (boost::tie(vi, vi_end) = vertices(G); vi != vi_end; ++vi) { const GVertex v1 = *vi; // current graph vertex if (v1 != inf_graph_v) { // check edges only from finite cells const Cell_handle c1 = G[v1]; // current cell for (int i = 0; i < 4; i++) { // for each of four neighbor cells const Cell_handle c2 = c1->neighbor(i); bool ends_in_void = false; // do both corresponding Voronoi verticies lie in void space? bool on_same_side = false; // do both ends lie on the same side of corresponding cell facet? const Weighted_point &p1 = c1->vertex((i+1)&3)->point(); // weighted points of common facet between c and c2 cells const Weighted_point &p2 = c1->vertex((i+2)&3)->point(); const Weighted_point &p3 = c1->vertex((i+3)&3)->point(); const Point &wcc = c1->weighted_circumcenter().point(); GVertex v2; // neighbor vertex in graph to construct edge to if (c2->id() != -1) { // neighbor cell is finite and in graph: id()=vertex_descriptor v2 = c2->id(); ends_in_void = true; on_same_side = (orientation(p1.point(), p2.point(), p3.point(), wcc) == orientation(p1.point(), p2.point(), p3.point(), c2->weighted_circumcenter().point())); } else if (T.is_infinite(c2)) { v2 = inf_graph_v; // use our infinite graph vertex as destination if neighbor cell is infinite ends_in_void = true; on_same_side = (orientation(p1.point(), p2.point(), p3.point(), wcc) != orientation(p1.point(), p2.point(), p3.point(), c1->vertex(i)->point().point())); // same side with infinite vertex = different sides with cell vertex } typename K::Compute_squared_radius_smallest_orthogonal_sphere_3 r_mouth; // facet bottleneck squared radius (facet closed if < 0) if (ends_in_void && (v2 > v1) && (on_same_side || r_mouth(p1, p2, p3) > 0)) add_edge(v1, v2, G); // use ordering v2>v1 to rule out most of the parallel edges: rely on v_inf>v1 for all finite vertices } } } res.out_log << "Number of vertices in G : " << num_vertices(G) << std::endl; res.out_log << "Number of edges in G : " << num_edges(G) << std::endl; // Find connected components on this Voronoi subnetwork std::vector<int> component(num_vertices(G)); int num_components = boost::connected_components(G, &component[0]); const int inf_comp_id = component[inf_graph_v]; // component of infinite vertex res.out_log << "Number of connected components : " << num_components << std::endl; res.out_log << "Component id of infinite vertex : " << inf_comp_id << std::endl; // Reserve storage for results res.voids.resize(num_components); std::fill(res.atom_surf.begin(), res.atom_surf.end(), 0.0L); // Calculate total volume of each finite component for (boost::tie(vi, vi_end) = vertices(G); vi != vi_end; ++vi) { const int comp_id = component[*vi]; if (comp_id != inf_comp_id) { // skip infinite component Cell_handle cell = G[*vi]; // current cell double Vc, Sc; // cell volume and surface Array_double_4 Sa; // per atom surface in cell Vc = cell_void_volume(cell, Sc, Sa); // void volume of cell and its surface area res.voids[comp_id].volume += Vc; // add to volume of component res.voids[comp_id].surface += Sc; for (int k = 0; k < 4; k++) { // process four cell atoms int atom_id = cell->vertex(k)->info().atom_id; res.atom_surf[atom_id] += Sa[k]; // atom exposed surface res.voids[comp_id].atoms.insert(atom_id); // add to set of cavity atoms } } } // Remove skipped infinite component with zero values res.voids.erase(res.voids.begin() + inf_comp_id); // Sort cavities by volume std::sort(res.voids.begin(), res.voids.end(), void_greater); return true; }
bool is_degenerate_VF(const Triangulation& triang, const Cell_handle& c, const int& fid, const int& uid, const int& vid, const Point& d, const char* prefix) { char degen_op_filename[200]; strcat(strcpy(degen_op_filename, prefix), ".degen_VF"); // an extra check - probably not needed. if (triang.is_infinite(c) || triang.is_infinite(c->neighbor(fid)) || triang.is_infinite(c->neighbor(6 - fid - uid - vid))) { return true; } vector<Cell_handle> VF; Facet_circulator fcirc = triang.incident_facets(Edge(c,uid,vid)); Facet_circulator begin = fcirc; do { if (triang.is_infinite((*fcirc).first)) { cerr << "< Inf VF >"; return true; // by check-1 it is degenerate. } Cell_handle cur_c = (*fcirc).first; int cur_fid = (*fcirc).second; // check if cur_c and its cur_fid neighbors are cospherical. if (is_cospherical_pair(triang, Facet(cur_c,cur_fid))) { cerr << "< Cosph VF >"; return true; // by check-2 it is degenerate. } fcirc ++; } while (fcirc != begin); // check-3 Point vv[3]; vv[0] = c->voronoi(); vv[1] = c->neighbor(fid)->voronoi(); vv[2] = c->neighbor(6 - fid - uid - vid)->voronoi(); Vector v[3]; v[0] = vv[0] - d; v[1] = vv[1] - d; v[2] = vv[2] - d; Vector v1xv0 = CGAL::cross_product(v[1], v[0]); Vector v0xv2 = CGAL::cross_product(v[0], v[2]); if (CGAL::to_double(v1xv0 * v0xv2) < 0) { ofstream fout; fout.open(degen_op_filename, ofstream::app); fout << "# prob : v1xv0 * v0xv2 = " << CGAL::to_double(v1xv0 * v0xv2) << endl; fout << "{LIST " << endl; fout << "# VF - color yellow " << endl; draw_VF(triang, Edge(c, uid, vid), 1, 1, 0, 1, fout); fout << "# v0 : segment(driver, voronoi(c)) - color red " << endl; draw_segment(Segment(d, vv[0]), 1, 0, 0, 1, fout); fout << "# v1 : segment(driver, voronoi(c->neighbor1)) - color green " << endl; draw_segment(Segment(d, vv[1]), 0, 1, 0, 1, fout); fout << "# v2 : segment(driver, voronoi(c->neighbor2)) - color blue " << endl; draw_segment(Segment(d, vv[2]), 0, 0, 1, 1, fout); fout << "}" << endl; fout.close(); cerr << "< - v1xv0 * v0xv2 < 0 - >"; return true; } return false; }
float sdf( const Point& q, const Mesh &mesh, const vector<double>& weights, KdTree& kd_tree, const Triangulation& triang ) { VECTOR3 query (CGAL::to_double(q.x()), CGAL::to_double(q.y()), CGAL::to_double(q.z())); kd_tree.queryPosition(query); // Initialize the search structure, and search all N points int n_vid = kd_tree.getNeighbourPositionIndex(0); if(n_vid == -1) throw std::runtime_error("No nearest neighbor. MDS empty?"); CGAL_assertion( ! mesh.vert_list[n_vid].iso()); MVertex nv = mesh.vert_list[n_vid]; double min_sq_d = HUGE; int n_fid = -1; for(int i = 0; i < nv.num_inc_face; i ++) { MFace f = mesh.face_list[nv.inc_face(i)]; Point p[3] = {mesh.vert_list[f.get_corner(0)].point(), mesh.vert_list[f.get_corner(1)].point(), mesh.vert_list[f.get_corner(2)].point()}; Triangle_3 t (p[0], p[1], p[2]); Plane_3 H (p[0], p[1], p[2]); Point _q = H.projection(q); // check if _q is inside t. if( t.has_on(_q) ) { double sq_d = CGAL::to_double((q-_q)*(q-_q)); if( sq_d < min_sq_d ) { min_sq_d = sq_d; n_fid = nv.inc_face(i); } } else { for(int j = 0; j < 3; j ++) { double _d = CGAL::to_double(CGAL::squared_distance(_q,Segment(p[j], p[(j+1)%3]))); double sq_d = CGAL::to_double((q-_q)*(q-_q)) + _d; if( sq_d < min_sq_d ) { min_sq_d = sq_d; n_fid = nv.inc_face(i); } } } } // locate the query point in the triang which is already tagged // with in-out flag by the reconstruction. bool is_q_outside = false; Triangulation::Locate_type lt; int u = -1, v = -1; Cell_handle c = triang.locate(q, lt, u, v); if( lt == Triangulation::OUTSIDE_AFFINE_HULL ) { is_q_outside = true; cerr << "Point " << q << " is outside the affine hull." << endl; } else if( lt == Triangulation::OUTSIDE_CONVEX_HULL ) is_q_outside = true; else { if( lt == Triangulation::CELL ) { if( c->outside ) is_q_outside = true; else is_q_outside = false; } else if( lt == Triangulation::FACET ) { Cell_handle _c = c->neighbor(u); if( c->outside && _c->outside ) is_q_outside = true; else is_q_outside = false; } else if( lt == Triangulation::EDGE ) { if( is_outside_VF(triang, Edge(c, u, v)) ) is_q_outside = true; else is_q_outside = false; } else { CGAL_assertion( lt == Triangulation::VERTEX ); is_q_outside = false; } } double w; if(weights.size() && mesh.face_list[n_fid].label != -1) w = weights[mesh.face_list[n_fid].label]; else w = 1.0; // double w = mesh.face_list[n_fid].w; double gen_sdf = 0; if( is_q_outside ) gen_sdf = w*sqrt(min_sq_d); else gen_sdf = -w*min_sq_d; #if 0 double MAX = 10, MIN = -10; if( gen_sdf > MAX ) gen_sdf = MAX; if( gen_sdf < MIN ) gen_sdf = MIN; #endif return gen_sdf; }