From 736f89026f0015fc79a13f3eff3d332545d02eed Mon Sep 17 00:00:00 2001 From: Garux Date: Mon, 22 Oct 2018 18:36:38 +0300 Subject: [PATCH] use convhull_3d for quicker hull calculation --- libs/convhull_3d.h | 324 ++++++++------------------------------------- radiant/csg.cpp | 84 +++++++----- 2 files changed, 107 insertions(+), 301 deletions(-) diff --git a/libs/convhull_3d.h b/libs/convhull_3d.h index 18be68fe..8951807a 100644 --- a/libs/convhull_3d.h +++ b/libs/convhull_3d.h @@ -1,16 +1,16 @@ /* Copyright (c) 2017-2018 Leo McCormack - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -57,7 +57,7 @@ extern "C" { #endif - + #ifdef CONVHULL_3D_USE_FLOAT_PRECISION typedef float CH_FLOAT; #else @@ -72,7 +72,7 @@ typedef struct _ch_vertex { }; } ch_vertex; typedef ch_vertex ch_vec3; - + /* builds the convexhull, returning the face indices corresponding to "in_vertices" */ void convhull_3d_build(/* input arguments */ ch_vertex* const in_vertices, /* vector of input vertices; nVert x 1 */ @@ -80,30 +80,6 @@ void convhull_3d_build(/* input arguments */ /* output arguments */ int** out_faces, /* & of empty int*, output face indices; flat: nOut_faces x 3 */ int* nOut_faces); /* & of int, number of output face indices */ - -/* exports the vertices, face indices, and face normals, as an 'obj' file, ready for GPU */ -void convhull_3d_export_obj(/* input arguments */ - ch_vertex* const vertices, /* vector of input vertices; nVert x 1 */ - const int nVert, /* number of vertices */ - int* const faces, /* face indices; flat: nFaces x 3 */ - const int nFaces, /* number of faces in hull */ - const int keepOnlyUsedVerticesFLAG, /* 0: exports in_vertices, 1: exports only used vertices */ - char* const obj_filename); /* obj filename, WITHOUT extension */ - -/* exports the vertices, face indices, and face normals, as an 'm' file, for MatLab verification */ -void convhull_3d_export_m(/* input arguments */ - ch_vertex* const vertices, /* vector of input vertices; nVert x 1 */ - const int nVert, /* number of vertices */ - int* const faces, /* face indices; flat: nFaces x 3 */ - const int nFaces, /* number of faces in hull */ - char* const m_filename); /* m filename, WITHOUT extension */ - -/* reads an 'obj' file and extracts only the vertices */ -void extractVerticesFromObjFile(/* input arguments */ - char* const obj_filename, /* obj filename, WITHOUT extension */ - /* output arguments */ - ch_vertex** out_vertices, /* & of empty ch_vertex*, output vertices; out_nVert x 1 */ - int* out_nVert); /* & of int, number of vertices */ #ifdef __cplusplus } /*extern "C"*/ @@ -116,22 +92,11 @@ void extractVerticesFromObjFile(/* input arguments */ * INTERNAL: ***********/ -#ifdef CONVHULL_3D_ENABLE - #include -#include #include #include #include #include -#include -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) - #define CV_STRNCPY(a,b,c) strncpy_s(a,c+1,b,c); - #define CV_STRCAT(a,b) strcat_s(a,sizeof(b),b); -#else - #define CV_STRNCPY(a,b,c) strncpy(a,b,c); - #define CV_STRCAT(a,b) strcat(a,b); -#endif #ifdef CONVHULL_3D_USE_FLOAT_PRECISION #define CH_FLT_MIN FLT_MIN #define CH_FLT_MAX FLT_MAX @@ -167,39 +132,38 @@ static int cmp_asc_int(const void*, const void*); static int cmp_desc_int(const void*, const void*); static void sort_float(CH_FLOAT*, CH_FLOAT*, int*, int, int); static void sort_int(int*, int*, int*, int, int); -static ch_vec3 cross(ch_vec3*, ch_vec3*); static CH_FLOAT det_4x4(CH_FLOAT*); static void plane_3d(CH_FLOAT*, CH_FLOAT*, CH_FLOAT*); static void ismember(int*, int*, int*, int, int); /* internal functions definitions: */ static int cmp_asc_float(const void *a,const void *b) { - struct float_w_idx *a1 = (struct float_w_idx*)a; - struct float_w_idx *a2 = (struct float_w_idx*)b; + const struct float_w_idx *a1 = (const struct float_w_idx*)a; + const struct float_w_idx *a2 = (const struct float_w_idx*)b; if((*a1).val<(*a2).val)return -1; else if((*a1).val>(*a2).val)return 1; else return 0; } static int cmp_desc_float(const void *a,const void *b) { - struct float_w_idx *a1 = (struct float_w_idx*)a; - struct float_w_idx *a2 = (struct float_w_idx*)b; + const struct float_w_idx *a1 = (const struct float_w_idx*)a; + const struct float_w_idx *a2 = (const struct float_w_idx*)b; if((*a1).val>(*a2).val)return -1; else if((*a1).val<(*a2).val)return 1; else return 0; } static int cmp_asc_int(const void *a,const void *b) { - struct int_w_idx *a1 = (struct int_w_idx*)a; - struct int_w_idx *a2 = (struct int_w_idx*)b; + const struct int_w_idx *a1 = (const struct int_w_idx*)a; + const struct int_w_idx *a2 = (const struct int_w_idx*)b; if((*a1).val<(*a2).val)return -1; else if((*a1).val>(*a2).val)return 1; else return 0; } static int cmp_desc_int(const void *a,const void *b) { - struct int_w_idx *a1 = (struct int_w_idx*)a; - struct int_w_idx *a2 = (struct int_w_idx*)b; + const struct int_w_idx *a1 = (const struct int_w_idx*)a; + const struct int_w_idx *a2 = (const struct int_w_idx*)b; if((*a1).val>(*a2).val)return -1; else if((*a1).val<(*a2).val)return 1; else return 0; @@ -216,7 +180,7 @@ static void sort_float { int i; struct float_w_idx *data; - + data = (float_w_idx*)malloc(len*sizeof(float_w_idx)); for(i=0;iy * v2->z - v1->z * v2->y; - cross.y = v1->z * v2->x - v1->x * v2->z; - cross.z = v1->x * v2->y - v1->y * v2->x; - return cross; -} - /* calculates the determinent of a 4x4 matrix */ static CH_FLOAT det_4x4(CH_FLOAT* m) { return @@ -310,7 +265,7 @@ static void plane_3d int r[3]; CH_FLOAT sign, det, norm_c; CH_FLOAT pdiff[2][3], pdiff_s[2][2]; - + for(i=0; i<2; i++) for(j=0; j<3; j++) pdiff[i][j] = p[(i+1)*3+j] - p[i*3+j]; @@ -380,13 +335,13 @@ void convhull_3d_build int* aVec, *faces; CH_FLOAT dfi, v, max_p, min_p; CH_FLOAT* points, *cf, *cfi, *df, *p_s, *span; - + if(nVert<3 || in_vertices==NULL){ (*out_faces) = NULL; (*nOut_faces) = 0; return; } - + /* 3 dimensions. The code should theoretically work for >=2 dimensions, but "plane_3d" and "det_4x4" are hardcoded for 3, * so would need to be rewritten */ d = 3; @@ -405,14 +360,14 @@ void convhull_3d_build points[i*(d+1)+j] = in_vertices[i].v[j] + CH_NOISE_VAL*rand()/(float)RAND_MAX; /* noise mitigates duplicates */ points[i*(d+1)+d] = 1.0f; /* add a last column of ones. Used only for determinant calculation */ } - + /* The initial convex hull is a simplex with (d+1) facets, where d is the number of dimensions */ nFaces = (d+1); faces = (int*)calloc(nFaces*d, sizeof(int)); aVec = (int*)malloc(nFaces*sizeof(int)); for(i=0; i0) ){ /* i is the first point of the points left */ i = pleft[0]; - + /* Delete the point selected */ for(j=0; j4){ - /* not a valid file */ - free((*out_vertices)); - (*out_vertices) = NULL; - (*out_nVert) = 0; - return; - } - (*out_vertices)[i].v[vertID] = atof(vert_char); - memset(vert_char, 0, 256 * sizeof(char)); - } - prev_char_isDigit = current_char_isDigit; - } - i++; - } - } -} -#endif /* CONVHULL_3D_ENABLE */ diff --git a/radiant/csg.cpp b/radiant/csg.cpp index 53dca800..e02a2336 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -1012,6 +1012,9 @@ public: std::size_t size() const { return m_vertices.size(); } + const Vector3& operator[]( std::size_t i ) const { + return m_vertices[i]; + } brushsplit_t classify_plane( const Plane3& plane ) const { brushsplit_t split; for( const_iterator i = begin(); i != end(); ++i ){ @@ -1084,6 +1087,53 @@ public: } }; +#include "convhull_3d.h" +void CSG_build_hull( const MergeVertices& mergeVertices, MergePlanes& mergePlanes ){ +#if 0 + /* bruteforce new planes */ + for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i ) + for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j ) + for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){ + const Plane3 plane = plane3_for_points( *i, *j, *k ); + if( plane3_valid( plane ) ){ + const brushsplit_t split = mergeVertices.classify_plane( plane ); + if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){ + if( split.counts[ePlaneFront] != 0 ) + mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) ); + else + mergePlanes.insert( MergePlane( plane, *i, *k, *j ) ); + } + } + } +#else + const int nVertices = mergeVertices.size(); + ch_vertex* vertices = ( ch_vertex* )malloc( mergeVertices.size() * sizeof( ch_vertex ) ); + for( std::size_t i = 0; i < mergeVertices.size(); ++i ){ + vertices[i].x = static_cast( mergeVertices[i].x() ); + vertices[i].y = static_cast( mergeVertices[i].y() ); + vertices[i].z = static_cast( mergeVertices[i].z() ); + } + int* faceIndices = NULL; + int nFaces; + convhull_3d_build( vertices, nVertices, &faceIndices, &nFaces ); + /* Where 'faceIndices' is a flat 2D matrix [nFaces x 3] */ + for( int i = 0; i < nFaces; ++i ){ + Vector3 p[3]; + for( int j = 0; j < 3; ++j ){ +// p[j] = Vector3( vertices[faceIndices[i * 3 + j]].x, vertices[faceIndices[i * 3 + j]].y, vertices[faceIndices[i * 3 + j]].z ); + p[j] = mergeVertices[faceIndices[i * 3 + j]]; + } + const Plane3 plane = plane3_for_points( p[0], p[1], p[2] ); + if( plane3_valid( plane ) ){ + mergePlanes.insert( MergePlane( plane, p[0], p[2], p[1] ) ); + } + } + + free( vertices ); + free( faceIndices ); +#endif +} + void CSG_WrapMerge( const ClipperPoints& clipperPoints ){ const bool primit = ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ); brush_vector_t selected_brushes; @@ -1127,21 +1177,8 @@ void CSG_WrapMerge( const ClipperPoints& clipperPoints ){ mergePlanes.insert( MergePlane( face.getPlane().plane3(), &face ) ); } } - /* bruteforce new planes */ - for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i ) - for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j ) - for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){ - const Plane3 plane = plane3_for_points( *i, *j, *k ); - if( plane3_valid( plane ) ){ - const brushsplit_t split = mergeVertices.classify_plane( plane ); - if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){ - if( split.counts[ePlaneFront] != 0 ) - mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) ); - else - mergePlanes.insert( MergePlane( plane, *i, *k, *j ) ); - } - } - } + + CSG_build_hull( mergeVertices, mergePlanes ); //globalOutputStream() << mergePlanes.size() << " mergePlanes.size()\n"; if( mergePlanes.size() < 4 ){ @@ -1242,21 +1279,8 @@ void CSG_DeleteComponents(){ } } - /* bruteforce new planes */ - for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i ) - for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j ) - for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){ - const Plane3 plane = plane3_for_points( *i, *j, *k ); - if( plane3_valid( plane ) ){ - const brushsplit_t split = mergeVertices.classify_plane( plane ); - if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){ - if( split.counts[ePlaneFront] != 0 ) - mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) ); - else - mergePlanes.insert( MergePlane( plane, *i, *k, *j ) ); - } - } - } + CSG_build_hull( mergeVertices, mergePlanes ); + if( mergePlanes.size() < 4 ){ globalWarningStream() << "CSG_DeleteComponents: Too few planes left: " << mergePlanes.size() << ".\n"; return;