#include "ConvexHull.h" #include "dgConvexHull3d.h" #include "WuQuantizer.h" #include "ApexUsingNamespace.h" /*! ** ** Copyright (c) 2015 by John W. Ratcliff mailto:jratcliffscarab@gmail.com ** ** ** The MIT license: ** ** 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 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ** If you find this code snippet useful; you can tip me at this bitcoin address: ** ** BITCOIN TIP JAR: "1BT66EoaGySkbY9J6MugvQRhMMXDwPxPya" ** */ #include #include #include using namespace hacd; namespace HACD { HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request HullResult &result) // contains the resulst { HullError ret = QE_FAIL; uint32_t vcount = desc.mVcount; if ( vcount < 8 ) vcount = 8; float *vsource = (float *) HACD_ALLOC( sizeof(float)*vcount*3 ); float scale[3]; float center[3]; uint32_t ovcount; bool ok = NormalizeAndCleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, vsource, desc.mNormalEpsilon, scale, center, desc.mMaxVertices*2, desc.mUseWuQuantizer ); // normalize point cloud, remove duplicates! if ( ok ) { double *bigVertices = (double *)HACD_ALLOC(sizeof(double)*3*ovcount); for (uint32_t i=0; i<3*ovcount; i++) { bigVertices[i] = vsource[i]; } dgConvexHull3d convexHull(bigVertices,sizeof(double)*3,(int32_t)ovcount,0.0001f,(int32_t)desc.mMaxVertices); if ( convexHull.GetCount() ) { float *hullVertices = (float *)HACD_ALLOC( sizeof(float)*3*convexHull.GetVertexCount() ); float *dest = hullVertices; for (int32_t i=0; i::Iterator iter(convexHull); uint32_t outCount = 0; for (iter.Begin(); iter; iter++) { dgConvexHull3DFace &face = (*iter); destIndices[0] = (uint32_t)face.m_index[0]; destIndices[1] = (uint32_t)face.m_index[1]; destIndices[2] = (uint32_t)face.m_index[2]; destIndices+=3; outCount++; } HACD_ASSERT( outCount == triangleCount ); // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table. float *vscratch = (float *) HACD_ALLOC( sizeof(float)*convexHull.GetVertexCount()*3 ); BringOutYourDead(hullVertices,(uint32_t)convexHull.GetVertexCount(),vscratch, ovcount, indices, triangleCount*3 ); ret = QE_OK; result.mNumOutputVertices = ovcount; result.mOutputVertices = (float *)HACD_ALLOC( sizeof(float)*ovcount*3); result.mNumTriangles = triangleCount; result.mIndices = (uint32_t *) HACD_ALLOC( sizeof(uint32_t)*triangleCount*3); memcpy(result.mOutputVertices, vscratch, sizeof(float)*3*ovcount ); memcpy(result.mIndices, indices, sizeof(uint32_t)*triangleCount*3); HACD_FREE(indices); HACD_FREE(vscratch); HACD_FREE(hullVertices); } HACD_FREE(bigVertices); } HACD_FREE(vsource); return ret; } HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it. { if ( result.mOutputVertices ) { HACD_FREE(result.mOutputVertices); result.mOutputVertices = 0; } if ( result.mIndices ) { HACD_FREE(result.mIndices); result.mIndices = 0; } return QE_OK; } bool HullLibrary::NormalizeAndCleanupVertices(uint32_t svcount, const float *svertices, uint32_t /*stride*/, uint32_t &vcount, // output number of vertices float *vertices, // location to store the results. float /*normalepsilon*/, float *scale, float *center, uint32_t maxVertices, bool useWuQuantizer) { bool ret = false; WuQuantizer *wq = createWuQuantizer(); if ( wq ) { const float *quantizedVertices; if ( useWuQuantizer ) { quantizedVertices = wq->wuQuantize3D(svcount,svertices,false,maxVertices,vcount); } else { quantizedVertices = wq->kmeansQuantize3D(svcount,svertices,false,maxVertices,vcount); } if ( quantizedVertices ) { memcpy(vertices,quantizedVertices,sizeof(float)*3*vcount); const float *_scale = wq->getDenormalizeScale(); scale[0] = _scale[0]; scale[1] = _scale[1]; scale[2] = _scale[2]; const float *_center = wq->getDenormalizeCenter(); center[0] = _center[0]; center[1] = _center[1]; center[2] = _center[2]; ret = true; } wq->release(); } return ret; } void HullLibrary::BringOutYourDead(const float *verts,uint32_t vcount, float *overts,uint32_t &ocount,uint32_t *indices,uint32_t indexcount) { uint32_t *used = (uint32_t *)HACD_ALLOC(sizeof(uint32_t)*vcount); memset(used,0,sizeof(uint32_t)*vcount); ocount = 0; for (uint32_t i=0; iConvexHullTriangle(v3,v2,v1); } //================================================================================== float HullLibrary::ComputeNormal(float *n,const float *A,const float *B,const float *C) { float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag; vx = (B[0] - C[0]); vy = (B[1] - C[1]); vz = (B[2] - C[2]); wx = (A[0] - B[0]); wy = (A[1] - B[1]); wz = (A[2] - B[2]); vw_x = vy * wz - vz * wy; vw_y = vz * wx - vx * wz; vw_z = vx * wy - vy * wx; mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); if ( mag < 0.000001f ) { mag = 0; } else { mag = 1.0f/mag; } n[0] = vw_x * mag; n[1] = vw_y * mag; n[2] = vw_z * mag; return mag; } }; // End of namespace HACD