/** * Calls the given function on all vertices that are on a boundary and have a normal and curvature * @param callback The function to call * @param material The material type (default ROCK) */ void StoneWeatherer::callOnVertices( void ( *callback )( const Vertex & v ), Contents material ) const { for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { if ( it->info().kill <= BORDER && ( it->info().flag & material ) ) { callback( *it ); } } }
/** * Executes one custom timestep * @param averageEdgeLength The function to compute the average edge length for a given vertex * @param getOffsetPoint Computes the new location of the given point * @return The results of running the timestep */ stepResults StoneWeatherer::doOneCustomStep( double ( *averageEdgeLength )( const Vertex_handle & v ), Point( *getOffsetPoint )( const Point & p, const VertexData & d, const StoneWeatherer * caller ) ) { CGAL::Timer timestamp; stepResults result; result.secondsTotal = 0.0; timestamp.start(); timestamp.reset(); /** * Maps circumcenters to where they really came from */ map<Point,Point> pointMap; // Generate the correct-resolution offset points vector<Point> newPoints; int n; int i; int j; Vertex_handle vhi; Vertex_handle vhj; double dist2; Point a; Point b; Point c; VertexData d; // Put in midPoints of edges as needed, and flag redundant vertices for ( Cell_iterator it = newDT->finite_cells_begin(); it != newDT->finite_cells_end(); ++it ) { if ( it->info() != AIR ) { for ( n = 0; n < 4; ++n ) { if ( it->neighbor( n )->info() != it->info() || newDT->is_infinite( it->neighbor( n ) ) ) { for ( i = 1; i < 4; ++i ) { Vertex_handle vhi = it->vertex( n ^ i ); for ( j = i + 1; j < 4; ++j ) { Vertex_handle vhj = it->vertex( n ^ j ); // Only check each edge once... if ( vhi < vhj ) { dist2 = ( vhi->point() - vhj->point() ).squared_length(); if ( dist2 > maxSquareDistance( averageEdgeLength, vhi, vhj ) ) { // Don't split non-live edges a = vhi->point(); b = vhj->point(); if ( !live( a.x(), a.y(), a.z() ) && !live( b.x(), b.y(), b.z() ) ) { continue; } // Split edge a = CGAL::ORIGIN + ( ( a - CGAL::ORIGIN ) + ( b - CGAL::ORIGIN ) ) * 0.5; d = VertexData::midPoint( vhi->info(), vhj->info() ); //// If the vertex is shared by both objects, split it //if ( ( d.flag & ROCK ) && ( d.flag & MORE_ROCK ) ) { // VertexData d1; // VertexData d2; // splitVertexData( d, d1, d2 ); // // Point a1 = jitterPoint( a ); // Point a2 = jitterPoint( a ); // // c = getOffsetPoint( a1, d1, this ); // newPoints.push_back( c ); // pointMap.insert( pair<Point,Point>( c, a1 ) ); // c = getOffsetPoint( a2, d2, this ); // newPoints.push_back( c ); // pointMap.insert( pair<Point,Point>( c, a2 ) ); //} //else { c = getOffsetPoint( a, d, this ); newPoints.push_back( c ); pointMap.insert( pair<Point,Point>( c, a ) ); //} } else if ( vhi->info().kill != TOO_CLOSE && dist2 < minSquareDistance( averageEdgeLength, vhi, vhj ) ) { // The higher-address endpoint vhj->info().kill = TOO_CLOSE; } } } } } } } } double bound[ 3 ][ 2 ] = { { 1.0e30, -1.0e30 }, { 1.0e30, -1.0e30 }, { 1.0e30, -1.0e30 } }; // Put in all the border vertices for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { if ( it->point().x() < bound[ 0 ][ 0 ] ) { bound[ 0 ][ 0 ] = it->point().x(); } else if ( it->point().x() > bound[ 0 ][ 1 ] ) { bound[ 0 ][ 1 ] = it->point().x(); } if ( it->point().y() < bound[ 1 ][ 0 ] ) { bound[ 1 ][ 0 ] = it->point().y(); } else if ( it->point().y() > bound[ 1 ][ 1 ] ) { bound[ 1 ][ 1 ] = it->point().y(); } if ( it->point().z() < bound[ 2 ][ 0 ] ) { bound[ 2 ][ 0 ] = it->point().z(); } else if ( it->point().z() > bound[ 2 ][ 1 ] ) { bound[ 2 ][ 1 ] = it->point().z(); } if ( !live( it->point().x(), it->point().y(), it->point().z() ) ) { newPoints.push_back( it->point() ); pointMap.insert( pair<Point,Point>( it->point(), it->point() ) ); } else if ( it->info().kill == BORDER ) { VertexData d = it->info(); Point a = it->point(); Point c; //// If the vertex is shared by both objects, split it //if ( ( d.flag & ROCK ) && ( d.flag & MORE_ROCK ) ) { // VertexData d1; // VertexData d2; // splitVertexData( d, d1, d2 ); // // Point a1 = jitterPoint( a ); // Point a2 = jitterPoint( a ); // // c = getOffsetPoint( a1, d1, this ); // newPoints.push_back( c ); // pointMap.insert( pair<Point,Point>( c, a1 ) ); // c = getOffsetPoint( a2, d2, this ); // newPoints.push_back( c ); // pointMap.insert( pair<Point,Point>( c, a2 ) ); //} //else { c = getOffsetPoint( a, d, this ); newPoints.push_back( c ); pointMap.insert( pair<Point,Point>( c, a ) ); //} } } result.secondsTotal += ( result.secondsMotion = timestamp.time() ); timestamp.reset(); // Create the new mesh swapDT(); newDT->clear(); newDT->insert( newPoints.begin(), newPoints.end() ); result.secondsTotal += ( result.secondsCGAL = timestamp.time() ); //secondsTotal += result.secondsCGAL; //secondsCGAL += result.secondsCGAL; timestamp.reset(); // Update the inside-outside flags of new tetrahedrons setContentFlags( result.midPoint, pointMap ); result.midPoint[ 0 ] = ( bound[ 0 ][ 0 ] + bound[ 0 ][ 1 ] ) * 0.5; result.midPoint[ 1 ] = ( bound[ 1 ][ 0 ] + bound[ 1 ][ 1 ] ) * 0.5; result.midPoint[ 2 ] = ( bound[ 2 ][ 0 ] + bound[ 2 ][ 1 ] ) * 0.5; result.secondsTotal += ( result.secondsLabeling = timestamp.time() ); //secondsTotal += result.secondsLabeling; //secondsLabeling += result.secondsLabeling; timestamp.reset(); // Update vertex information setVertexInfo(); result.secondsTotal += ( result.secondsAnalysis = timestamp.time() ); timestamp.reset(); timestamp.stop(); result.numVertices = newDT->number_of_vertices(); result.numTetrahedrons = newDT->number_of_cells(); cumulativeResults.secondsTotal += result.secondsTotal; cumulativeResults.secondsMotion += result.secondsMotion; cumulativeResults.secondsCGAL += result.secondsCGAL; cumulativeResults.secondsLabeling += result.secondsLabeling; cumulativeResults.secondsAnalysis += result.secondsAnalysis; return result; }
/** * Sets the new vertex info for the vertices in the new mesh */ void StoneWeatherer::setVertexInfo() { // Clear everything for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { it->info().clear(); } int i; // Label the vertices to keep (those defining boundaries between materials, where "infinite" means "air") for ( All_Cell_iterator it = newDT->all_cells_begin(); it != newDT->all_cells_end(); ++it ) { if ( newDT->is_infinite( it ) ) { for ( i = 0; i < 4; ++i ) { it->vertex( i )->info().flag |= AIR; } } else { for ( i = 0; i < 4; ++i ) { it->vertex( i )->info().flag |= it->info(); } } } // Simplify the labels for mesh simplification later for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { switch ( it->info().flag ) { case AIR | DIRT | ROCK | MORE_ROCK: // border case AIR | DIRT | ROCK: // border case AIR | DIRT | MORE_ROCK: // border case AIR | ROCK | MORE_ROCK: // border case DIRT | ROCK | MORE_ROCK: // border case AIR | ROCK: // border case AIR | DIRT: // border case AIR | MORE_ROCK: // border case ROCK | DIRT: // border case DIRT | MORE_ROCK: // border case ROCK | MORE_ROCK: // border it->info().kill = BORDER; break; default: it->info().kill = FLOATER; } } int n; // Accumulate face normals for border faces for ( Cell_iterator it = newDT->finite_cells_begin(); it != newDT->finite_cells_end(); ++it ) { if ( it->info() != AIR ) { for ( n = 0; n < 4; ++n ) { if ( it->neighbor( n )->info() < it->info() || newDT->is_infinite( it->neighbor( n ) ) ) { Point t0 = it->vertex( n ^ 1 )->point(); Vector s1 = it->vertex( n ^ 2 )->point() - t0; Vector s2 = it->vertex( n ^ 3 )->point() - t0; Vector norm = CGAL::cross_product( s1, s2 ); for ( i = 1; i < 4; ++i ) { it->vertex( n ^ i )->info().normal = it->vertex( n ^ i )->info().normal + norm; } } } } } // Normalize the normals for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { if ( it->info().kill != FLOATER ) { it->info().normal = it->info().normal / sqrt( it->info().normal.squared_length() ); } } // Accumulate the edge curvatures and find range of edge lengths for future stepsize and vertex importance minEdgeLength = -1.0e300; int j; Vector e; double elen2; double curveMult; double importanceMult; double n_dot_e; for ( Cell_iterator it = newDT->finite_cells_begin(); it != newDT->finite_cells_end(); ++it ) { if ( it->info() != AIR ) { for ( n = 0; n < 4; ++n ) { if ( it->neighbor( n )->info() < it->info() || newDT->is_infinite( it->neighbor( n ) ) ) { for ( i = 1; i < 4; ++i ) { for ( j = i + 1; j < 4; ++j ) { e = it->vertex( n ^ i )->point() - it->vertex( n ^ j )->point(); elen2 = e.squared_length(); SETMAX( minEdgeLength, -elen2 ); curveMult = 1.0 / elen2; importanceMult = sqrt( curveMult ); // Geometric importance is edge-length independent n_dot_e = dot( it->vertex( n ^ i )->info().normal, e ); it->vertex( n ^ i )->info().numEdges += 1; it->vertex( n ^ i )->info().curvature += 2.0 * n_dot_e * curveMult; SETMAX( it->vertex( n ^ i )->info().importance, fabs( n_dot_e * importanceMult ) ); } } } } } } minEdgeLength = sqrt( -minEdgeLength ); minCurvature = -1.0e300; maxCurvature = -1.0e300; for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { if ( it->info().numEdges > 0 ) { it->info().curvature /= it->info().numEdges; SETMAX( minCurvature, -it->info().curvature ); SETMAX( maxCurvature, +it->info().curvature ); } } // Colorize the vertices //for ( Vertex_iterator it = newDT->finite_vertices_begin(); it != newDT->finite_vertices_end(); ++it ) { // it->info().rgb[ 0 ] = 0.0; // it->info().rgb[ 1 ] = 0.0; // it->info().rgb[ 2 ] = 0.0; // if ( it->info().flag & ROCK ) { // it->info().rgb[ 2 ] = 1.0; // } // if ( it->info().flag & MORE_ROCK ) { // it->info().rgb[ 0 ] = 1.0; // } //} minCurvature *= -1.0; }