diff --git a/pyfqmr/Simplify.h b/pyfqmr/Simplify.h index 6e6fcbc..f709b13 100644 --- a/pyfqmr/Simplify.h +++ b/pyfqmr/Simplify.h @@ -7,7 +7,7 @@ // License : MIT // http://opensource.org/licenses/MIT // -//https://github.com/sp4cerat/Fast-Quadric-Mesh-S; +//https://github.com/sp4cerat/Fast-Quadric-Mesh-S; // 5/2016: Chris Rorden created minimal version for OSX/Linux/Windows compile //#include @@ -341,8 +341,8 @@ namespace Simplify // more iterations yield higher quality // - void simplify_mesh(int target_count, int update_rate=5, double agressiveness=7, - bool verbose=false, int max_iterations=100, double alpha = 0.000000001, + void simplify_mesh(int target_count, int update_rate=5, double agressiveness=7, + void (*log)(char*, int)=NULL, int max_iterations=100, double alpha = 0.000000001, int K = 3, bool lossless=false, double threshold_lossless = 0.0001, bool preserve_border = false) { @@ -381,8 +381,10 @@ namespace Simplify if(lossless) threshold = threshold_lossless ; // target number of triangles reached ? Then break - if ((verbose) && (iteration%5==0)) { - printf("iteration %d - triangles %d threshold %g\n",iteration,triangle_count-deleted_triangles, threshold); + if ((log) && (iteration%5==0)) { + char message[128]; + snprintf(message, 127, "iteration %d - triangles %d threshold %g",iteration,triangle_count-deleted_triangles, threshold); + log(message, 128); } // remove vertices & mark deleted triangles @@ -397,7 +399,7 @@ namespace Simplify { int i0=t.v[ j ]; Vertex &v0 = vertices[i0]; int i1=t.v[(j+1)%3]; Vertex &v1 = vertices[i1]; - // Border check //Added preserve_border method from issue 14 + // Border check //Added preserve_border method from issue 14 if(preserve_border){ if (v0.border || v1.border) continue; // should keep border vertices } @@ -442,9 +444,9 @@ namespace Simplify break; } // done? - if (lossless && (deleted_triangles<=0)){ break; + if (lossless && (deleted_triangles<=0)){ break; } else if (!lossless && (triangle_count-deleted_triangles<=target_count)){break;} - + if (lossless) deleted_triangles = 0; } } @@ -452,10 +454,10 @@ namespace Simplify compact_mesh(); } //simplify_mesh() - void simplify_mesh_lossless(bool verbose=false, double epsilon=1e-3, int max_iterations = 9999) + void simplify_mesh_lossless(void (*log)(char*, int)=NULL, double epsilon=1e-3, int max_iterations = 9999) { // init - loopi(0,triangles.size()) + loopi(0,triangles.size()) { triangles[i].deleted=0; } @@ -478,8 +480,10 @@ namespace Simplify // If it does not, try to adjust the 3 parameters // double threshold = epsilon; //1.0E-3 EPS; - if (verbose) { - printf("lossless iteration %d\n", iteration); + if (log) { + char message[128]; + snprintf(message, 127, "lossless iteration %d\n", iteration); + log(message, 128); } // remove vertices & mark deleted triangles @@ -1113,4 +1117,4 @@ namespace Simplify fclose(file); } }; -/////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////// diff --git a/pyfqmr/Simplify.pyx b/pyfqmr/Simplify.pyx index 829aafe..e38ef0e 100644 --- a/pyfqmr/Simplify.pyx +++ b/pyfqmr/Simplify.pyx @@ -21,14 +21,20 @@ _REF = _hidden_ref() cdef extern from "Simplify.h" namespace "Simplify" : void simplify_mesh( int target_count, int update_rate, double aggressiveness, - bool verbose, int max_iterations,double alpha, int K, + void (*log)(char*, int), int max_iterations,double alpha, int K, bool lossless, double threshold_lossless, bool preserve_border) - void simplify_mesh_lossless(bool verbose, double epsilon, int max_iterations) + void simplify_mesh_lossless(void (*log)(char*, int), double epsilon, int max_iterations) void setMeshFromExt(vector[vector[double]] vertices, vector[vector[int]] faces) vector[vector[int]] getFaces() vector[vector[double]] getVertices() vector[vector[double]] getNormals() +cdef void log_message(char* message, int length) noexcept: + if message is not NULL: + from logging import getLogger + + getLogger("pyfqmr").debug(message.decode("utf-8")) + cdef class Simplify : cdef int[:,:] faces_mv @@ -144,15 +150,24 @@ cdef class Simplify : ---- threshold = alpha*pow( iteration + K, agressiveness) """ + + cdef void (*log)(char*, int) noexcept + + log = NULL + if verbose: + log = log_message + N_start = self.faces_mv.shape[0] t_start = _time() - simplify_mesh(target_count, update_rate, aggressiveness, verbose, max_iterations, alpha, K, + simplify_mesh(target_count, update_rate, aggressiveness, log, max_iterations, alpha, K, lossless, threshold_lossless, preserve_border) t_end = _time() N_end = getFaces().size() if verbose: - print('simplified mesh in {} seconds from {} to {} triangles'.format( + from logging import getLogger + + getLogger("pyfqmr").debug('simplified mesh in {} seconds from {} to {} triangles'.format( round(t_end-t_start,4), N_start, N_end) ) @@ -168,14 +183,22 @@ cdef class Simplify : max_iterations : int Maximum number of iterations """ + cdef void (*log)(char*, int) noexcept + + log = NULL + if verbose: + log = log_message + N_start = self.faces_mv.shape[0] t_start = _time() - simplify_mesh_lossless(verbose, epsilon, max_iterations) + simplify_mesh_lossless(log, epsilon, max_iterations) t_end = _time() N_end = getFaces().size() if verbose: - print('simplified mesh in {} seconds from {} to {} triangles'.format( + from logging import getLogger + + getLogger("pyfqmr").debug('simplified mesh in {} seconds from {} to {} triangles'.format( round(t_end-t_start,4), N_start, N_end) ) diff --git a/tests/test_simplify.py b/tests/test_simplify.py index 32421d0..677ebae 100644 --- a/tests/test_simplify.py +++ b/tests/test_simplify.py @@ -1,3 +1,4 @@ +from logging import root as root_logger, DEBUG from pathlib import Path import pytest @@ -5,6 +6,8 @@ import numpy as np +root_logger.setLevel(DEBUG) + # Get the /example folder at the root of this repo EXAMPLES_DIR = Path(__file__, "..", "..", "example").resolve() @@ -15,7 +18,7 @@ def test_example(): simp.setMesh(bunny.vertices, bunny.faces) simp.simplify_mesh(len(bunny.faces) // 2) vertices, faces, normals = simp.getMesh() - + assert len(faces) / len(bunny.faces) == pytest.approx(.5, rel=.05) simplified = tr.Trimesh(vertices, faces, normals) assert simplified.area == pytest.approx(simplified.area, rel=.05) @@ -28,7 +31,7 @@ def test_empty(): simp.setMesh(verts, faces) simp.simplify_mesh() vertices, faces, normals = simp.getMesh() - + assert len(vertices) == 0 assert len(faces) == 0 - assert len(normals) == 0 \ No newline at end of file + assert len(normals) == 0