diff options
Diffstat (limited to 'tests/bullet/Extras/ConvexDecomposition/concavity.cpp')
-rw-r--r-- | tests/bullet/Extras/ConvexDecomposition/concavity.cpp | 795 |
1 files changed, 795 insertions, 0 deletions
diff --git a/tests/bullet/Extras/ConvexDecomposition/concavity.cpp b/tests/bullet/Extras/ConvexDecomposition/concavity.cpp new file mode 100644 index 00000000..f1a46600 --- /dev/null +++ b/tests/bullet/Extras/ConvexDecomposition/concavity.cpp @@ -0,0 +1,795 @@ +#include "float_math.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <vector> + +/*---------------------------------------------------------------------- + Copyright (c) 2004 Open Dynamics Framework Group + www.physicstools.org + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided + that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + Neither the name of the Open Dynamics Framework Group nor the names of its contributors may + be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-----------------------------------------------------------------------*/ + +// http://codesuppository.blogspot.com +// +// mailto: jratcliff@infiniplex.net +// +// http://www.amillionpixels.us +// + +#include "concavity.h" +#include "raytri.h" +#include "bestfit.h" +#include "cd_hull.h" +#include "meshvolume.h" +#include "cd_vector.h" +#include "splitplane.h" +#include "ConvexDecomposition.h" + + +#define WSCALE 4 +#define CONCAVE_THRESH 0.05f + +namespace ConvexDecomposition +{ + +unsigned int getDebugColor(void) +{ + static unsigned int colors[8] = + { + 0xFF0000, + 0x00FF00, + 0x0000FF, + 0xFFFF00, + 0x00FFFF, + 0xFF00FF, + 0xFFFFFF, + 0xFF8040 + }; + + static int count = 0; + + count++; + + if ( count == 8 ) count = 0; + + assert( count >= 0 && count < 8 ); + + unsigned int color = colors[count]; + + return color; + +} + +class Wpoint +{ +public: + Wpoint(const Vector3d &p,float w) + { + mPoint = p; + mWeight = w; + } + + Vector3d mPoint; + float mWeight; +}; + +typedef std::vector< Wpoint > WpointVector; + + +static inline float DistToPt(const float *p,const float *plane) +{ + float x = p[0]; + float y = p[1]; + float z = p[2]; + float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3]; + return d; +} + + +static void intersect(const float *p1,const float *p2,float *split,const float *plane) +{ + + float dp1 = DistToPt(p1,plane); + + float dir[3]; + + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + + float dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2]; + float dot2 = dp1 - plane[3]; + + float t = -(plane[3] + dot2 ) / dot1; + + split[0] = (dir[0]*t)+p1[0]; + split[1] = (dir[1]*t)+p1[1]; + split[2] = (dir[2]*t)+p1[2]; +} + + +class CTri +{ +public: + CTri(void) { }; + + CTri(const float *p1,const float *p2,const float *p3,unsigned int i1,unsigned int i2,unsigned int i3) + { + mProcessed = 0; + mI1 = i1; + mI2 = i2; + mI3 = i3; + + mP1.Set(p1); + mP2.Set(p2); + mP3.Set(p3); + + mPlaneD = mNormal.ComputePlane(mP1,mP2,mP3); + } + + float Facing(const CTri &t) + { + float d = mNormal.Dot(t.mNormal); + return d; + } + + // clip this line segment against this triangle. + bool clip(const Vector3d &start,Vector3d &end) const + { + Vector3d sect; + + bool hit = lineIntersectsTriangle(start.Ptr(), end.Ptr(), mP1.Ptr(), mP2.Ptr(), mP3.Ptr(), sect.Ptr() ); + + if ( hit ) + { + end = sect; + } + return hit; + } + + bool Concave(const Vector3d &p,float &distance,Vector3d &n) const + { + n.NearestPointInTriangle(p,mP1,mP2,mP3); + distance = p.Distance(n); + return true; + } + + void addTri(unsigned int *indices,unsigned int i1,unsigned int i2,unsigned int i3,unsigned int &tcount) const + { + indices[tcount*3+0] = i1; + indices[tcount*3+1] = i2; + indices[tcount*3+2] = i3; + tcount++; + } + + float getVolume(ConvexDecompInterface *callback) const + { + unsigned int indices[8*3]; + + + unsigned int tcount = 0; + + addTri(indices,0,1,2,tcount); + addTri(indices,3,4,5,tcount); + + addTri(indices,0,3,4,tcount); + addTri(indices,0,4,1,tcount); + + addTri(indices,1,4,5,tcount); + addTri(indices,1,5,2,tcount); + + addTri(indices,0,3,5,tcount); + addTri(indices,0,5,2,tcount); + + const float *vertices = mP1.Ptr(); + + if ( callback ) + { + unsigned int color = getDebugColor(); + +#if 0 + Vector3d d1 = mNear1; + Vector3d d2 = mNear2; + Vector3d d3 = mNear3; + + callback->ConvexDebugPoint(mP1.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(mP2.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(mP3.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(d1.Ptr(),0.01f,0xFF0000); + callback->ConvexDebugPoint(d2.Ptr(),0.01f,0xFF0000); + callback->ConvexDebugPoint(d3.Ptr(),0.01f,0xFF0000); + + callback->ConvexDebugTri(mP1.Ptr(), d1.Ptr(), d1.Ptr(),0x00FF00); + callback->ConvexDebugTri(mP2.Ptr(), d2.Ptr(), d2.Ptr(),0x00FF00); + callback->ConvexDebugTri(mP3.Ptr(), d3.Ptr(), d3.Ptr(),0x00FF00); + +#else + for (unsigned int i=0; i<tcount; i++) + { + unsigned int i1 = indices[i*3+0]; + unsigned int i2 = indices[i*3+1]; + unsigned int i3 = indices[i*3+2]; + + const float *p1 = &vertices[ i1*3 ]; + const float *p2 = &vertices[ i2*3 ]; + const float *p3 = &vertices[ i3*3 ]; + + callback->ConvexDebugTri(p1,p2,p3,color); + + } +#endif + } + + float v = computeMeshVolume(mP1.Ptr(), tcount, indices ); + + return v; + + } + + float raySect(const Vector3d &p,const Vector3d &dir,Vector3d §) const + { + float plane[4]; + + plane[0] = mNormal.x; + plane[1] = mNormal.y; + plane[2] = mNormal.z; + plane[3] = mPlaneD; + + Vector3d dest = p+dir*100000; + + intersect( p.Ptr(), dest.Ptr(), sect.Ptr(), plane ); + + return sect.Distance(p); // return the intersection distance. + + } + + float planeDistance(const Vector3d &p) const + { + float plane[4]; + + plane[0] = mNormal.x; + plane[1] = mNormal.y; + plane[2] = mNormal.z; + plane[3] = mPlaneD; + + return DistToPt( p.Ptr(), plane ); + + } + + bool samePlane(const CTri &t) const + { + const float THRESH = 0.001f; + float dd = fabsf( t.mPlaneD - mPlaneD ); + if ( dd > THRESH ) return false; + dd = fabsf( t.mNormal.x - mNormal.x ); + if ( dd > THRESH ) return false; + dd = fabsf( t.mNormal.y - mNormal.y ); + if ( dd > THRESH ) return false; + dd = fabsf( t.mNormal.z - mNormal.z ); + if ( dd > THRESH ) return false; + return true; + } + + bool hasIndex(unsigned int i) const + { + if ( i == mI1 || i == mI2 || i == mI3 ) return true; + return false; + } + + bool sharesEdge(const CTri &t) const + { + bool ret = false; + unsigned int count = 0; + + if ( t.hasIndex(mI1) ) count++; + if ( t.hasIndex(mI2) ) count++; + if ( t.hasIndex(mI3) ) count++; + + if ( count >= 2 ) ret = true; + + return ret; + } + + void debug(unsigned int color,ConvexDecompInterface *callback) + { + callback->ConvexDebugTri( mP1.Ptr(), mP2.Ptr(), mP3.Ptr(), color ); + callback->ConvexDebugTri( mP1.Ptr(), mP1.Ptr(), mNear1.Ptr(), 0xFF0000 ); + callback->ConvexDebugTri( mP2.Ptr(), mP2.Ptr(), mNear2.Ptr(), 0xFF0000 ); + callback->ConvexDebugTri( mP2.Ptr(), mP3.Ptr(), mNear3.Ptr(), 0xFF0000 ); + callback->ConvexDebugPoint( mNear1.Ptr(), 0.01f, 0xFF0000 ); + callback->ConvexDebugPoint( mNear2.Ptr(), 0.01f, 0xFF0000 ); + callback->ConvexDebugPoint( mNear3.Ptr(), 0.01f, 0xFF0000 ); + } + + float area(void) + { + float a = mConcavity*mP1.Area(mP2,mP3); + return a; + } + + void addWeighted(WpointVector &list,ConvexDecompInterface *callback) + { + + Wpoint p1(mP1,mC1); + Wpoint p2(mP2,mC2); + Wpoint p3(mP3,mC3); + + Vector3d d1 = mNear1 - mP1; + Vector3d d2 = mNear2 - mP2; + Vector3d d3 = mNear3 - mP3; + + d1*=WSCALE; + d2*=WSCALE; + d3*=WSCALE; + + d1 = d1 + mP1; + d2 = d2 + mP2; + d3 = d3 + mP3; + + Wpoint p4(d1,mC1); + Wpoint p5(d2,mC2); + Wpoint p6(d3,mC3); + + list.push_back(p1); + list.push_back(p2); + list.push_back(p3); + + list.push_back(p4); + list.push_back(p5); + list.push_back(p6); + +#if 0 + callback->ConvexDebugPoint(mP1.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(mP2.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(mP3.Ptr(),0.01f,0x00FF00); + callback->ConvexDebugPoint(d1.Ptr(),0.01f,0xFF0000); + callback->ConvexDebugPoint(d2.Ptr(),0.01f,0xFF0000); + callback->ConvexDebugPoint(d3.Ptr(),0.01f,0xFF0000); + + callback->ConvexDebugTri(mP1.Ptr(), d1.Ptr(), d1.Ptr(),0x00FF00); + callback->ConvexDebugTri(mP2.Ptr(), d2.Ptr(), d2.Ptr(),0x00FF00); + callback->ConvexDebugTri(mP3.Ptr(), d3.Ptr(), d3.Ptr(),0x00FF00); + + Vector3d np1 = mP1 + mNormal*0.05f; + Vector3d np2 = mP2 + mNormal*0.05f; + Vector3d np3 = mP3 + mNormal*0.05f; + + callback->ConvexDebugTri(mP1.Ptr(), np1.Ptr(), np1.Ptr(), 0xFF00FF ); + callback->ConvexDebugTri(mP2.Ptr(), np2.Ptr(), np2.Ptr(), 0xFF00FF ); + callback->ConvexDebugTri(mP3.Ptr(), np3.Ptr(), np3.Ptr(), 0xFF00FF ); + + callback->ConvexDebugPoint( np1.Ptr(), 0.01F, 0XFF00FF ); + callback->ConvexDebugPoint( np2.Ptr(), 0.01F, 0XFF00FF ); + callback->ConvexDebugPoint( np3.Ptr(), 0.01F, 0XFF00FF ); + +#endif + + + + } + + Vector3d mP1; + Vector3d mP2; + Vector3d mP3; + Vector3d mNear1; + Vector3d mNear2; + Vector3d mNear3; + Vector3d mNormal; + float mPlaneD; + float mConcavity; + float mC1; + float mC2; + float mC3; + unsigned int mI1; + unsigned int mI2; + unsigned int mI3; + int mProcessed; // already been added... +}; + +typedef std::vector< CTri > CTriVector; + +bool featureMatch(CTri &m,const CTriVector &tris,ConvexDecompInterface *callback,const CTriVector &input_mesh) +{ + + bool ret = false; + + float neardot = 0.707f; + + m.mConcavity = 0; + + //gLog->Display("*********** FEATURE MATCH *************\r\n"); + //gLog->Display("Plane: %0.4f,%0.4f,%0.4f %0.4f\r\n", m.mNormal.x, m.mNormal.y, m.mNormal.z, m.mPlaneD ); + //gLog->Display("*********************************************\r\n"); + + CTriVector::const_iterator i; + + CTri nearest; + + + for (i=tris.begin(); i!=tris.end(); ++i) + { + const CTri &t = (*i); + + + //gLog->Display(" HullPlane: %0.4f,%0.4f,%0.4f %0.4f\r\n", t.mNormal.x, t.mNormal.y, t.mNormal.z, t.mPlaneD ); + + if ( t.samePlane(m) ) + { + //gLog->Display("*** PLANE MATCH!!!\r\n"); + ret = false; + break; + } + + float dot = t.mNormal.Dot(m.mNormal); + + if ( dot > neardot ) + { + + float d1 = t.planeDistance( m.mP1 ); + float d2 = t.planeDistance( m.mP2 ); + float d3 = t.planeDistance( m.mP3 ); + + if ( d1 > 0.001f || d2 > 0.001f || d3 > 0.001f ) // can't be near coplaner! + { + + neardot = dot; + + Vector3d n1,n2,n3; + + t.raySect( m.mP1, m.mNormal, m.mNear1 ); + t.raySect( m.mP2, m.mNormal, m.mNear2 ); + t.raySect( m.mP3, m.mNormal, m.mNear3 ); + + nearest = t; + + ret = true; + } + + } + } + + if ( ret ) + { + if ( 0 ) + { + CTriVector::const_iterator i; + for (i=input_mesh.begin(); i!=input_mesh.end(); ++i) + { + const CTri &c = (*i); + if ( c.mI1 != m.mI1 && c.mI2 != m.mI2 && c.mI3 != m.mI3 ) + { + c.clip( m.mP1, m.mNear1 ); + c.clip( m.mP2, m.mNear2 ); + c.clip( m.mP3, m.mNear3 ); + } + } + } + + //gLog->Display("*********************************************\r\n"); + //gLog->Display(" HullPlaneNearest: %0.4f,%0.4f,%0.4f %0.4f\r\n", nearest.mNormal.x, nearest.mNormal.y, nearest.mNormal.z, nearest.mPlaneD ); + + m.mC1 = m.mP1.Distance( m.mNear1 ); + m.mC2 = m.mP2.Distance( m.mNear2 ); + m.mC3 = m.mP3.Distance( m.mNear3 ); + + m.mConcavity = m.mC1; + + if ( m.mC2 > m.mConcavity ) m.mConcavity = m.mC2; + if ( m.mC3 > m.mConcavity ) m.mConcavity = m.mC3; + + #if 0 + callback->ConvexDebugTri( m.mP1.Ptr(), m.mP2.Ptr(), m.mP3.Ptr(), 0x00FF00 ); + callback->ConvexDebugTri( m.mNear1.Ptr(), m.mNear2.Ptr(), m.mNear3.Ptr(), 0xFF0000 ); + + callback->ConvexDebugTri( m.mP1.Ptr(), m.mP1.Ptr(), m.mNear1.Ptr(), 0xFFFF00 ); + callback->ConvexDebugTri( m.mP2.Ptr(), m.mP2.Ptr(), m.mNear2.Ptr(), 0xFFFF00 ); + callback->ConvexDebugTri( m.mP3.Ptr(), m.mP3.Ptr(), m.mNear3.Ptr(), 0xFFFF00 ); + #endif + + } + else + { + //gLog->Display("No match\r\n"); + } + + //gLog->Display("*********************************************\r\n"); + return ret; +} + +bool isFeatureTri(CTri &t,CTriVector &flist,float fc,ConvexDecompInterface *callback,unsigned int color) +{ + bool ret = false; + + if ( t.mProcessed == 0 ) // if not already processed + { + + float c = t.mConcavity / fc; // must be within 80% of the concavity of the parent. + + if ( c > 0.85f ) + { + // see if this triangle is a 'feature' triangle. Meaning it shares an + // edge with any existing feature triangle and is within roughly the same + // concavity of the parent. + if ( flist.size() ) + { + CTriVector::iterator i; + for (i=flist.begin(); i!=flist.end(); ++i) + { + CTri &ftri = (*i); + if ( ftri.sharesEdge(t) ) + { + t.mProcessed = 2; // it is now part of a feature. + flist.push_back(t); // add it to the feature list. +// callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(),t.mP3.Ptr(), color ); + ret = true; + break; + } + } + } + else + { + t.mProcessed = 2; + flist.push_back(t); // add it to the feature list. +// callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(),t.mP3.Ptr(), color ); + ret = true; + } + } + else + { + t.mProcessed = 1; // eliminated for this feature, but might be valid for the next one.. + } + + } + return ret; +} + +float computeConcavity(unsigned int vcount, + const float *vertices, + unsigned int tcount, + const unsigned int *indices, + ConvexDecompInterface *callback, + float *plane, // plane equation to split on + float &volume) +{ + + + float cret = 0; + volume = 1; + + HullResult result; + HullLibrary hl; + HullDesc desc; + + desc.mMaxFaces = 256; + desc.mMaxVertices = 256; + desc.SetHullFlag(QF_TRIANGLES); + + + desc.mVcount = vcount; + desc.mVertices = vertices; + desc.mVertexStride = sizeof(float)*3; + + HullError ret = hl.CreateConvexHull(desc,result); + + if ( ret == QE_OK ) + { +#if 0 + float bmin[3]; + float bmax[3]; + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + Vector3d center; + + center.x = bmin[0] + dx*0.5f; + center.y = bmin[1] + dy*0.5f; + center.z = bmin[2] + dz*0.5f; +#endif + + volume = computeMeshVolume2( result.mOutputVertices, result.mNumFaces, result.mIndices ); + +#if 1 + // ok..now..for each triangle on the original mesh.. + // we extrude the points to the nearest point on the hull. + const unsigned int *source = result.mIndices; + + CTriVector tris; + + for (unsigned int i=0; i<result.mNumFaces; i++) + { + unsigned int i1 = *source++; + unsigned int i2 = *source++; + unsigned int i3 = *source++; + + const float *p1 = &result.mOutputVertices[i1*3]; + const float *p2 = &result.mOutputVertices[i2*3]; + const float *p3 = &result.mOutputVertices[i3*3]; + +// callback->ConvexDebugTri(p1,p2,p3,0xFFFFFF); + + CTri t(p1,p2,p3,i1,i2,i3); // + tris.push_back(t); + } + + // we have not pre-computed the plane equation for each triangle in the convex hull.. + + float totalVolume = 0; + + CTriVector ftris; // 'feature' triangles. + + const unsigned int *src = indices; + + + float maxc=0; + + + if ( 1 ) + { + CTriVector input_mesh; + if ( 1 ) + { + const unsigned int *src = indices; + for (unsigned int i=0; i<tcount; i++) + { + + unsigned int i1 = *src++; + unsigned int i2 = *src++; + unsigned int i3 = *src++; + + const float *p1 = &vertices[i1*3]; + const float *p2 = &vertices[i2*3]; + const float *p3 = &vertices[i3*3]; + + CTri t(p1,p2,p3,i1,i2,i3); + input_mesh.push_back(t); + } + } + + CTri maxctri; + + for (unsigned int i=0; i<tcount; i++) + { + + unsigned int i1 = *src++; + unsigned int i2 = *src++; + unsigned int i3 = *src++; + + const float *p1 = &vertices[i1*3]; + const float *p2 = &vertices[i2*3]; + const float *p3 = &vertices[i3*3]; + + CTri t(p1,p2,p3,i1,i2,i3); + + featureMatch(t, tris, callback, input_mesh ); + + if ( t.mConcavity > CONCAVE_THRESH ) + { + + if ( t.mConcavity > maxc ) + { + maxc = t.mConcavity; + maxctri = t; + } + + float v = t.getVolume(0); + totalVolume+=v; + ftris.push_back(t); + } + + } + } + + if ( ftris.size() && 0 ) + { + + // ok..now we extract the triangles which form the maximum concavity. + CTriVector major_feature; + float maxarea = 0; + + while ( maxc > CONCAVE_THRESH ) + { + + unsigned int color = getDebugColor(); // + + CTriVector flist; + + bool found; + + float totalarea = 0; + + do + { + found = false; + CTriVector::iterator i; + for (i=ftris.begin(); i!=ftris.end(); ++i) + { + CTri &t = (*i); + if ( isFeatureTri(t,flist,maxc,callback,color) ) + { + found = true; + totalarea+=t.area(); + } + } + } while ( found ); + + + if ( totalarea > maxarea ) + { + major_feature = flist; + maxarea = totalarea; + } + + maxc = 0; + + for (unsigned int i=0; i<ftris.size(); i++) + { + CTri &t = ftris[i]; + if ( t.mProcessed != 2 ) + { + t.mProcessed = 0; + if ( t.mConcavity > maxc ) + { + maxc = t.mConcavity; + } + } + } + } + + unsigned int color = getDebugColor(); + + WpointVector list; + for (unsigned int i=0; i<major_feature.size(); ++i) + { + major_feature[i].addWeighted(list,callback); + major_feature[i].debug(color,callback); + } + + getBestFitPlane( list.size(), &list[0].mPoint.x, sizeof(Wpoint), &list[0].mWeight, sizeof(Wpoint), plane ); + + computeSplitPlane( vcount, vertices, tcount, indices, callback, plane ); + + + } + else + { + computeSplitPlane( vcount, vertices, tcount, indices, callback, plane ); + } +#endif + + cret = totalVolume; + + hl.ReleaseResult(result); + } + + + return cret; +} + + +} |