moving convex_decomposition/ ivcon/ simmechanics_to_urdf/ to robot_model_tools

This commit is contained in:
Ioan Sucan 2012-08-02 17:53:32 -07:00
parent 0bbe586ef5
commit 36c696acab
50 changed files with 0 additions and 34838 deletions

View File

@ -1,249 +0,0 @@
#ifndef CONVEX_DECOMPOSITION_H
#define CONVEX_DECOMPOSITION_H
namespace ConvexDecomposition
{
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
class ConvexResult
{
public:
ConvexResult(void)
{
mHullVcount = 0;
mHullVertices = 0;
mHullTcount = 0;
mHullIndices = 0;
}
ConvexResult(unsigned int hvcount,const double *hvertices,unsigned int htcount,const unsigned int *hindices)
{
mHullVcount = hvcount;
if ( mHullVcount )
{
mHullVertices = new double[mHullVcount*sizeof(double)*3];
memcpy(mHullVertices, hvertices, sizeof(double)*3*mHullVcount );
}
else
{
mHullVertices = 0;
}
mHullTcount = htcount;
if ( mHullTcount )
{
mHullIndices = new unsigned int[sizeof(unsigned int)*mHullTcount*3];
memcpy(mHullIndices,hindices, sizeof(unsigned int)*mHullTcount*3 );
}
else
{
mHullIndices = 0;
}
}
ConvexResult(const ConvexResult &r) // copy constructor, perform a deep copy of the data.
{
mHullVcount = r.mHullVcount;
if ( mHullVcount )
{
mHullVertices = new double[mHullVcount*sizeof(double)*3];
memcpy(mHullVertices, r.mHullVertices, sizeof(double)*3*mHullVcount );
}
else
{
mHullVertices = 0;
}
mHullTcount = r.mHullTcount;
if ( mHullTcount )
{
mHullIndices = new unsigned int[sizeof(unsigned int)*mHullTcount*3];
memcpy(mHullIndices, r.mHullIndices, sizeof(unsigned int)*mHullTcount*3 );
}
else
{
mHullIndices = 0;
}
}
~ConvexResult(void)
{
delete mHullVertices;
delete mHullIndices;
}
// the convex hull.
unsigned int mHullVcount;
double * mHullVertices;
unsigned int mHullTcount;
unsigned int *mHullIndices;
double mHullVolume; // the volume of the convex hull.
};
// convert from doubles back down to floats.
class FConvexResult
{
public:
FConvexResult(const ConvexResult &r)
{
mHullVcount = r.mHullVcount;
mHullVertices = 0;
if ( mHullVcount )
{
mHullVertices = new float[mHullVcount*3];
const double *src = r.mHullVertices;
float * dest = mHullVertices;
for (unsigned int i=0; i<mHullVcount; i++)
{
dest[0] = (float) src[0];
dest[1] = (float) src[1];
dest[2] = (float) src[2];
src+=3;
dest+=3;
}
}
mHullTcount = r.mHullTcount;
if ( mHullTcount )
{
mHullIndices = new unsigned int[mHullTcount*3];
memcpy(mHullIndices,r.mHullIndices,sizeof(unsigned int)*mHullTcount*3);
}
else
{
mHullIndices = 0;
}
mHullVolume = (float)r.mHullVolume;
}
~FConvexResult(void)
{
delete mHullVertices;
delete mHullIndices;
}
unsigned int mHullVcount;
float * mHullVertices;
unsigned int mHullTcount;
unsigned int *mHullIndices;
float mHullVolume; // the volume of the convex hull.
};
class ConvexDecompInterface
{
public:
virtual void ConvexDebugTri(const double *p1,const double *p2,const double *p3,unsigned int color) { };
virtual void ConvexDebugPoint(const double *p,double dist,unsigned int color) { };
virtual void ConvexDebugBound(const double *bmin,const double *bmax,unsigned int color) { };
virtual void ConvexDebugOBB(const double *sides, const double *matrix,unsigned int color) { };
virtual void ConvexDecompResult(ConvexResult &result) = 0;
};
// just to avoid passing a zillion parameters to the method the
// options are packed into this descriptor.
class DecompDesc
{
public:
DecompDesc(void)
{
mVcount = 0;
mVertices = 0;
mTcount = 0;
mIndices = 0;
mDepth = 5;
mCpercent = 5;
mPpercent = 5;
mMaxVertices = 32;
mSkinWidth = 0;
mCallback = 0;
}
// describes the input triangle.
unsigned int mVcount; // the number of vertices in the source mesh.
const double *mVertices; // start of the vertex position array. Assumes a stride of 3 doubles.
unsigned int mTcount; // the number of triangles in the source mesh.
unsigned int *mIndices; // the indexed triangle list array (zero index based)
// options
unsigned int mDepth; // depth to split, a maximum of 10, generally not over 7.
double mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
double mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
// hull output limits.
unsigned int mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
double mSkinWidth; // a skin width to apply to the output hulls.
ConvexDecompInterface *mCallback; // the interface to receive back the results.
};
// perform approximate convex decomposition on a mesh.
unsigned int performConvexDecomposition(const DecompDesc &desc); // returns the number of hulls produced.
};
#endif

View File

@ -1,483 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
// Geometric Tools, Inc.
// http://www.geometrictools.com
// Copyright (c) 1998-2006. All Rights Reserved
//
// The Wild Magic Library (WM3) source code is supplied under the terms of
// the license agreement
// http://www.geometrictools.com/License/WildMagic3License.pdf
// and may not be copied or disclosed except in accordance with the terms
// of that agreement.
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include "bestfit.h"
namespace ConvexDecomposition
{
class Vec3
{
public:
Vec3(void) { };
Vec3(double _x,double _y,double _z) { x = _x; y = _y; z = _z; };
double dot(const Vec3 &v)
{
return x*v.x + y*v.y + z*v.z; // the dot product
}
double x;
double y;
double z;
};
class Eigen
{
public:
void DecrSortEigenStuff(void)
{
Tridiagonal(); //diagonalize the matrix.
QLAlgorithm(); //
DecreasingSort();
GuaranteeRotation();
}
void Tridiagonal(void)
{
double fM00 = mElement[0][0];
double fM01 = mElement[0][1];
double fM02 = mElement[0][2];
double fM11 = mElement[1][1];
double fM12 = mElement[1][2];
double fM22 = mElement[2][2];
m_afDiag[0] = fM00;
m_afSubd[2] = 0;
if (fM02 != (double)0.0)
{
double fLength = sqrt(fM01*fM01+fM02*fM02);
double fInvLength = ((double)1.0)/fLength;
fM01 *= fInvLength;
fM02 *= fInvLength;
double fQ = ((double)2.0)*fM01*fM12+fM02*(fM22-fM11);
m_afDiag[1] = fM11+fM02*fQ;
m_afDiag[2] = fM22-fM02*fQ;
m_afSubd[0] = fLength;
m_afSubd[1] = fM12-fM01*fQ;
mElement[0][0] = (double)1.0;
mElement[0][1] = (double)0.0;
mElement[0][2] = (double)0.0;
mElement[1][0] = (double)0.0;
mElement[1][1] = fM01;
mElement[1][2] = fM02;
mElement[2][0] = (double)0.0;
mElement[2][1] = fM02;
mElement[2][2] = -fM01;
m_bIsRotation = false;
}
else
{
m_afDiag[1] = fM11;
m_afDiag[2] = fM22;
m_afSubd[0] = fM01;
m_afSubd[1] = fM12;
mElement[0][0] = (double)1.0;
mElement[0][1] = (double)0.0;
mElement[0][2] = (double)0.0;
mElement[1][0] = (double)0.0;
mElement[1][1] = (double)1.0;
mElement[1][2] = (double)0.0;
mElement[2][0] = (double)0.0;
mElement[2][1] = (double)0.0;
mElement[2][2] = (double)1.0;
m_bIsRotation = true;
}
}
bool QLAlgorithm(void)
{
const int iMaxIter = 32;
for (int i0 = 0; i0 <3; i0++)
{
int i1;
for (i1 = 0; i1 < iMaxIter; i1++)
{
int i2;
for (i2 = i0; i2 <= (3-2); i2++)
{
double fTmp = fabs(m_afDiag[i2]) + fabs(m_afDiag[i2+1]);
if ( fabs(m_afSubd[i2]) + fTmp == fTmp )
break;
}
if (i2 == i0)
{
break;
}
double fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((double)2.0) * m_afSubd[i0]);
double fR = sqrt(fG*fG+(double)1.0);
if (fG < (double)0.0)
{
fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR);
}
else
{
fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR);
}
double fSin = (double)1.0, fCos = (double)1.0, fP = (double)0.0;
for (int i3 = i2-1; i3 >= i0; i3--)
{
double fF = fSin*m_afSubd[i3];
double fB = fCos*m_afSubd[i3];
if (fabs(fF) >= fabs(fG))
{
fCos = fG/fF;
fR = sqrt(fCos*fCos+(double)1.0);
m_afSubd[i3+1] = fF*fR;
fSin = ((double)1.0)/fR;
fCos *= fSin;
}
else
{
fSin = fF/fG;
fR = sqrt(fSin*fSin+(double)1.0);
m_afSubd[i3+1] = fG*fR;
fCos = ((double)1.0)/fR;
fSin *= fCos;
}
fG = m_afDiag[i3+1]-fP;
fR = (m_afDiag[i3]-fG)*fSin+((double)2.0)*fB*fCos;
fP = fSin*fR;
m_afDiag[i3+1] = fG+fP;
fG = fCos*fR-fB;
for (int i4 = 0; i4 < 3; i4++)
{
fF = mElement[i4][i3+1];
mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF;
mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF;
}
}
m_afDiag[i0] -= fP;
m_afSubd[i0] = fG;
m_afSubd[i2] = (double)0.0;
}
if (i1 == iMaxIter)
{
return false;
}
}
return true;
}
void DecreasingSort(void)
{
//sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1]
for (int i0 = 0, i1; i0 <= 3-2; i0++)
{
// locate maximum eigenvalue
i1 = i0;
double fMax = m_afDiag[i1];
int i2;
for (i2 = i0+1; i2 < 3; i2++)
{
if (m_afDiag[i2] > fMax)
{
i1 = i2;
fMax = m_afDiag[i1];
}
}
if (i1 != i0)
{
// swap eigenvalues
m_afDiag[i1] = m_afDiag[i0];
m_afDiag[i0] = fMax;
// swap eigenvectors
for (i2 = 0; i2 < 3; i2++)
{
double fTmp = mElement[i2][i0];
mElement[i2][i0] = mElement[i2][i1];
mElement[i2][i1] = fTmp;
m_bIsRotation = !m_bIsRotation;
}
}
}
}
void GuaranteeRotation(void)
{
if (!m_bIsRotation)
{
// change sign on the first column
for (int iRow = 0; iRow <3; iRow++)
{
mElement[iRow][0] = -mElement[iRow][0];
}
}
}
double mElement[3][3];
double m_afDiag[3];
double m_afSubd[3];
bool m_bIsRotation;
};
bool getBestFitPlane(unsigned int vcount,
const double *points,
unsigned int vstride,
const double *weights,
unsigned int wstride,
double *plane)
{
bool ret = false;
Vec3 kOrigin(0,0,0);
double wtotal = 0;
if ( 1 )
{
const char *source = (const char *) points;
const char *wsource = (const char *) weights;
for (unsigned int i=0; i<vcount; i++)
{
const double *p = (const double *) source;
double w = 1;
if ( wsource )
{
const double *ws = (const double *) wsource;
w = *ws; //
wsource+=wstride;
}
kOrigin.x+=p[0]*w;
kOrigin.y+=p[1]*w;
kOrigin.z+=p[2]*w;
wtotal+=w;
source+=vstride;
}
}
double recip = 1.0f / wtotal; // reciprocol of total weighting
kOrigin.x*=recip;
kOrigin.y*=recip;
kOrigin.z*=recip;
double fSumXX=0;
double fSumXY=0;
double fSumXZ=0;
double fSumYY=0;
double fSumYZ=0;
double fSumZZ=0;
if ( 1 )
{
const char *source = (const char *) points;
const char *wsource = (const char *) weights;
for (unsigned int i=0; i<vcount; i++)
{
const double *p = (const double *) source;
double w = 1;
if ( wsource )
{
const double *ws = (const double *) wsource;
w = *ws; //
wsource+=wstride;
}
Vec3 kDiff;
kDiff.x = w*(p[0] - kOrigin.x); // apply vertex weighting!
kDiff.y = w*(p[1] - kOrigin.y);
kDiff.z = w*(p[2] - kOrigin.z);
fSumXX+= kDiff.x * kDiff.x; // sume of the squares of the differences.
fSumXY+= kDiff.x * kDiff.y; // sume of the squares of the differences.
fSumXZ+= kDiff.x * kDiff.z; // sume of the squares of the differences.
fSumYY+= kDiff.y * kDiff.y;
fSumYZ+= kDiff.y * kDiff.z;
fSumZZ+= kDiff.z * kDiff.z;
source+=vstride;
}
}
fSumXX *= recip;
fSumXY *= recip;
fSumXZ *= recip;
fSumYY *= recip;
fSumYZ *= recip;
fSumZZ *= recip;
// setup the eigensolver
Eigen kES;
kES.mElement[0][0] = fSumXX;
kES.mElement[0][1] = fSumXY;
kES.mElement[0][2] = fSumXZ;
kES.mElement[1][0] = fSumXY;
kES.mElement[1][1] = fSumYY;
kES.mElement[1][2] = fSumYZ;
kES.mElement[2][0] = fSumXZ;
kES.mElement[2][1] = fSumYZ;
kES.mElement[2][2] = fSumZZ;
// compute eigenstuff, smallest eigenvalue is in last position
kES.DecrSortEigenStuff();
Vec3 kNormal;
kNormal.x = kES.mElement[0][2];
kNormal.y = kES.mElement[1][2];
kNormal.z = kES.mElement[2][2];
// the minimum energy
plane[0] = kNormal.x;
plane[1] = kNormal.y;
plane[2] = kNormal.z;
plane[3] = 0 - kNormal.dot(kOrigin);
return ret;
}
double getBoundingRegion(unsigned int vcount,const double *points,unsigned int pstride,double *bmin,double *bmax) // returns the diagonal distance
{
const unsigned char *source = (const unsigned char *) points;
bmin[0] = points[0];
bmin[1] = points[1];
bmin[2] = points[2];
bmax[0] = points[0];
bmax[1] = points[1];
bmax[2] = points[2];
for (unsigned int i=1; i<vcount; i++)
{
source+=pstride;
const double *p = (const double *) source;
if ( p[0] < bmin[0] ) bmin[0] = p[0];
if ( p[1] < bmin[1] ) bmin[1] = p[1];
if ( p[2] < bmin[2] ) bmin[2] = p[2];
if ( p[0] > bmax[0] ) bmax[0] = p[0];
if ( p[1] > bmax[1] ) bmax[1] = p[1];
if ( p[2] > bmax[2] ) bmax[2] = p[2];
}
double dx = bmax[0] - bmin[0];
double dy = bmax[1] - bmin[1];
double dz = bmax[2] - bmin[2];
return sqrt( dx*dx + dy*dy + dz*dz );
}
bool overlapAABB(const double *bmin1,const double *bmax1,const double *bmin2,const double *bmax2) // return true if the two AABB's overlap.
{
if ( bmax2[0] < bmin1[0] ) return false; // if the maximum is less than our minimum on any axis
if ( bmax2[1] < bmin1[1] ) return false;
if ( bmax2[2] < bmin1[2] ) return false;
if ( bmin2[0] > bmax1[0] ) return false; // if the minimum is greater than our maximum on any axis
if ( bmin2[1] > bmax1[1] ) return false; // if the minimum is greater than our maximum on any axis
if ( bmin2[2] > bmax1[2] ) return false; // if the minimum is greater than our maximum on any axis
return true; // the extents overlap
}
}; // end of namespace

View File

@ -1,90 +0,0 @@
#ifndef BEST_FIT_H
#define BEST_FIT_H
// This routine was released in 'snippet' form
// by John W. Ratcliff mailto:jratcliff@infiniplex.net
// on March 22, 2006.
//
// This routine computes the 'best fit' plane equation to
// a set of input data points with an optional per vertex
// weighting component.
//
// The implementation for this was lifted directly from
// David Eberly's Magic Software implementation.
// computes the best fit plane to a collection of data points.
// returns the plane equation as A,B,C,D format. (Ax+By+Cz+D)
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
bool getBestFitPlane(unsigned int vcount, // number of input data points
const double *points, // starting address of points array.
unsigned int vstride, // stride between input points.
const double *weights, // *optional point weighting values.
unsigned int wstride, // weight stride for each vertex.
double *plane);
double getBoundingRegion(unsigned int vcount,const double *points,unsigned int pstride,double *bmin,double *bmax); // returns the diagonal distance
bool overlapAABB(const double *bmin1,const double *bmax1,const double *bmin2,const double *bmax2); // return true if the two AABB's overlap.
};
#endif

View File

@ -1,368 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// compute the 'best fit' oriented bounding box of an input point cloud by doing an exhaustive search.
// it spins the point cloud around searching for the minimal volume. It keeps narrowing down until
// it fails to find a better fit. The only dependency is on 'double_math'
//
// The inputs are:
//
// vcount : number of input vertices in the point cloud.
// points : a pointer to the first vertex.
// pstride : The stride between each point measured in bytes.
//
// The outputs are:
//
// sides : The length of the sides of the OBB as X, Y, Z distance.
// matrix : A pointer to a 4x4 matrix. This will contain the 3x3 rotation and the translation component.
// pos : The center of the OBB
// quat : The orientation of the OBB expressed as quaternion in the form of X,Y,Z,W
//
//
// Please email bug fixes or improvements to John W. Ratcliff at mailto:jratcliff@infiniplex.net
//
// If you find this source code useful donate a couple of bucks to my kid's fund raising website at
// www.amillionpixels.us
//
// More snippets at: www.codesuppository.com
//
#include "bestfitobb.h"
#include "float_math.h"
namespace ConvexDecomposition
{
// computes the OBB for this set of points relative to this transform matrix.
void computeOBB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *matrix)
{
const char *src = (const char *) points;
double bmin[3] = { 1e9, 1e9, 1e9 };
double bmax[3] = { -1e9, -1e9, -1e9 };
for (unsigned int i=0; i<vcount; i++)
{
const double *p = (const double *) src;
double t[3];
fm_inverseRT(matrix, p, t ); // inverse rotate translate
if ( t[0] < bmin[0] ) bmin[0] = t[0];
if ( t[1] < bmin[1] ) bmin[1] = t[1];
if ( t[2] < bmin[2] ) bmin[2] = t[2];
if ( t[0] > bmax[0] ) bmax[0] = t[0];
if ( t[1] > bmax[1] ) bmax[1] = t[1];
if ( t[2] > bmax[2] ) bmax[2] = t[2];
src+=pstride;
}
double center[3];
sides[0] = bmax[0]-bmin[0];
sides[1] = bmax[1]-bmin[1];
sides[2] = bmax[2]-bmin[2];
center[0] = sides[0]*0.5f+bmin[0];
center[1] = sides[1]*0.5f+bmin[1];
center[2] = sides[2]*0.5f+bmin[2];
double ocenter[3];
fm_rotate(matrix,center,ocenter);
matrix[12]+=ocenter[0];
matrix[13]+=ocenter[1];
matrix[14]+=ocenter[2];
}
void computeBestFitOBB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *matrix)
{
double bmin[3];
double bmax[3];
fm_getAABB(vcount,points,pstride,bmin,bmax);
double center[3];
center[0] = (bmax[0]-bmin[0])*0.5f + bmin[0];
center[1] = (bmax[1]-bmin[1])*0.5f + bmin[1];
center[2] = (bmax[2]-bmin[2])*0.5f + bmin[2];
double ax = 0;
double ay = 0;
double az = 0;
double sweep = 45.0f; // 180 degree sweep on all three axes.
double steps = 7.0f; // 7 steps on each axis)
double bestVolume = 1e9;
double angle[3];
while ( sweep >= 1 )
{
bool found = false;
double stepsize = sweep / steps;
for (double x=ax-sweep; x<=ax+sweep; x+=stepsize)
{
for (double y=ay-sweep; y<=ay+sweep; y+=stepsize)
{
for (double z=az-sweep; z<=az+sweep; z+=stepsize)
{
double pmatrix[16];
fm_eulerMatrix( x*FM_DEG_TO_RAD, y*FM_DEG_TO_RAD, z*FM_DEG_TO_RAD, pmatrix );
pmatrix[3*4+0] = center[0];
pmatrix[3*4+1] = center[1];
pmatrix[3*4+2] = center[2];
double psides[3];
computeOBB( vcount, points, pstride, psides, pmatrix );
double volume = psides[0]*psides[1]*psides[2]; // the volume of the cube
if ( volume < bestVolume )
{
bestVolume = volume;
sides[0] = psides[0];
sides[1] = psides[1];
sides[2] = psides[2];
angle[0] = ax;
angle[1] = ay;
angle[2] = az;
memcpy(matrix,pmatrix,sizeof(double)*16);
found = true; // yes, we found an improvement.
}
}
}
}
if ( found )
{
ax = angle[0];
ay = angle[1];
az = angle[2];
sweep*=0.5f; // sweep 1/2 the distance as the last time.
}
else
{
break; // no improvement, so just
}
}
}
void computeBestFitOBB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *pos,double *quat)
{
double matrix[16];
computeBestFitOBB(vcount,points,pstride,sides,matrix);
fm_getTranslation(matrix,pos);
fm_matrixToQuat(matrix,quat);
}
void computeBestFitABB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *pos)
{
double bmin[3];
double bmax[3];
bmin[0] = points[0];
bmin[1] = points[1];
bmin[2] = points[2];
bmax[0] = points[0];
bmax[1] = points[1];
bmax[2] = points[2];
const char *cp = (const char *) points;
for (unsigned int i=0; i<vcount; i++)
{
const double *p = (const double *) cp;
if ( p[0] < bmin[0] ) bmin[0] = p[0];
if ( p[1] < bmin[1] ) bmin[1] = p[1];
if ( p[2] < bmin[2] ) bmin[2] = p[2];
if ( p[0] > bmax[0] ) bmax[0] = p[0];
if ( p[1] > bmax[1] ) bmax[1] = p[1];
if ( p[2] > bmax[2] ) bmax[2] = p[2];
cp+=pstride;
}
sides[0] = bmax[0] - bmin[0];
sides[1] = bmax[1] - bmin[1];
sides[2] = bmax[2] - bmin[2];
pos[0] = bmin[0]+sides[0]*0.5f;
pos[1] = bmin[1]+sides[1]*0.5f;
pos[2] = bmin[2]+sides[2]*0.5f;
}
void computeBestFitOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *pos,float *quat) // the float version of the routine.
{
double *temp = new double[vcount*3];
const char *src = (const char *)points;
double *dest = temp;
for (unsigned int i=0; i<vcount; i++)
{
const float *s = (const float *) src;
temp[0] = s[0];
temp[1] = s[1];
temp[2] = s[2];
temp+=3;
s+=pstride;
}
double dsides[3];
double dpos[3];
double dquat[3];
computeBestFitOBB(vcount,temp,sizeof(double)*3,dsides,dpos,dquat);
if ( sides )
{
sides[0] = (float) dsides[0];
sides[1] = (float) dsides[1];
sides[2] = (float) dsides[2];
}
if ( pos )
{
pos[0] = (float) dpos[0];
pos[1] = (float) dpos[1];
pos[2] = (float) dpos[2];
}
if ( quat )
{
quat[0] = (float) dquat[0];
quat[1] = (float) dquat[1];
quat[2] = (float) dquat[2];
quat[3] = (float) dquat[3];
}
delete temp;
}
void computeBestFitABB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *pos)
{
float bmin[3];
float bmax[3];
bmin[0] = points[0];
bmin[1] = points[1];
bmin[2] = points[2];
bmax[0] = points[0];
bmax[1] = points[1];
bmax[2] = points[2];
const char *cp = (const char *) points;
for (unsigned int i=0; i<vcount; i++)
{
const float *p = (const float *) cp;
if ( p[0] < bmin[0] ) bmin[0] = p[0];
if ( p[1] < bmin[1] ) bmin[1] = p[1];
if ( p[2] < bmin[2] ) bmin[2] = p[2];
if ( p[0] > bmax[0] ) bmax[0] = p[0];
if ( p[1] > bmax[1] ) bmax[1] = p[1];
if ( p[2] > bmax[2] ) bmax[2] = p[2];
cp+=pstride;
}
sides[0] = bmax[0] - bmin[0];
sides[1] = bmax[1] - bmin[1];
sides[2] = bmax[2] - bmin[2];
pos[0] = bmin[0]+sides[0]*0.5f;
pos[1] = bmin[1]+sides[1]*0.5f;
pos[2] = bmin[2]+sides[2]*0.5f;
}
};

View File

@ -1,100 +0,0 @@
#ifndef BEST_FIT_OBB_H
#define BEST_FIT_OBB_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// compute the 'best fit' oriented bounding box of an input point cloud by doing an exhaustive search.
// it spins the point cloud around searching for the minimal volume. It keeps narrowing down until
// it fails to find a better fit. The only dependency is on 'double_math'
//
// The inputs are:
//
// vcount : number of input vertices in the point cloud.
// points : a pointer to the first vertex.
// pstride : The stride between each point measured in bytes.
//
// The outputs are:
//
// sides : The length of the sides of the OBB as X, Y, Z distance.
// matrix : A pointer to a 4x4 matrix. This will contain the 3x3 rotation and the translation component.
// pos : The center of the OBB
// quat : The orientation of the OBB expressed as quaternion in the form of X,Y,Z,W
//
//
// Please email bug fixes or improvements to John W. Ratcliff at mailto:jratcliff@infiniplex.net
//
// If you find this source code useful donate a couple of bucks to my kid's fund raising website at
// www.amillionpixels.us
//
// More snippets at: www.codesuppository.com
//
namespace ConvexDecomposition
{
void computeBestFitOBB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *matrix);
void computeBestFitOBB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *pos,double *quat);
void computeBestFitABB(unsigned int vcount,const double *points,unsigned int pstride,double *sides,double *pos);
void computeBestFitOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *pos,float *quat); // the float version of the routine.
void computeBestFitABB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *pos);
};
#endif

View File

@ -1,250 +0,0 @@
#ifndef HULL_LIB_H
#define HULL_LIB_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
class HullResult
{
public:
HullResult(void)
{
mPolygons = true;
mNumOutputVertices = 0;
mOutputVertices = 0;
mNumFaces = 0;
mNumIndices = 0;
mIndices = 0;
}
bool mPolygons; // true if indices represents polygons, false indices are triangles
unsigned int mNumOutputVertices; // number of vertices in the output hull
double *mOutputVertices; // array of vertices, 3 doubles each x,y,z
unsigned int mNumFaces; // the number of faces produced
unsigned int mNumIndices; // the total number of indices
unsigned int *mIndices; // pointer to indices.
// If triangles, then indices are array indexes into the vertex list.
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
};
class FHullResult
{
public:
FHullResult(const HullResult &r)
{
mPolygons = r.mPolygons;
mNumOutputVertices = r.mNumOutputVertices;
mNumFaces = r.mNumFaces;
mNumIndices = r.mNumIndices;
mIndices = 0;
mOutputVertices = 0;
if ( mNumIndices )
{
mIndices = new unsigned int[mNumIndices];
memcpy(mIndices,r.mIndices,sizeof(unsigned int)*mNumIndices);
}
if ( mNumOutputVertices )
{
mOutputVertices = new float[mNumOutputVertices*3];
const double *src = r.mOutputVertices;
float *dst = mOutputVertices;
for (unsigned int i=0; i<mNumOutputVertices; i++)
{
dst[0] = (float) src[0];
dst[1] = (float) src[1];
dst[2] = (float) src[2];
dst+=3;
src+=3;
}
}
}
~FHullResult(void)
{
delete mIndices;
delete mOutputVertices;
}
bool mPolygons; // true if indices represents polygons, false indices are triangles
unsigned int mNumOutputVertices; // number of vertices in the output hull
float *mOutputVertices; // array of vertices, 3 doubles each x,y,z
unsigned int mNumFaces; // the number of faces produced
unsigned int mNumIndices; // the total number of indices
unsigned int *mIndices; // pointer to indices.
// If triangles, then indices are array indexes into the vertex list.
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
};
enum HullFlag
{
QF_TRIANGLES = (1<<0), // report results as triangles, not polygons.
QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices.
QF_SKIN_WIDTH = (1<<2), // extrude hull based on this skin width
QF_DEFAULT = 0
};
class HullDesc
{
public:
HullDesc(void)
{
mFlags = QF_DEFAULT;
mVcount = 0;
mVertices = 0;
mVertexStride = 0;
mNormalEpsilon = 0.001f;
mMaxVertices = 4096; // maximum number of points to be considered for a convex hull.
mSkinWidth = 0.01f; // default is one centimeter
};
HullDesc(HullFlag flag,
unsigned int vcount,
const double *vertices,
unsigned int stride)
{
mFlags = flag;
mVcount = vcount;
mVertices = vertices;
mVertexStride = stride;
mNormalEpsilon = 0.001f;
mMaxVertices = 4096;
mSkinWidth = 0.01f; // default is one centimeter
}
bool HasHullFlag(HullFlag flag) const
{
if ( mFlags & flag ) return true;
return false;
}
void SetHullFlag(HullFlag flag)
{
mFlags|=flag;
}
void ClearHullFlag(HullFlag flag)
{
mFlags&=~flag;
}
unsigned int mFlags; // flags to use when generating the convex hull.
unsigned int mVcount; // number of vertices in the input point cloud
const double *mVertices; // the array of vertices.
unsigned int mVertexStride; // the stride of each vertex, in bytes.
double mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
double mSkinWidth;
unsigned int mMaxVertices; // maximum number of vertices to be considered for the hull!
};
enum HullError
{
QE_OK, // success!
QE_FAIL // failed.
};
// This class is used when converting a convex hull into a triangle mesh.
class ConvexHullVertex
{
public:
double mPos[3];
double mNormal[3];
double mTexel[2];
};
// A virtual interface to receive the triangles from the convex hull.
class ConvexHullTriangleInterface
{
public:
virtual void ConvexHullTriangle(const ConvexHullVertex &v1,const ConvexHullVertex &v2,const ConvexHullVertex &v3) = 0;
};
class HullLibrary
{
public:
HullError CreateConvexHull(const HullDesc &desc, // describes the input request
HullResult &result); // contains the resulst
HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it.
// Utility function to convert the output convex hull as a renderable set of triangles. Unfolds the polygons into
// individual triangles, compute the vertex normals, and projects some texture co-ordinates.
HullError CreateTriangleMesh(HullResult &answer,ConvexHullTriangleInterface *iface);
private:
double ComputeNormal(double *n,const double *A,const double *B,const double *C);
void AddConvexTriangle(ConvexHullTriangleInterface *callback,const double *p1,const double *p2,const double *p3);
void BringOutYourDead(const double *verts,unsigned int vcount, double *overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount);
bool CleanupVertices(unsigned int svcount,
const double *svertices,
unsigned int stride,
unsigned int &vcount, // output number of vertices
double *vertices, // location to store the results.
double normalepsilon,
double *scale);
};
};
#endif

View File

@ -1,858 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#pragma warning(disable:4996)
#include "cd_wavefront.h"
using namespace ConvexDecomposition;
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include <vector>
namespace ConvexDecomposition
{
typedef std::vector< int > IntVector;
typedef std::vector< double > FloatVector;
#if defined(__APPLE__) || defined(__CELLOS_LV2__)
#define stricmp(a, b) strcasecmp((a), (b))
#endif
/*******************************************************************/
/******************** InParser.h ********************************/
/*******************************************************************/
class InPlaceParserInterface
{
public:
virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
};
enum SeparatorType
{
ST_DATA, // is data
ST_HARD, // is a hard separator
ST_SOFT, // is a soft separator
ST_EOS // is a comment symbol, and everything past this character should be ignored
};
class InPlaceParser
{
public:
InPlaceParser(void)
{
Init();
}
InPlaceParser(char *data,int len)
{
Init();
SetSourceData(data,len);
}
InPlaceParser(const char *fname)
{
Init();
SetFile(fname);
}
~InPlaceParser(void);
void Init(void)
{
mQuoteChar = 34;
mData = 0;
mLen = 0;
mMyAlloc = false;
for (int i=0; i<256; i++)
{
mHard[i] = ST_DATA;
mHardString[i*2] = i;
mHardString[i*2+1] = 0;
}
mHard[0] = ST_EOS;
mHard[32] = ST_SOFT;
mHard[9] = ST_SOFT;
mHard[13] = ST_SOFT;
mHard[10] = ST_SOFT;
}
void SetFile(const char *fname); // use this file as source data to parse.
void SetSourceData(char *data,int len)
{
mData = data;
mLen = len;
mMyAlloc = false;
};
int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
void SetHardSeparator(char c) // add a hard separator
{
mHard[c] = ST_HARD;
}
void SetHard(char c) // add a hard separator
{
mHard[c] = ST_HARD;
}
void SetCommentSymbol(char c) // comment character, treated as 'end of string'
{
mHard[c] = ST_EOS;
}
void ClearHardSeparator(char c)
{
mHard[c] = ST_DATA;
}
void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
bool EOS(char c)
{
if ( mHard[c] == ST_EOS )
{
return true;
}
return false;
}
void SetQuoteChar(char c)
{
mQuoteChar = c;
}
private:
inline char * AddHard(int &argc,const char **argv,char *foo);
inline bool IsHard(char c);
inline char * SkipSpaces(char *foo);
inline bool IsWhiteSpace(char c);
inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
char *mData; // ascii data to parse.
int mLen; // length of data
SeparatorType mHard[256];
char mHardString[256*2];
char mQuoteChar;
};
/*******************************************************************/
/******************** InParser.cpp ********************************/
/*******************************************************************/
void InPlaceParser::SetFile(const char *fname)
{
if ( mMyAlloc )
{
free(mData);
}
mData = 0;
mLen = 0;
mMyAlloc = false;
FILE *fph = fopen(fname,"rb");
if ( fph )
{
fseek(fph,0L,SEEK_END);
mLen = ftell(fph);
fseek(fph,0L,SEEK_SET);
if ( mLen )
{
mData = (char *) malloc(sizeof(char)*(mLen+1));
int ok = fread(mData, mLen, 1, fph);
if ( !ok )
{
free(mData);
mData = 0;
}
else
{
mData[mLen] = 0; // zero byte terminate end of file marker.
mMyAlloc = true;
}
}
fclose(fph);
}
}
InPlaceParser::~InPlaceParser(void)
{
if ( mMyAlloc )
{
free(mData);
}
}
#define MAXARGS 512
bool InPlaceParser::IsHard(char c)
{
return mHard[c] == ST_HARD;
}
char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
{
while ( IsHard(*foo) )
{
const char *hard = &mHardString[*foo*2];
if ( argc < MAXARGS )
{
argv[argc++] = hard;
}
foo++;
}
return foo;
}
bool InPlaceParser::IsWhiteSpace(char c)
{
return mHard[c] == ST_SOFT;
}
char * InPlaceParser::SkipSpaces(char *foo)
{
while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
return foo;
}
bool InPlaceParser::IsNonSeparator(char c)
{
if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
return false;
}
int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
{
int ret = 0;
const char *argv[MAXARGS];
int argc = 0;
char *foo = line;
while ( !EOS(*foo) && argc < MAXARGS )
{
foo = SkipSpaces(foo); // skip any leading spaces
if ( EOS(*foo) ) break;
if ( *foo == mQuoteChar ) // if it is an open quote
{
foo++;
if ( argc < MAXARGS )
{
argv[argc++] = foo;
}
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
if ( !EOS(*foo) )
{
*foo = 0; // replace close quote with zero byte EOS
foo++;
}
}
else
{
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
if ( IsNonSeparator(*foo) ) // add non-hard argument.
{
bool quote = false;
if ( *foo == mQuoteChar )
{
foo++;
quote = true;
}
if ( argc < MAXARGS )
{
argv[argc++] = foo;
}
if ( quote )
{
while (*foo && *foo != mQuoteChar ) foo++;
if ( *foo ) *foo = 32;
}
// continue..until we hit an eos ..
while ( !EOS(*foo) ) // until we hit EOS
{
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
{
*foo = 0;
foo++;
break;
}
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
{
const char *hard = &mHardString[*foo*2];
*foo = 0;
if ( argc < MAXARGS )
{
argv[argc++] = hard;
}
foo++;
break;
}
foo++;
} // end of while loop...
}
}
}
if ( argc )
{
ret = callback->ParseLine(lineno, argc, argv );
}
return ret;
}
int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
{
assert( callback );
if ( !mData ) return 0;
int ret = 0;
int lineno = 0;
char *foo = mData;
char *begin = foo;
while ( *foo )
{
if ( *foo == 10 || *foo == 13 )
{
lineno++;
*foo = 0;
if ( *begin ) // if there is any data to parse at all...
{
int v = ProcessLine(lineno,begin,callback);
if ( v ) ret = v;
}
foo++;
if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
begin = foo;
}
else
{
foo++;
}
}
lineno++; // lasst line.
int v = ProcessLine(lineno,begin,callback);
if ( v ) ret = v;
return ret;
}
void InPlaceParser::DefaultSymbols(void)
{
SetHardSeparator(',');
SetHardSeparator('(');
SetHardSeparator(')');
SetHardSeparator('=');
SetHardSeparator('[');
SetHardSeparator(']');
SetHardSeparator('{');
SetHardSeparator('}');
SetCommentSymbol('#');
}
const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
{
const char **ret = 0;
static const char *argv[MAXARGS];
int argc = 0;
char *foo = line;
while ( !EOS(*foo) && argc < MAXARGS )
{
foo = SkipSpaces(foo); // skip any leading spaces
if ( EOS(*foo) ) break;
if ( *foo == mQuoteChar ) // if it is an open quote
{
foo++;
if ( argc < MAXARGS )
{
argv[argc++] = foo;
}
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
if ( !EOS(*foo) )
{
*foo = 0; // replace close quote with zero byte EOS
foo++;
}
}
else
{
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
if ( IsNonSeparator(*foo) ) // add non-hard argument.
{
bool quote = false;
if ( *foo == mQuoteChar )
{
foo++;
quote = true;
}
if ( argc < MAXARGS )
{
argv[argc++] = foo;
}
if ( quote )
{
while (*foo && *foo != mQuoteChar ) foo++;
if ( *foo ) *foo = 32;
}
// continue..until we hit an eos ..
while ( !EOS(*foo) ) // until we hit EOS
{
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
{
*foo = 0;
foo++;
break;
}
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
{
const char *hard = &mHardString[*foo*2];
*foo = 0;
if ( argc < MAXARGS )
{
argv[argc++] = hard;
}
foo++;
break;
}
foo++;
} // end of while loop...
}
}
}
count = argc;
if ( argc )
{
ret = argv;
}
return ret;
}
/*******************************************************************/
/******************** Geometry.h ********************************/
/*******************************************************************/
class GeometryVertex
{
public:
double mPos[3];
double mNormal[3];
double mTexel[2];
};
class GeometryInterface
{
public:
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
{
}
};
/*******************************************************************/
/******************** Obj.h ********************************/
/*******************************************************************/
class OBJ : public InPlaceParserInterface
{
public:
int LoadMesh(const char *fname,GeometryInterface *callback);
int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
private:
void GetVertex(GeometryVertex &v,const char *face) const;
FloatVector mVerts;
FloatVector mTexels;
FloatVector mNormals;
GeometryInterface *mCallback;
friend class WavefrontObj;
};
/*******************************************************************/
/******************** Obj.cpp ********************************/
/*******************************************************************/
int OBJ::LoadMesh(const char *fname,GeometryInterface *iface)
{
int ret = 0;
mVerts.clear();
mTexels.clear();
mNormals.clear();
mCallback = iface;
InPlaceParser ipp(fname);
ipp.Parse(this);
return ret;
}
static const char * GetArg(const char **argv,int i,int argc)
{
const char * ret = 0;
if ( i < argc ) ret = argv[i];
return ret;
}
void OBJ::GetVertex(GeometryVertex &v,const char *face) const
{
v.mPos[0] = 0;
v.mPos[1] = 0;
v.mPos[2] = 0;
v.mTexel[0] = 0;
v.mTexel[1] = 0;
v.mNormal[0] = 0;
v.mNormal[1] = 1;
v.mNormal[2] = 0;
int index = atoi( face )-1;
const char *texel = strstr(face,"/");
if ( texel )
{
int tindex = atoi( texel+1) - 1;
if ( tindex >=0 && tindex < (int)(mTexels.size()/2) )
{
const double *t = &mTexels[tindex*2];
v.mTexel[0] = t[0];
v.mTexel[1] = t[1];
}
const char *normal = strstr(texel+1,"/");
if ( normal )
{
int nindex = atoi( normal+1 ) - 1;
if (nindex >= 0 && nindex < (int)(mNormals.size()/3) )
{
const double *n = &mNormals[nindex*3];
v.mNormal[0] = n[0];
v.mNormal[1] = n[1];
v.mNormal[2] = n[2];
}
}
}
if ( index >= 0 && index < (int)(mVerts.size()/3) )
{
const double *p = &mVerts[index*3];
v.mPos[0] = p[0];
v.mPos[1] = p[1];
v.mPos[2] = p[2];
}
}
int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
{
int ret = 0;
if ( argc >= 1 )
{
const char *foo = argv[0];
if ( *foo != '#' )
{
if ( strcmp(argv[0],"v") == 0 && argc == 4 )
{
double vx = (double) atof( argv[1] );
double vy = (double) atof( argv[2] );
double vz = (double) atof( argv[3] );
mVerts.push_back(vx);
mVerts.push_back(vy);
mVerts.push_back(vz);
}
else if ( strcmp(argv[0],"vt") == 0 && argc == 3 )
{
double tx = (double) atof( argv[1] );
double ty = (double) atof( argv[2] );
mTexels.push_back(tx);
mTexels.push_back(ty);
}
else if ( strcmp(argv[0],"vn") == 0 && argc == 4 )
{
double normalx = (double) atof(argv[1]);
double normaly = (double) atof(argv[2]);
double normalz = (double) atof(argv[3]);
mNormals.push_back(normalx);
mNormals.push_back(normaly);
mNormals.push_back(normalz);
}
else if ( strcmp(argv[0],"f") == 0 && argc >= 4 )
{
GeometryVertex v[32];
int vcount = argc-1;
for (int i=1; i<argc; i++)
{
GetVertex(v[i-1],argv[i] );
}
// need to generate a normal!
#if 0 // not currently implemented
if ( mNormals.empty() )
{
Vector3d<double> p1( v[0].mPos );
Vector3d<double> p2( v[1].mPos );
Vector3d<double> p3( v[2].mPos );
Vector3d<double> n;
n.ComputeNormal(p3,p2,p1);
for (int i=0; i<vcount; i++)
{
v[i].mNormal[0] = n.x;
v[i].mNormal[1] = n.y;
v[i].mNormal[2] = n.z;
}
}
#endif
mCallback->NodeTriangle(&v[0],&v[1],&v[2]);
if ( vcount >=3 ) // do the fan
{
for (int i=2; i<(vcount-1); i++)
{
mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]);
}
}
}
}
}
return ret;
}
class BuildMesh : public GeometryInterface
{
public:
int GetIndex(const double *p)
{
int vcount = mVertices.size()/3;
if(vcount>0)
{
//New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
const double *v = &mVertices[0];
for (int i=0; i<vcount; i++)
{
if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) return i;
v+=3;
}
}
mVertices.push_back( p[0] );
mVertices.push_back( p[1] );
mVertices.push_back( p[2] );
return vcount;
}
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
{
mIndices.push_back( GetIndex(v1->mPos) );
mIndices.push_back( GetIndex(v2->mPos) );
mIndices.push_back( GetIndex(v3->mPos) );
}
const FloatVector& GetVertices(void) const { return mVertices; };
const IntVector& GetIndices(void) const { return mIndices; };
private:
FloatVector mVertices;
IntVector mIndices;
};
WavefrontObj::WavefrontObj(void)
{
mVertexCount = 0;
mTriCount = 0;
mIndices = 0;
mVertices = 0;
}
WavefrontObj::~WavefrontObj(void)
{
delete mIndices;
delete mVertices;
}
unsigned int WavefrontObj::loadObj(const char *fname) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
{
unsigned int ret = 0;
delete mVertices;
mVertices = 0;
delete mIndices;
mIndices = 0;
mVertexCount = 0;
mTriCount = 0;
BuildMesh bm;
OBJ obj;
obj.LoadMesh(fname,&bm);
const FloatVector &vlist = bm.GetVertices();
const IntVector &indices = bm.GetIndices();
if ( vlist.size() )
{
mVertexCount = vlist.size()/3;
mVertices = new double[mVertexCount*3];
memcpy( mVertices, &vlist[0], sizeof(double)*mVertexCount*3 );
mTriCount = indices.size()/3;
mIndices = new int[mTriCount*3*sizeof(int)];
memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);
ret = mTriCount;
}
else if( obj.mVerts.size() > 0 ) {
// take consecutive vertices
mVertexCount = obj.mVerts.size()/3;
mVertices = new double[mVertexCount*3];
memcpy( mVertices, &obj.mVerts[0], sizeof(double)*mVertexCount*3 );
mTriCount = mVertexCount/3;
mIndices = new int[mTriCount*3*sizeof(int)];
for(int i = 0; i < mVertexCount; ++i)
mIndices[i] = i;
ret = mTriCount;
}
return ret;
}
};

View File

@ -1,82 +0,0 @@
#ifndef CD_WAVEFRONT_OBJ_H
#define CD_WAVEFRONT_OBJ_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
class WavefrontObj
{
public:
WavefrontObj(void);
~WavefrontObj(void);
unsigned int loadObj(const char *fname); // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
int mVertexCount;
int mTriCount;
int *mIndices;
double *mVertices;
};
};
#endif

View File

@ -1,821 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include <vector>
#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<double> &p,double w)
{
mPoint = p;
mWeight = w;
}
Vector3d<double> mPoint;
double mWeight;
};
typedef std::vector< Wpoint > WpointVector;
static inline double DistToPt(const double *p,const double *plane)
{
double x = p[0];
double y = p[1];
double z = p[2];
double d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3];
return d;
}
static void intersect(const double *p1,const double *p2,double *split,const double *plane)
{
double dp1 = DistToPt(p1,plane);
double dp2 = DistToPt(p2,plane);
double dir[3];
dir[0] = p2[0] - p1[0];
dir[1] = p2[1] - p1[1];
dir[2] = p2[2] - p1[2];
double dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2];
double dot2 = dp1 - plane[3];
double 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 double *p1,const double *p2,const double *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);
}
double Facing(const CTri &t)
{
double d = mNormal.Dot(t.mNormal);
return d;
}
// clip this line segment against this triangle.
bool clip(const Vector3d<double> &start,Vector3d<double> &end) const
{
Vector3d<double> 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<double> &p,double &distance,Vector3d<double> &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++;
}
double 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 double *vertices = mP1.Ptr();
if ( callback )
{
unsigned int color = getDebugColor();
#if 0
Vector3d<double> d1 = mNear1;
Vector3d<double> d2 = mNear2;
Vector3d<double> 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 double *p1 = &vertices[ i1*3 ];
const double *p2 = &vertices[ i2*3 ];
const double *p3 = &vertices[ i3*3 ];
callback->ConvexDebugTri(p1,p2,p3,color);
}
#endif
}
double v = computeMeshVolume(mP1.Ptr(), tcount, indices );
return v;
}
double raySect(const Vector3d<double> &p,const Vector3d<double> &dir,Vector3d<double> &sect) const
{
double plane[4];
plane[0] = mNormal.x;
plane[1] = mNormal.y;
plane[2] = mNormal.z;
plane[3] = mPlaneD;
Vector3d<double> dest = p+dir*100000;
intersect( p.Ptr(), dest.Ptr(), sect.Ptr(), plane );
return sect.Distance(p); // return the intersection distance.
}
double planeDistance(const Vector3d<double> &p) const
{
double 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 double THRESH = 0.001f;
double dd = fabs( t.mPlaneD - mPlaneD );
if ( dd > THRESH ) return false;
dd = fabs( t.mNormal.x - mNormal.x );
if ( dd > THRESH ) return false;
dd = fabs( t.mNormal.y - mNormal.y );
if ( dd > THRESH ) return false;
dd = fabs( 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 );
}
double area(void)
{
double 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<double> d1 = mNear1 - mP1;
Vector3d<double> d2 = mNear2 - mP2;
Vector3d<double> 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<double> np1 = mP1 + mNormal*0.05f;
Vector3d<double> np2 = mP2 + mNormal*0.05f;
Vector3d<double> 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<double> mP1;
Vector3d<double> mP2;
Vector3d<double> mP3;
Vector3d<double> mNear1;
Vector3d<double> mNear2;
Vector3d<double> mNear3;
Vector3d<double> mNormal;
double mPlaneD;
double mConcavity;
double mC1;
double mC2;
double 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;
double 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;
double near[3] = { 1e9, 1e9, 1e9 };
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;
}
double dot = t.mNormal.Dot(m.mNormal);
if ( dot > neardot )
{
double d1 = t.planeDistance( m.mP1 );
double d2 = t.planeDistance( m.mP2 );
double d3 = t.planeDistance( m.mP3 );
if ( d1 > 0.001f || d2 > 0.001f || d3 > 0.001f ) // can't be near coplaner!
{
neardot = dot;
Vector3d<double> 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,double fc,ConvexDecompInterface *callback,unsigned int color)
{
bool ret = false;
if ( t.mProcessed == 0 ) // if not already processed
{
double 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;
}
double computeConcavity(unsigned int vcount,
const double *vertices,
unsigned int tcount,
const unsigned int *indices,
ConvexDecompInterface *callback,
double *plane, // plane equation to split on
double &volume)
{
double cret = 0;
volume = 1;
HullResult result;
HullLibrary hl;
HullDesc desc;
desc.mMaxVertices = 256;
desc.SetHullFlag(QF_TRIANGLES);
desc.mVcount = vcount;
desc.mVertices = vertices;
desc.mVertexStride = sizeof(double)*3;
HullError ret = hl.CreateConvexHull(desc,result);
if ( ret == QE_OK )
{
double bmin[3];
double bmax[3];
double diagonal = getBoundingRegion( result.mNumOutputVertices, result.mOutputVertices, sizeof(double)*3, bmin, bmax );
double dx = bmax[0] - bmin[0];
double dy = bmax[1] - bmin[1];
double dz = bmax[2] - bmin[2];
Vector3d<double> center;
center.x = bmin[0] + dx*0.5f;
center.y = bmin[1] + dy*0.5f;
center.z = bmin[2] + dz*0.5f;
double boundVolume = dx*dy*dz;
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 double *p1 = &result.mOutputVertices[i1*3];
const double *p2 = &result.mOutputVertices[i2*3];
const double *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..
double totalVolume = 0;
CTriVector ftris; // 'feature' triangles.
const unsigned int *src = indices;
double 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 double *p1 = &vertices[i1*3];
const double *p2 = &vertices[i2*3];
const double *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 double *p1 = &vertices[i1*3];
const double *p2 = &vertices[i2*3];
const double *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;
}
double 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;
double maxarea = 0;
while ( maxc > CONCAVE_THRESH )
{
unsigned int color = getDebugColor(); //
CTriVector flist;
bool found;
double 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;
}
};

View File

@ -1,81 +0,0 @@
#ifndef COMPUTE_CONCAVITY_H
#define COMPUTE_CONCAVITY_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
class ConvexDecompInterface;
// compute's how 'concave' this object is and returns the total volume of the
// convex hull as well as the volume of the 'concavity' which was found.
double computeConcavity(unsigned int vcount,
const double *vertices,
unsigned int tcount,
const unsigned int *indices,
ConvexDecompInterface *callback,
double *plane,
double &volume);
};
#endif

View File

@ -1,378 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include "fitsphere.h"
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
/*
An Efficient Bounding Sphere
by Jack Ritter
from "Graphics Gems", Academic Press, 1990
*/
/* Routine to calculate tight bounding sphere over */
/* a set of points in 3D */
/* This contains the routine find_bounding_sphere(), */
/* the struct definition, and the globals used for parameters. */
/* The abs() of all coordinates must be < BIGNUMBER */
/* Code written by Jack Ritter and Lyle Rains. */
namespace ConvexDecomposition
{
#define BIGNUMBER 100000000.0 /* hundred million */
static inline void Set(double *n,double x,double y,double z)
{
n[0] = x;
n[1] = y;
n[2] = z;
};
static inline void Copy(double *dest,const double *source)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
}
double computeBoundingSphere(unsigned int vcount,const double *points,double *center)
{
double mRadius;
double mRadius2;
double xmin[3];
double xmax[3];
double ymin[3];
double ymax[3];
double zmin[3];
double zmax[3];
double dia1[3];
double dia2[3];
/* FIRST PASS: find 6 minima/maxima points */
Set(xmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(xmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
Set(ymin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(ymax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
Set(zmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(zmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
for (unsigned i=0; i<vcount; i++)
{
const double *caller_p = &points[i*3];
if (caller_p[0]<xmin[0])
Copy(xmin,caller_p); /* New xminimum point */
if (caller_p[0]>xmax[0])
Copy(xmax,caller_p);
if (caller_p[1]<ymin[1])
Copy(ymin,caller_p);
if (caller_p[1]>ymax[1])
Copy(ymax,caller_p);
if (caller_p[2]<zmin[2])
Copy(zmin,caller_p);
if (caller_p[2]>zmax[2])
Copy(zmax,caller_p);
}
/* Set xspan = distance between the 2 points xmin & xmax (squared) */
double dx = xmax[0] - xmin[0];
double dy = xmax[1] - xmin[1];
double dz = xmax[2] - xmin[2];
double xspan = dx*dx + dy*dy + dz*dz;
/* Same for y & z spans */
dx = ymax[0] - ymin[0];
dy = ymax[1] - ymin[1];
dz = ymax[2] - ymin[2];
double yspan = dx*dx + dy*dy + dz*dz;
dx = zmax[0] - zmin[0];
dy = zmax[1] - zmin[1];
dz = zmax[2] - zmin[2];
double zspan = dx*dx + dy*dy + dz*dz;
/* Set points dia1 & dia2 to the maximally separated pair */
Copy(dia1,xmin);
Copy(dia2,xmax); /* assume xspan biggest */
double maxspan = xspan;
if (yspan>maxspan)
{
maxspan = yspan;
Copy(dia1,ymin);
Copy(dia2,ymax);
}
if (zspan>maxspan)
{
Copy(dia1,zmin);
Copy(dia2,zmax);
}
/* dia1,dia2 is a diameter of initial sphere */
/* calc initial center */
center[0] = (dia1[0]+dia2[0])*0.5f;
center[1] = (dia1[1]+dia2[1])*0.5f;
center[2] = (dia1[2]+dia2[2])*0.5f;
/* calculate initial radius**2 and radius */
dx = dia2[0]-center[0]; /* x component of radius vector */
dy = dia2[1]-center[1]; /* y component of radius vector */
dz = dia2[2]-center[2]; /* z component of radius vector */
mRadius2 = dx*dx + dy*dy + dz*dz;
mRadius = double(sqrt(mRadius2));
/* SECOND PASS: increment current sphere */
if ( 1 )
{
for (unsigned i=0; i<vcount; i++)
{
const double *caller_p = &points[i*3];
dx = caller_p[0]-center[0];
dy = caller_p[1]-center[1];
dz = caller_p[2]-center[2];
double old_to_p_sq = dx*dx + dy*dy + dz*dz;
if (old_to_p_sq > mRadius2) /* do r**2 test first */
{ /* this point is outside of current sphere */
double old_to_p = double(sqrt(old_to_p_sq));
/* calc radius of new sphere */
mRadius = (mRadius + old_to_p) * 0.5f;
mRadius2 = mRadius*mRadius; /* for next r**2 compare */
double old_to_new = old_to_p - mRadius;
/* calc center of new sphere */
double recip = 1.0f /old_to_p;
double cx = (mRadius*center[0] + old_to_new*caller_p[0]) * recip;
double cy = (mRadius*center[1] + old_to_new*caller_p[1]) * recip;
double cz = (mRadius*center[2] + old_to_new*caller_p[2]) * recip;
Set(center,cx,cy,cz);
}
}
}
return mRadius;
}
static inline void Set(float *n,float x,float y,float z)
{
n[0] = x;
n[1] = y;
n[2] = z;
};
static inline void Copy(float *dest,const float *source)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
}
float computeBoundingSphere(unsigned int vcount,const float *points,float *center)
{
float mRadius;
float mRadius2;
float xmin[3];
float xmax[3];
float ymin[3];
float ymax[3];
float zmin[3];
float zmax[3];
float dia1[3];
float dia2[3];
/* FIRST PASS: find 6 minima/maxima points */
Set(xmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(xmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
Set(ymin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(ymax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
Set(zmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
Set(zmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
for (unsigned i=0; i<vcount; i++)
{
const float *caller_p = &points[i*3];
if (caller_p[0]<xmin[0])
Copy(xmin,caller_p); /* New xminimum point */
if (caller_p[0]>xmax[0])
Copy(xmax,caller_p);
if (caller_p[1]<ymin[1])
Copy(ymin,caller_p);
if (caller_p[1]>ymax[1])
Copy(ymax,caller_p);
if (caller_p[2]<zmin[2])
Copy(zmin,caller_p);
if (caller_p[2]>zmax[2])
Copy(zmax,caller_p);
}
/* Set xspan = distance between the 2 points xmin & xmax (squared) */
float dx = xmax[0] - xmin[0];
float dy = xmax[1] - xmin[1];
float dz = xmax[2] - xmin[2];
float xspan = dx*dx + dy*dy + dz*dz;
/* Same for y & z spans */
dx = ymax[0] - ymin[0];
dy = ymax[1] - ymin[1];
dz = ymax[2] - ymin[2];
float yspan = dx*dx + dy*dy + dz*dz;
dx = zmax[0] - zmin[0];
dy = zmax[1] - zmin[1];
dz = zmax[2] - zmin[2];
float zspan = dx*dx + dy*dy + dz*dz;
/* Set points dia1 & dia2 to the maximally separated pair */
Copy(dia1,xmin);
Copy(dia2,xmax); /* assume xspan biggest */
float maxspan = xspan;
if (yspan>maxspan)
{
maxspan = yspan;
Copy(dia1,ymin);
Copy(dia2,ymax);
}
if (zspan>maxspan)
{
Copy(dia1,zmin);
Copy(dia2,zmax);
}
/* dia1,dia2 is a diameter of initial sphere */
/* calc initial center */
center[0] = (dia1[0]+dia2[0])*0.5f;
center[1] = (dia1[1]+dia2[1])*0.5f;
center[2] = (dia1[2]+dia2[2])*0.5f;
/* calculate initial radius**2 and radius */
dx = dia2[0]-center[0]; /* x component of radius vector */
dy = dia2[1]-center[1]; /* y component of radius vector */
dz = dia2[2]-center[2]; /* z component of radius vector */
mRadius2 = dx*dx + dy*dy + dz*dz;
mRadius = float(sqrt(mRadius2));
/* SECOND PASS: increment current sphere */
if ( 1 )
{
for (unsigned i=0; i<vcount; i++)
{
const float *caller_p = &points[i*3];
dx = caller_p[0]-center[0];
dy = caller_p[1]-center[1];
dz = caller_p[2]-center[2];
float old_to_p_sq = dx*dx + dy*dy + dz*dz;
if (old_to_p_sq > mRadius2) /* do r**2 test first */
{ /* this point is outside of current sphere */
float old_to_p = float(sqrt(old_to_p_sq));
/* calc radius of new sphere */
mRadius = (mRadius + old_to_p) * 0.5f;
mRadius2 = mRadius*mRadius; /* for next r**2 compare */
float old_to_new = old_to_p - mRadius;
/* calc center of new sphere */
float recip = 1.0f /old_to_p;
float cx = (mRadius*center[0] + old_to_new*caller_p[0]) * recip;
float cy = (mRadius*center[1] + old_to_new*caller_p[1]) * recip;
float cz = (mRadius*center[2] + old_to_new*caller_p[2]) * recip;
Set(center,cx,cy,cz);
}
}
}
return mRadius;
}
double computeSphereVolume(double r)
{
return (4.0f*3.141592654f*r*r*r)/3.0f; // 4/3 PI R cubed
}
};

View File

@ -1,70 +0,0 @@
#ifndef FIT_SPHERE_H
#define FIT_SPHERE_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
double computeBoundingSphere(unsigned int vcount,const double *points,double *center);
float computeBoundingSphere(unsigned int vcount,const float *points,float *center);
double computeSphereVolume(double r);
};
#endif

View File

@ -1,463 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include "float_math.h"
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// a set of routines that let you do common 3d math
// operations without any vector, matrix, or quaternion
// classes or templates.
//
// a vector (or point) is a 'double *' to 3 doubleing point numbers.
// a matrix is a 'double *' to an array of 16 doubleing point numbers representing a 4x4 transformation matrix compatible with D3D or OGL
// a quaternion is a 'double *' to 4 doubles representing a quaternion x,y,z,w
//
//
//
// Please email bug fixes or improvements to John W. Ratcliff at mailto:jratcliff@infiniplex.net
//
// If you find this source code useful donate a couple of bucks to my kid's fund raising website at
// www.amillionpixels.us
//
// More snippets at: www.codesuppository.com
//
namespace ConvexDecomposition
{
void fm_inverseRT(const double *matrix,const double *pos,double *t) // inverse rotate translate the point.
{
double _x = pos[0] - matrix[3*4+0];
double _y = pos[1] - matrix[3*4+1];
double _z = pos[2] - matrix[3*4+2];
// Multiply inverse-translated source vector by inverted rotation transform
t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z);
t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z);
t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z);
}
void fm_identity(double *matrix) // set 4x4 matrix to identity.
{
matrix[0*4+0] = 1;
matrix[1*4+1] = 1;
matrix[2*4+2] = 1;
matrix[3*4+3] = 1;
matrix[1*4+0] = 0;
matrix[2*4+0] = 0;
matrix[3*4+0] = 0;
matrix[0*4+1] = 0;
matrix[2*4+1] = 0;
matrix[3*4+1] = 0;
matrix[0*4+2] = 0;
matrix[1*4+2] = 0;
matrix[3*4+2] = 0;
matrix[0*4+3] = 0;
matrix[1*4+3] = 0;
matrix[2*4+3] = 0;
}
void fm_eulerMatrix(double ax,double ay,double az,double *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
{
double quat[4];
fm_eulerToQuat(ax,ay,az,quat);
fm_quatToMatrix(quat,matrix);
}
void fm_getAABB(unsigned int vcount,const double *points,unsigned int pstride,double *bmin,double *bmax)
{
const unsigned char *source = (const unsigned char *) points;
bmin[0] = points[0];
bmin[1] = points[1];
bmin[2] = points[2];
bmax[0] = points[0];
bmax[1] = points[1];
bmax[2] = points[2];
for (unsigned int i=1; i<vcount; i++)
{
source+=pstride;
const double *p = (const double *) source;
if ( p[0] < bmin[0] ) bmin[0] = p[0];
if ( p[1] < bmin[1] ) bmin[1] = p[1];
if ( p[2] < bmin[2] ) bmin[2] = p[2];
if ( p[0] > bmax[0] ) bmax[0] = p[0];
if ( p[1] > bmax[1] ) bmax[1] = p[1];
if ( p[2] > bmax[2] ) bmax[2] = p[2];
}
}
void fm_eulerToQuat(double roll,double pitch,double yaw,double *quat) // convert euler angles to quaternion.
{
roll *= 0.5f;
pitch *= 0.5f;
yaw *= 0.5f;
double cr = cos(roll);
double cp = cos(pitch);
double cy = cos(yaw);
double sr = sin(roll);
double sp = sin(pitch);
double sy = sin(yaw);
double cpcy = cp * cy;
double spsy = sp * sy;
double spcy = sp * cy;
double cpsy = cp * sy;
quat[0] = ( sr * cpcy - cr * spsy);
quat[1] = ( cr * spcy + sr * cpsy);
quat[2] = ( cr * cpsy - sr * spcy);
quat[3] = cr * cpcy + sr * spsy;
}
void fm_quatToMatrix(const double *quat,double *matrix) // convert quaterinion rotation to matrix, zeros out the translation component.
{
double xx = quat[0]*quat[0];
double yy = quat[1]*quat[1];
double zz = quat[2]*quat[2];
double xy = quat[0]*quat[1];
double xz = quat[0]*quat[2];
double yz = quat[1]*quat[2];
double wx = quat[3]*quat[0];
double wy = quat[3]*quat[1];
double wz = quat[3]*quat[2];
matrix[0*4+0] = 1 - 2 * ( yy + zz );
matrix[1*4+0] = 2 * ( xy - wz );
matrix[2*4+0] = 2 * ( xz + wy );
matrix[0*4+1] = 2 * ( xy + wz );
matrix[1*4+1] = 1 - 2 * ( xx + zz );
matrix[2*4+1] = 2 * ( yz - wx );
matrix[0*4+2] = 2 * ( xz - wy );
matrix[1*4+2] = 2 * ( yz + wx );
matrix[2*4+2] = 1 - 2 * ( xx + yy );
matrix[3*4+0] = 0.0f;
matrix[3*4+1] = 0.0f;
matrix[3*4+2] = 0.0f;
matrix[0*4+3] = 0.0f;
matrix[1*4+3] = 0.0f;
matrix[2*4+3] = 0.0f;
matrix[3*4+3] =(double) 1.0f;
}
void fm_quatRotate(const double *quat,const double *v,double *r) // rotate a vector directly by a quaternion.
{
double left[4];
left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2];
left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0];
left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1];
left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2];
r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]);
r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]);
r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]);
}
void fm_getTranslation(const double *matrix,double *t)
{
t[0] = matrix[3*4+0];
t[1] = matrix[3*4+1];
t[2] = matrix[3*4+2];
}
void fm_matrixToQuat(const double *matrix,double *quat) // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
{
double tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2];
// check the diagonal
if (tr > 0.0f )
{
double s = (double) sqrt ( (double) (tr + 1.0f) );
quat[3] = s * 0.5f;
s = 0.5f / s;
quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s;
quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s;
quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s;
}
else
{
// diagonal is negative
int nxt[3] = {1, 2, 0};
double qa[4];
int i = 0;
if (matrix[1*4+1] > matrix[0*4+0]) i = 1;
if (matrix[2*4+2] > matrix[i*4+i]) i = 2;
int j = nxt[i];
int k = nxt[j];
double s = sqrt ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) );
qa[i] = s * 0.5f;
if (s != 0.0f ) s = 0.5f / s;
qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s;
qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s;
qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s;
quat[0] = qa[0];
quat[1] = qa[1];
quat[2] = qa[2];
quat[3] = qa[3];
}
}
double fm_sphereVolume(double radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed )
{
return (4.0f / 3.0f ) * FM_PI * radius * radius * radius;
}
double fm_cylinderVolume(double radius,double h)
{
return FM_PI * radius * radius *h;
}
double fm_capsuleVolume(double radius,double h)
{
double volume = fm_sphereVolume(radius); // volume of the sphere portion.
double ch = h-radius*2; // this is the cylinder length
if ( ch > 0 )
{
volume+=fm_cylinderVolume(radius,ch);
}
return volume;
}
void fm_transform(const double *matrix,const double *v,double *t) // rotate and translate this point
{
t[0] = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0];
t[1] = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1];
t[2] = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2];
}
void fm_rotate(const double *matrix,const double *v,double *t) // rotate and translate this point
{
t[0] = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]);
t[1] = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]);
t[2] = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]);
}
double fm_distance(const double *p1,const double *p2)
{
double dx = p1[0] - p2[0];
double dy = p1[1] - p2[1];
double dz = p1[2] - p2[2];
return sqrt( dx*dx + dy*dy + dz *dz );
}
double fm_distanceSquared(const double *p1,const double *p2)
{
double dx = p1[0] - p2[0];
double dy = p1[1] - p2[1];
double dz = p1[2] - p2[2];
return dx*dx + dy*dy + dz *dz;
}
double fm_computePlane(const double *A,const double *B,const double *C,double *n) // returns D
{
double vx = (B[0] - C[0]);
double vy = (B[1] - C[1]);
double vz = (B[2] - C[2]);
double wx = (A[0] - B[0]);
double wy = (A[1] - B[1]);
double wz = (A[2] - B[2]);
double vw_x = vy * wz - vz * wy;
double vw_y = vz * wx - vx * wz;
double vw_z = vx * wy - vy * wx;
double mag = sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
if ( mag < 0.000001f )
{
mag = 0;
}
else
{
mag = 1.0f/mag;
}
double x = vw_x * mag;
double y = vw_y * mag;
double z = vw_z * mag;
double D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2]));
n[0] = x;
n[1] = y;
n[2] = z;
return D;
}
double fm_distToPlane(const double *plane,const double *p) // computes the distance of this point from the plane.
{
return p[0]*plane[0]+p[1]*plane[1]+p[2]*plane[2]+plane[3];
}
double fm_dot(const double *p1,const double *p2)
{
return p1[0]*p2[0]+p1[1]*p2[2]+p1[2]*p2[2];
}
void fm_cross(double *cross,const double *a,const double *b)
{
cross[0] = a[1]*b[2] - a[2]*b[1];
cross[1] = a[2]*b[0] - a[0]*b[2];
cross[2] = a[0]*b[1] - a[1]*b[0];
}
void fm_computeNormalVector(double *n,const double *p1,const double *p2)
{
n[0] = p2[0] - p1[0];
n[1] = p2[1] - p1[1];
n[2] = p2[2] - p1[2];
fm_normalize(n);
}
bool fm_computeWindingOrder(const double *p1,const double *p2,const double *p3) // returns true if the triangle is clockwise.
{
bool ret = false;
double v1[3];
double v2[3];
fm_computeNormalVector(v1,p1,p2); // p2-p1 (as vector) and then normalized
fm_computeNormalVector(v2,p1,p3); // p3-p1 (as vector) and then normalized
double cross[3];
fm_cross(cross, v1, v2 );
double ref[3] = { 1, 0, 0 };
double d = fm_dot( cross, ref );
if ( d <= 0 )
ret = false;
else
ret = true;
return ret;
}
void fm_normalize(double *n) // normalize this vector
{
double dist = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
double mag = 0;
if ( dist > 0.0000001f )
mag = 1.0f / sqrt(dist);
n[0]*=mag;
n[1]*=mag;
n[2]*=mag;
}
}; // end of namespace

View File

@ -1,112 +0,0 @@
#ifndef FLOAT_MATH_H
#define FLOAT_MATH_H
namespace ConvexDecomposition
{
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// a set of routines that let you do common 3d math
// operations without any vector, matrix, or quaternion
// classes or templates.
//
// a vector (or point) is a 'double *' to 3 doubleing point numbers.
// a matrix is a 'double *' to an array of 16 doubleing point numbers representing a 4x4 transformation matrix compatible with D3D or OGL
// a quaternion is a 'double *' to 4 doubles representing a quaternion x,y,z,w
//
//
//
// Please email bug fixes or improvements to John W. Ratcliff at mailto:jratcliff@infiniplex.net
//
// If you find this source code useful donate a couple of bucks to my kid's fund raising website at
// www.amillionpixels.us
//
// More snippets at: www.codesuppository.com
//
const double FM_PI = 3.141592654f;
const double FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f);
const double FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI));
void fm_identity(double *matrix); // set 4x4 matrix to identity.
void fm_inverseRT(const double *matrix,const double *pos,double *t); // inverse rotate translate the point.
void fm_transform(const double *matrix,const double *pos,double *t); // rotate and translate this point.
void fm_rotate(const double *matrix,const double *pos,double *t); // only rotate the point by a 4x4 matrix, don't translate.
void fm_eulerMatrix(double ax,double ay,double az,double *matrix); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_getAABB(unsigned int vcount,const double *points,unsigned int pstride,double *bmin,double *bmax);
void fm_eulerToQuat(double roll,double pitch,double yaw,double *quat); // convert euler angles to quaternion.
void fm_quatToMatrix(const double *quat,double *matrix); // convert quaterinion rotation to matrix, translation set to zero.
void fm_quatRotate(const double *quat,const double *v,double *r); // rotate a vector directly by a quaternion.
void fm_getTranslation(const double *matrix,double *t);
void fm_matrixToQuat(const double *matrix,double *quat); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
double fm_sphereVolume(double radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
double fm_cylinderVolume(double radius,double h);
double fm_capsuleVolume(double radius,double h);
double fm_distance(const double *p1,const double *p2);
double fm_distanceSquared(const double *p1,const double *p2);
double fm_computePlane(const double *p1,const double *p2,const double *p3,double *n); // return D
double fm_distToPlane(const double *plane,const double *pos); // computes the distance of this point from the plane.
double fm_dot(const double *p1,const double *p2);
void fm_cross(double *cross,const double *a,const double *b);
void fm_computeNormalVector(double *n,const double *p1,const double *p2); // as P2-P1 normalized.
bool fm_computeWindingOrder(const double *p1,const double *p2,const double *p3); // returns true if the triangle is clockwise.
void fm_normalize(double *n); // normalize this vector
}; // end of nsamepace
#endif

View File

@ -1,251 +0,0 @@
#include "meshvolume.h"
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
inline double det(const double *p1,const double *p2,const double *p3)
{
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
}
double computeMeshVolume(const double *vertices,unsigned int tcount,const unsigned int *indices)
{
double volume = 0;
const double *p0 = vertices;
for (unsigned int i=0; i<tcount; i++,indices+=3)
{
const double *p1 = &vertices[ indices[0]*3 ];
const double *p2 = &vertices[ indices[1]*3 ];
const double *p3 = &vertices[ indices[2]*3 ];
volume+=det(p1,p2,p3); // compute the volume of the tetrahedran relative to the origin.
}
volume*=(1.0f/6.0f);
if ( volume < 0 )
volume*=-1;
return volume;
}
inline void CrossProduct(const double *a,const double *b,double *cross)
{
cross[0] = a[1]*b[2] - a[2]*b[1];
cross[1] = a[2]*b[0] - a[0]*b[2];
cross[2] = a[0]*b[1] - a[1]*b[0];
}
inline double DotProduct(const double *a,const double *b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
inline double tetVolume(const double *p0,const double *p1,const double *p2,const double *p3)
{
double a[3];
double b[3];
double c[3];
a[0] = p1[0] - p0[0];
a[1] = p1[1] - p0[1];
a[2] = p1[2] - p0[2];
b[0] = p2[0] - p0[0];
b[1] = p2[1] - p0[1];
b[2] = p2[2] - p0[2];
c[0] = p3[0] - p0[0];
c[1] = p3[1] - p0[1];
c[2] = p3[2] - p0[2];
double cross[3];
CrossProduct( b, c, cross );
double volume = DotProduct( a, cross );
if ( volume < 0 )
return -volume;
return volume;
}
inline double det(const double *p0,const double *p1,const double *p2,const double *p3)
{
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
}
double computeMeshVolume2(const double *vertices,unsigned int tcount,const unsigned int *indices)
{
double volume = 0;
const double *p0 = vertices;
for (unsigned int i=0; i<tcount; i++,indices+=3)
{
const double *p1 = &vertices[ indices[0]*3 ];
const double *p2 = &vertices[ indices[1]*3 ];
const double *p3 = &vertices[ indices[2]*3 ];
volume+=tetVolume(p0,p1,p2,p3); // compute the volume of the tetrahdren relative to the root vertice
}
return volume * (1.0f / 6.0f );
}
//** Float versions
inline float det(const float *p1,const float *p2,const float *p3)
{
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
}
float computeMeshVolume(const float *vertices,unsigned int tcount,const unsigned int *indices)
{
float volume = 0;
const float *p0 = vertices;
for (unsigned int i=0; i<tcount; i++,indices+=3)
{
const float *p1 = &vertices[ indices[0]*3 ];
const float *p2 = &vertices[ indices[1]*3 ];
const float *p3 = &vertices[ indices[2]*3 ];
volume+=det(p1,p2,p3); // compute the volume of the tetrahedran relative to the origin.
}
volume*=(1.0f/6.0f);
if ( volume < 0 )
volume*=-1;
return volume;
}
inline void CrossProduct(const float *a,const float *b,float *cross)
{
cross[0] = a[1]*b[2] - a[2]*b[1];
cross[1] = a[2]*b[0] - a[0]*b[2];
cross[2] = a[0]*b[1] - a[1]*b[0];
}
inline float DotProduct(const float *a,const float *b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
inline float tetVolume(const float *p0,const float *p1,const float *p2,const float *p3)
{
float a[3];
float b[3];
float c[3];
a[0] = p1[0] - p0[0];
a[1] = p1[1] - p0[1];
a[2] = p1[2] - p0[2];
b[0] = p2[0] - p0[0];
b[1] = p2[1] - p0[1];
b[2] = p2[2] - p0[2];
c[0] = p3[0] - p0[0];
c[1] = p3[1] - p0[1];
c[2] = p3[2] - p0[2];
float cross[3];
CrossProduct( b, c, cross );
float volume = DotProduct( a, cross );
if ( volume < 0 )
return -volume;
return volume;
}
inline float det(const float *p0,const float *p1,const float *p2,const float *p3)
{
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
}
float computeMeshVolume2(const float *vertices,unsigned int tcount,const unsigned int *indices)
{
float volume = 0;
const float *p0 = vertices;
for (unsigned int i=0; i<tcount; i++,indices+=3)
{
const float *p1 = &vertices[ indices[0]*3 ];
const float *p2 = &vertices[ indices[1]*3 ];
const float *p3 = &vertices[ indices[2]*3 ];
volume+=tetVolume(p0,p1,p2,p3); // compute the volume of the tetrahdren relative to the root vertice
}
return volume * (1.0f / 6.0f );
}
};

View File

@ -1,70 +0,0 @@
#ifndef MESH_VOLUME_H
#define MESH_VOLUME_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
double computeMeshVolume(const double *vertices,unsigned int tcount,const unsigned int *indices);
double computeMeshVolume2(const double *vertices,unsigned int tcount,const unsigned int *indices);
float computeMeshVolume(const float *vertices,unsigned int tcount,const unsigned int *indices);
};
#endif

View File

@ -1,314 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include "planetri.h"
namespace ConvexDecomposition
{
static inline double DistToPt(const double *p,const double *plane)
{
double x = p[0];
double y = p[1];
double z = p[2];
double d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3];
return d;
}
static PlaneTriResult getSidePlane(const double *p,const double *plane,double epsilon)
{
double d = DistToPt(p,plane);
if ( (d+epsilon) > 0 )
return PTR_FRONT; // it is 'in front' within the provided epsilon value.
return PTR_BACK;
}
static void add(const double *p,double *dest,unsigned int tstride,unsigned int &pcount)
{
char *d = (char *) dest;
d = d + pcount*tstride;
dest = (double *) d;
dest[0] = p[0];
dest[1] = p[1];
dest[2] = p[2];
pcount++;
assert( pcount <= 4 );
}
// assumes that the points are on opposite sides of the plane!
static void intersect(const double *p1,const double *p2,double *split,const double *plane)
{
double dp1 = DistToPt(p1,plane);
double dp2 = DistToPt(p2,plane);
double dir[3];
dir[0] = p2[0] - p1[0];
dir[1] = p2[1] - p1[1];
dir[2] = p2[2] - p1[2];
double dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2];
double dot2 = dp1 - plane[3];
double 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];
}
#define MAXPTS 256
class point
{
public:
void set(const double *p)
{
x = p[0];
y = p[1];
z = p[2];
}
double x;
double y;
double z;
};
class polygon
{
public:
polygon(void)
{
mVcount = 0;
}
polygon(const double *p1,const double *p2,const double *p3)
{
mVcount = 3;
mVertices[0].set(p1);
mVertices[1].set(p2);
mVertices[2].set(p3);
}
int NumVertices(void) const { return mVcount; };
const point& Vertex(int index)
{
if ( index < 0 ) index+=mVcount;
return mVertices[index];
};
void set(const point *pts,int count)
{
for (int i=0; i<count; i++)
{
mVertices[i] = pts[i];
}
mVcount = count;
}
int mVcount;
point mVertices[MAXPTS];
};
class plane
{
public:
plane(const double *p)
{
normal.x = p[0];
normal.y = p[1];
normal.z = p[2];
D = p[3];
}
double Classify_Point(const point &p)
{
return p.x*normal.x + p.y*normal.y + p.z*normal.z + D;
}
point normal;
double D;
};
void Split_Polygon(polygon *poly, plane *part, polygon &front, polygon &back)
{
int count = poly->NumVertices ();
int out_c = 0, in_c = 0;
point ptA, ptB,outpts[MAXPTS],inpts[MAXPTS];
double sideA, sideB;
ptA = poly->Vertex (count - 1);
sideA = part->Classify_Point (ptA);
for (int i = -1; ++i < count;)
{
ptB = poly->Vertex(i);
sideB = part->Classify_Point(ptB);
if (sideB > 0)
{
if (sideA < 0)
{
point v;
intersect(&ptB.x, &ptA.x, &v.x, &part->normal.x );
outpts[out_c++] = inpts[in_c++] = v;
}
outpts[out_c++] = ptB;
}
else if (sideB < 0)
{
if (sideA > 0)
{
point v;
intersect(&ptB.x, &ptA.x, &v.x, &part->normal.x );
outpts[out_c++] = inpts[in_c++] = v;
}
inpts[in_c++] = ptB;
}
else
outpts[out_c++] = inpts[in_c++] = ptB;
ptA = ptB;
sideA = sideB;
}
front.set(&outpts[0], out_c);
back.set(&inpts[0], in_c);
}
PlaneTriResult planeTriIntersection(const double *_plane, // the plane equation in Ax+By+Cz+D format
const double *triangle, // the source triangle.
unsigned int tstride, // stride in bytes of the input and output *vertices*
double epsilon, // the co-planer epsilon value.
double *front, // the triangle in front of the
unsigned int &fcount, // number of vertices in the 'front' triangle
double *back, // the triangle in back of the plane
unsigned int &bcount) // the number of vertices in the 'back' triangle.
{
fcount = 0;
bcount = 0;
const char *tsource = (const char *) triangle;
// get the three vertices of the triangle.
const double *p1 = (const double *) (tsource);
const double *p2 = (const double *) (tsource+tstride);
const double *p3 = (const double *) (tsource+tstride*2);
PlaneTriResult r1 = getSidePlane(p1,_plane,epsilon); // compute the side of the plane each vertex is on
PlaneTriResult r2 = getSidePlane(p2,_plane,epsilon);
PlaneTriResult r3 = getSidePlane(p3,_plane,epsilon);
if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane.
{
if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle.
{
add(p1,front,tstride,fcount);
add(p2,front,tstride,fcount);
add(p3,front,tstride,fcount);
}
else
{
add(p1,back,tstride,bcount); // if all three are in 'back' then copy to the 'back' output triangle.
add(p2,back,tstride,bcount);
add(p3,back,tstride,bcount);
}
return r1; // if all three points are on the same side of the plane return result
}
polygon pi(p1,p2,p3);
polygon pfront,pback;
plane part(_plane);
Split_Polygon(&pi,&part,pfront,pback);
for (int i=0; i<pfront.mVcount; i++)
{
add( &pfront.mVertices[i].x, front, tstride, fcount );
}
for (int i=0; i<pback.mVcount; i++)
{
add( &pback.mVertices[i].x, back, tstride, bcount );
}
PlaneTriResult ret = PTR_SPLIT;
if ( fcount == 0 && bcount )
ret = PTR_BACK;
if ( bcount == 0 && fcount )
ret = PTR_FRONT;
return ret;
}
};

View File

@ -1,82 +0,0 @@
#ifndef PLANE_TRI_H
#define PLANE_TRI_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
enum PlaneTriResult
{
PTR_FRONT,
PTR_BACK,
PTR_SPLIT,
};
PlaneTriResult planeTriIntersection(const double *plane, // the plane equation in Ax+By+Cz+D format
const double *triangle, // the source position triangle.
unsigned int tstride, // stride in bytes between vertices of the triangle.
double epsilon, // the co-planer epsilon value.
double *front, // the triangle in front of the
unsigned int &fcount, // number of vertices in the 'front' triangle.
double *back, // the triangle in back of the plane
unsigned int &bcount); // the number of vertices in the 'back' triangle.
};
#endif

View File

@ -1,160 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include "raytri.h"
namespace ConvexDecomposition
{
/* a = b - c */
#define vector(a,b,c) \
(a)[0] = (b)[0] - (c)[0]; \
(a)[1] = (b)[1] - (c)[1]; \
(a)[2] = (b)[2] - (c)[2];
#define innerProduct(v,q) \
((v)[0] * (q)[0] + \
(v)[1] * (q)[1] + \
(v)[2] * (q)[2])
#define crossProduct(a,b,c) \
(a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \
(a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \
(a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1];
bool rayIntersectsTriangle(const double *p,const double *d,const double *v0,const double *v1,const double *v2,double &t)
{
double e1[3],e2[3],h[3],s[3],q[3];
double a,f,u,v;
vector(e1,v1,v0);
vector(e2,v2,v0);
crossProduct(h,d,e2);
a = innerProduct(e1,h);
if (a > -0.00001 && a < 0.00001)
return(false);
f = 1/a;
vector(s,p,v0);
u = f * (innerProduct(s,h));
if (u < 0.0 || u > 1.0)
return(false);
crossProduct(q,s,e1);
v = f * innerProduct(d,q);
if (v < 0.0 || u + v > 1.0)
return(false);
// at this stage we can compute t to find out where
// the intersection point is on the line
t = f * innerProduct(e2,q);
if (t > 0) // ray intersection
return(true);
else // this means that there is a line intersection
// but not a ray intersection
return (false);
}
bool lineIntersectsTriangle(const double *rayStart,const double *rayEnd,const double *p1,const double *p2,const double *p3,double *sect)
{
double dir[3];
dir[0] = rayEnd[0] - rayStart[0];
dir[1] = rayEnd[1] - rayStart[1];
dir[2] = rayEnd[2] - rayStart[2];
double d = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
double r = 1.0f / d;
dir[0]*=r;
dir[1]*=r;
dir[2]*=r;
double t;
bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t );
if ( ret )
{
if ( t > d )
{
sect[0] = rayStart[0] + dir[0]*t;
sect[1] = rayStart[1] + dir[1]*t;
sect[2] = rayStart[2] + dir[2]*t;
}
else
{
ret = false;
}
}
return ret;
}
}; // end of namespace

View File

@ -1,69 +0,0 @@
#ifndef RAY_TRI_H
#define RAY_TRI_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
// returns true if the ray intersects the triangle.
bool lineIntersectsTriangle(const double *rayStart,const double *rayEnd,const double *p1,const double *p2,const double *p3,double *sect);
bool rayIntersectsTriangle(const double *p,const double *d,const double *v0,const double *v1,const double *v2,double &t);
};
#endif

View File

@ -1,339 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <float.h>
#include <math.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include "splitplane.h"
#include "ConvexDecomposition.h"
#include "cd_vector.h"
#include "cd_hull.h"
#include "cd_wavefront.h"
#include "bestfit.h"
#include "planetri.h"
#include "vlookup.h"
#include "meshvolume.h"
#include "bestfitobb.h"
#include "float_math.h"
namespace ConvexDecomposition
{
static void computePlane(const double *A,const double *B,const double *C,double *plane)
{
double vx = (B[0] - C[0]);
double vy = (B[1] - C[1]);
double vz = (B[2] - C[2]);
double wx = (A[0] - B[0]);
double wy = (A[1] - B[1]);
double wz = (A[2] - B[2]);
double vw_x = vy * wz - vz * wy;
double vw_y = vz * wx - vx * wz;
double vw_z = vx * wy - vy * wx;
double mag = sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
if ( mag < 0.000001f )
{
mag = 0;
}
else
{
mag = 1.0f/mag;
}
double x = vw_x * mag;
double y = vw_y * mag;
double z = vw_z * mag;
double D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2]));
plane[0] = x;
plane[1] = y;
plane[2] = z;
plane[3] = D;
}
class Rect3d
{
public:
Rect3d(void) { };
Rect3d(const double *bmin,const double *bmax)
{
mMin[0] = bmin[0];
mMin[1] = bmin[1];
mMin[2] = bmin[2];
mMax[0] = bmax[0];
mMax[1] = bmax[1];
mMax[2] = bmax[2];
}
void SetMin(const double *bmin)
{
mMin[0] = bmin[0];
mMin[1] = bmin[1];
mMin[2] = bmin[2];
}
void SetMax(const double *bmax)
{
mMax[0] = bmax[0];
mMax[1] = bmax[1];
mMax[2] = bmax[2];
}
void SetMin(double x,double y,double z)
{
mMin[0] = x;
mMin[1] = y;
mMin[2] = z;
}
void SetMax(double x,double y,double z)
{
mMax[0] = x;
mMax[1] = y;
mMax[2] = z;
}
double mMin[3];
double mMax[3];
};
void splitRect(unsigned int axis,
const Rect3d &source,
Rect3d &b1,
Rect3d &b2,
const double *midpoint)
{
switch ( axis )
{
case 0:
b1.SetMin(source.mMin);
b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] );
b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] );
b2.SetMax(source.mMax);
break;
case 1:
b1.SetMin(source.mMin);
b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] );
b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] );
b2.SetMax(source.mMax);
break;
case 2:
b1.SetMin(source.mMin);
b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] );
b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] );
b2.SetMax(source.mMax);
break;
}
}
bool computeSplitPlane(unsigned int vcount,
const double *vertices,
unsigned int tcount,
const unsigned int *indices,
ConvexDecompInterface *callback,
double *plane)
{
bool cret = false;
double sides[3];
double matrix[16];
computeBestFitOBB( vcount, vertices, sizeof(double)*3, sides, matrix );
double bmax[3];
double bmin[3];
bmax[0] = sides[0]*0.5f;
bmax[1] = sides[1]*0.5f;
bmax[2] = sides[2]*0.5f;
bmin[0] = -bmax[0];
bmin[1] = -bmax[1];
bmin[2] = -bmax[2];
double dx = sides[0];
double dy = sides[1];
double dz = sides[2];
double laxis = dx;
unsigned int axis = 0;
if ( dy > dx )
{
axis = 1;
laxis = dy;
}
if ( dz > dx && dz > dy )
{
axis = 2;
laxis = dz;
}
double p1[3];
double p2[3];
double p3[3];
p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f;
p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f;
p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f;
Rect3d b(bmin,bmax);
Rect3d b1,b2;
splitRect(axis,b,b1,b2,p1);
// callback->ConvexDebugBound(b1.mMin,b1.mMax,0x00FF00);
// callback->ConvexDebugBound(b2.mMin,b2.mMax,0xFFFF00);
switch ( axis )
{
case 0:
p2[1] = bmin[1];
p2[2] = bmin[2];
if ( dz > dy )
{
p3[1] = bmax[1];
p3[2] = bmin[2];
}
else
{
p3[1] = bmin[1];
p3[2] = bmax[2];
}
break;
case 1:
p2[0] = bmin[0];
p2[2] = bmin[2];
if ( dx > dz )
{
p3[0] = bmax[0];
p3[2] = bmin[2];
}
else
{
p3[0] = bmin[0];
p3[2] = bmax[2];
}
break;
case 2:
p2[0] = bmin[0];
p2[1] = bmin[1];
if ( dx > dy )
{
p3[0] = bmax[0];
p3[1] = bmin[1];
}
else
{
p3[0] = bmin[0];
p3[1] = bmax[1];
}
break;
}
double tp1[3];
double tp2[3];
double tp3[3];
fm_transform(matrix,p1,tp1);
fm_transform(matrix,p2,tp2);
fm_transform(matrix,p3,tp3);
// callback->ConvexDebugTri(p1,p2,p3,0xFF0000);
computePlane(tp1,tp2,tp3,plane);
return true;
}
};

View File

@ -1,76 +0,0 @@
#ifndef SPLIT_PLANE_H
#define SPLIT_PLANE_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
class ConvexDecompInterface;
bool computeSplitPlane(unsigned int vcount,
const double *vertices,
unsigned int tcount,
const unsigned int *indices,
ConvexDecompInterface *callback,
double *plane);
};
#endif

View File

@ -1,410 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
#include <vector> // Include STL vector class.
#include "triangulate.h"
namespace ConvexDecomposition
{
class Vec2d
{
public:
Vec2d(const double *v)
{
mX = v[0];
mY = v[1];
}
Vec2d(double x,double y)
{
Set(x,y);
};
double GetX(void) const { return mX; };
double GetY(void) const { return mY; };
void Set(double x,double y)
{
mX = x;
mY = y;
};
private:
double mX;
double mY;
};// Typedef an STL vector of vertices which are used to represent
// a polygon/contour and a series of triangles.
typedef std::vector< Vec2d > Vec2dVector;
static bool Process(const Vec2dVector &contour,Vec2dVector &result); // compute area of a contour/polygon
static double Area(const Vec2dVector &contour); // decide if point Px/Py is inside triangle defined by (Ax,Ay) (Bx,By) (Cx,Cy)
static bool InsideTriangle(double Ax, double Ay,double Bx, double By,double Cx, double Cy,double Px, double Py);
static bool Snip(const Vec2dVector &contour,int u,int v,int w,int n,int *V);
static const double EPSILON=0.0000000001f;
double Area(const Vec2dVector &contour)
{
int n = contour.size();
double A=0.0f;
for(int p=n-1,q=0; q<n; p=q++)
{
A+= contour[p].GetX()*contour[q].GetY() - contour[q].GetX()*contour[p].GetY();
}
return A*0.5f;
}
/*
InsideTriangle decides if a point P is Inside of the triangle
defined by A, B, C.
*/
bool InsideTriangle(double Ax, double Ay,double Bx, double By,double Cx, double Cy,double Px, double Py)
{
double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
double cCROSSap, bCROSScp, aCROSSbp; ax = Cx - Bx; ay = Cy - By;
bx = Ax - Cx; by = Ay - Cy;
cx = Bx - Ax; cy = By - Ay;
apx= Px - Ax; apy= Py - Ay;
bpx= Px - Bx; bpy= Py - By;
cpx= Px - Cx; cpy= Py - Cy; aCROSSbp = ax*bpy - ay*bpx;
cCROSSap = cx*apy - cy*apx;
bCROSScp = bx*cpy - by*cpx; return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
};
bool Snip(const Vec2dVector &contour,int u,int v,int w,int n,int *V)
{
int p;
double Ax, Ay, Bx, By, Cx, Cy, Px, Py;
Ax = contour[V[u]].GetX();
Ay = contour[V[u]].GetY();
Bx = contour[V[v]].GetX();
By = contour[V[v]].GetY();
Cx = contour[V[w]].GetX();
Cy = contour[V[w]].GetY();
if ( EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false; for (p=0;p<n;p++)
{
if( (p == u) || (p == v) || (p == w) ) continue;
Px = contour[V[p]].GetX();
Py = contour[V[p]].GetY();
if (InsideTriangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py)) return false;
} return true;
}
bool Process(const Vec2dVector &contour,Vec2dVector &result)
{
/* allocate and initialize list of Vertices in polygon */
int n = contour.size();
if ( n < 3 ) return false; int *V = new int[n]; /* we want a counter-clockwise polygon in V */ if ( 0.0f < Area(contour) )
for (int v=0; v<n; v++) V[v] = v;
else
for(int v=0; v<n; v++) V[v] = (n-1)-v; int nv = n; /* remove nv-2 Vertices, creating 1 triangle every time */
int count = 2*nv; /* error detection */
for(int m=0, v=nv-1; nv>2; )
{
/* if we loop, it is probably a non-simple polygon */
if (0 >= (count--))
{
//** Triangulate: ERROR - probable bad polygon!
return false;
} /* three consecutive vertices in current polygon, <u,v,w> */
int u = v ;
if (nv <= u) u = 0; /* previous */
v = u+1; if (nv <= v) v = 0; /* new v */
int w = v+1;
if (nv <= w) w = 0; /* next */
if ( Snip(contour,u,v,w,nv,V) )
{
int a,b,c,s,t; /* true names of the vertices */
a = V[u];
b = V[v];
c = V[w]; /* output Triangle */
result.push_back( contour[a] );
result.push_back( contour[b] );
result.push_back( contour[c] );
m++; /* remove v from remaining polygon */
for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--; /* resest error detection counter */
count = 2*nv;
}
}
delete V;
return true;
}
unsigned int triangulate3d(unsigned int pcount, // number of points in the polygon
const double *vertices, // array of 3d vertices.
double *triangles, // memory to store output triangles
unsigned int maxTri, // maximum triangles we are allowed to output.
const double *plane)
{
unsigned int ret = 0;
FILE *fph = fopen("debug.obj", "wb");
if ( fph )
{
fprintf(fph,"v 10 10 0\r\n");
for (unsigned int i=0; i<pcount; i++)
{
fprintf(fph,"v %f %f %f\r\n", vertices[i*3+0], vertices[i*3+1], vertices[i*3+2]);
}
for (unsigned int i=0; i<pcount; i++)
{
unsigned int next = i+1;
if ( next == pcount ) next = 0;
fprintf(fph,"f %d %d %d\r\n", i+2, 1, next+2 );
}
fclose(fph);
}
if ( pcount >= 3 )
{
double normal[3];
normal[0] = plane[0];
normal[1] = plane[1];
normal[2] = plane[2];
double D = plane[3];
unsigned int i0 = 0;
unsigned int i1 = 1;
unsigned int i2 = 2;
unsigned int axis = 0;
// find the dominant axis.
double dx = fabs(normal[0]);
double dy = fabs(normal[1]);
double dz = fabs(normal[2]);
if ( dx > dy && dx > dz )
{
axis = 0;
i0 = 1;
i1 = 2;
i2 = 0;
}
else if ( dy > dx && dy > dz )
{
i0 = 0;
i1 = 2;
i2 = 1;
axis = 1;
}
else if ( dz > dx && dz > dy )
{
i0 = 0;
i1 = 1;
i2 = 2;
axis = 2;
}
double *ptemp = new double[pcount*2];
double *ptri = new double[maxTri*2*3];
const double *source = vertices;
double *dest = ptemp;
for (unsigned int i=0; i<pcount; i++)
{
dest[0] = source[i0];
dest[1] = source[i1];
dest+=2;
source+=3;
}
ret = triangulate2d(pcount, ptemp, ptri, maxTri );
// ok..now we have to copy it back and project the 3d component.
if ( ret )
{
const double *source = ptri;
double *dest = triangles;
double inverseZ = -1.0f / normal[i2];
for (unsigned int i=0; i<ret*3; i++)
{
dest[i0] = source[0];
dest[i1] = source[1];
dest[i2] = (normal[i0]*source[0] + normal[i1]*source[1] + D ) * inverseZ; // solve for projected component
dest+=3;
source+=2;
}
if ( 1 )
{
FILE *fph = fopen("test.obj","wb");
const double *source = triangles;
for (unsigned int i=0; i<ret*3; i++)
{
fprintf(fph,"v %f %f %f\r\n", source[0], source[1], source[2] );
source+=3;
}
int index = 1;
for (unsigned int i=0; i<ret; i++)
{
fprintf(fph,"f %d %d %d\r\n", index, index+1, index+2 );
index+=3;
}
fclose(fph);
}
}
delete ptri;
delete ptemp;
}
return ret;
}
unsigned int triangulate3d(unsigned int pcount, // number of points in the polygon
const unsigned int *indices, // polygon points using indices
const double *vertices, // base address for array indexing
double *triangles, // buffer to store output 3d triangles.
unsigned int maxTri, // maximum triangles we can output.
const double *plane)
{
unsigned int ret = 0;
if ( pcount )
{
// copy the indexed polygon out as a flat array of vertices.
double *ptemp = new double[pcount*3];
double *dest = ptemp;
for (unsigned int i=0; i<pcount; i++)
{
unsigned int index = indices[i];
const double *source = &vertices[index*3];
*dest++ = *source++;
*dest++ = *source++;
*dest++ = *source++;
}
ret = triangulate3d(pcount,ptemp,triangles,maxTri,plane);
delete ptemp;
}
return ret;
}
unsigned int triangulate2d(unsigned int pcount, // number of points in the polygon
const double *vertices, // address of input points (2d)
double *triangles, // destination buffer for output triangles.
unsigned int maxTri) // maximum number of triangles we can store.
{
unsigned int ret = 0;
const double *source = vertices;
Vec2dVector vlist;
for (unsigned int i=0; i<pcount; i++)
{
Vec2d v(source);
vlist.push_back(v);
source+=2;
}
Vec2dVector result;
bool ok = Process(vlist,result);
if ( ok )
{
ret = result.size()/3;
if ( ret < maxTri )
{
double *dest = triangles;
for (unsigned int i=0; i<ret*3; i++)
{
dest[0] = result[i].GetX();
dest[1] = result[i].GetY();
dest+=2;
}
}
else
{
ret = 0;
}
}
return ret;
}
}; // end of namespace

View File

@ -1,85 +0,0 @@
#ifndef TRIANGULATE_H
#define TRIANGULATE_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
namespace ConvexDecomposition
{
// all 3d triangles should be co-planer. Doesn't bother to check, you should have done that yourself to begin with!
unsigned int triangulate3d(unsigned int pcount, // number of points in the polygon
const double *vertices, // array of 3d vertices.
double *triangles, // memory to store output triangles
unsigned int maxTri,
const double *plane); // maximum triangles we are allowed to output.
unsigned int triangulate3d(unsigned int pcount, // number of points in the polygon
const unsigned int *indices, // polygon points using indices
const double *vertices, // base address for array indexing
double *triangles, // buffer to store output 3d triangles.
unsigned int maxTri,
const double *plane); // maximum triangles we can output.
unsigned int triangulate2d(unsigned int pcount, // number of points in the polygon
const double *vertices, // address of input points (2d)
double *triangles, // destination buffer for output triangles.
unsigned int maxTri); // maximum number of triangles we can store.
};
#endif

View File

@ -1,340 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#pragma warning(disable:4786)
#include <vector>
#include <map>
#include <set>
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// CodeSnippet provided by John W. Ratcliff
// on March 23, 2006.
//
// mailto: jratcliff@infiniplex.net
//
// Personal website: http://jratcliffscarab.blogspot.com
// Coding Website: http://codesuppository.blogspot.com
// FundRaising Blog: http://amillionpixels.blogspot.com
// Fundraising site: http://www.amillionpixels.us
// New Temple Site: http://newtemple.blogspot.com
//
// This snippet shows how to 'hide' the complexity of
// the STL by wrapping some useful piece of functionality
// around a handful of discrete API calls.
//
// This API allows you to create an indexed triangle list
// from a collection of raw input triangles. Internally
// it uses an STL set to build the lookup table very rapidly.
//
// Here is how you would use it to build an indexed triangle
// list from a raw list of triangles.
//
// (1) create a 'VertexLookup' interface by calling
//
// VertexLook vl = Vl_createVertexLookup();
//
// (2) For each vertice in each triangle call:
//
// unsigned int i1 = Vl_getIndex(vl,p1);
// unsigned int i2 = Vl_getIndex(vl,p2);
// unsigned int i3 = Vl_getIndex(vl,p3);
//
// save the 3 indices into your triangle list array.
//
// (3) Get the vertex array by calling:
//
// const double *vertices = Vl_getVertices(vl);
//
// (4) Get the number of vertices so you can copy them into
// your own buffer.
// unsigned int vcount = Vl_getVcount(vl);
//
// (5) Release the VertexLookup interface when you are done with it.
// Vl_releaseVertexLookup(vl);
//
// Teaches the following lessons:
//
// How to wrap the complexity of STL and C++ classes around a
// simple API interface.
//
// How to use an STL set and custom comparator operator for
// a complex data type.
//
// How to create a template class.
//
// How to achieve significant performance improvements by
// taking advantage of built in STL containers in just
// a few lines of code.
//
// You could easily modify this code to support other vertex
// formats with any number of interpolants.
#include "vlookup.h"
namespace ConvexDecomposition
{
class VertexPosition
{
public:
VertexPosition(void) { };
VertexPosition(const double *p)
{
mPos[0] = p[0];
mPos[1] = p[1];
mPos[2] = p[2];
};
void Set(int index,const double *pos)
{
const double * p = &pos[index*3];
mPos[0] = p[0];
mPos[1] = p[1];
mPos[2] = p[2];
};
double GetX(void) const { return mPos[0]; };
double GetY(void) const { return mPos[1]; };
double GetZ(void) const { return mPos[2]; };
double mPos[3];
};
template <typename Type> class VertexLess
{
public:
typedef std::vector< Type > VertexVector;
bool operator()(int v1,int v2) const;
static void SetSearch(const Type& match,VertexVector *list)
{
mFind = match;
mList = list;
};
private:
const Type& Get(int index) const
{
if ( index == -1 ) return mFind;
VertexVector &vlist = *mList;
return vlist[index];
}
static Type mFind; // vertice to locate.
static VertexVector *mList;
};
template <typename Type> class VertexPool
{
public:
typedef std::set<int, VertexLess<Type> > VertexSet;
typedef std::vector< Type > VertexVector;
int GetVertex(const Type& vtx)
{
VertexLess<Type>::SetSearch(vtx,&mVtxs);
typename VertexSet::iterator found;
found = mVertSet.find( -1 );
if ( found != mVertSet.end() )
{
return *found;
}
int idx = (int)mVtxs.size();
mVtxs.push_back( vtx );
mVertSet.insert( idx );
return idx;
};
const double * GetPos(int idx) const
{
return mVtxs[idx].mPos;
}
const Type& Get(int idx) const
{
return mVtxs[idx];
};
unsigned int GetSize(void) const
{
return mVtxs.size();
};
void Clear(int reservesize) // clear the vertice pool.
{
mVertSet.clear();
mVtxs.clear();
mVtxs.reserve(reservesize);
};
const VertexVector& GetVertexList(void) const { return mVtxs; };
void Set(const Type& vtx)
{
mVtxs.push_back(vtx);
}
unsigned int GetVertexCount(void) const
{
return mVtxs.size();
};
Type * GetBuffer(void)
{
return &mVtxs[0];
};
private:
VertexSet mVertSet; // ordered list.
VertexVector mVtxs; // set of vertices.
};
double tmpp[3] = {0,0,0};
template<> VertexPosition VertexLess<VertexPosition>::mFind = tmpp;
template<> std::vector<VertexPosition > *VertexLess<VertexPosition>::mList =0;
enum RDIFF
{
RD_EQUAL,
RD_LESS,
RD_GREATER
};
static RDIFF relativeDiff(const double *a,const double *b,double magnitude)
{
RDIFF ret = RD_EQUAL;
double m2 = magnitude*magnitude;
double dx = a[0]-b[0];
double dy = a[1]-b[1];
double dz = a[2]-b[2];
double d2 = (dx*dx)+(dy*dy)+(dz*dz);
if ( d2 > m2 )
{
if ( a[0] < b[0] ) ret = RD_LESS;
else if ( a[0] > b[0] ) ret = RD_GREATER;
else if ( a[1] < b[1] ) ret = RD_LESS;
else if ( a[1] > b[1] ) ret = RD_GREATER;
else if ( a[2] < b[2] ) ret = RD_LESS;
else if ( a[2] > b[2] ) ret = RD_GREATER;
}
return ret;
}
template<>
bool VertexLess<VertexPosition>::operator()(int v1,int v2) const
{
bool ret = false;
const VertexPosition& a = Get(v1);
const VertexPosition& b = Get(v2);
RDIFF d = relativeDiff(a.mPos,b.mPos,0.0001f);
if ( d == RD_LESS ) ret = true;
return ret;
};
VertexLookup Vl_createVertexLookup(void)
{
VertexLookup ret = new VertexPool< VertexPosition >;
return ret;
}
void Vl_releaseVertexLookup(VertexLookup vlook)
{
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
delete vp;
}
unsigned int Vl_getIndex(VertexLookup vlook,const double *pos) // get index.
{
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
VertexPosition p(pos);
return vp->GetVertex(p);
}
const double * Vl_getVertices(VertexLookup vlook)
{
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
return vp->GetPos(0);
}
unsigned int Vl_getVcount(VertexLookup vlook)
{
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
return vp->GetVertexCount();
}
}; // end of namespace

View File

@ -1,143 +0,0 @@
#ifndef VLOOKUP_H
#define VLOOKUP_H
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/
// CodeSnippet provided by John W. Ratcliff
// on March 23, 2006.
//
// mailto: jratcliff@infiniplex.net
//
// Personal website: http://jratcliffscarab.blogspot.com
// Coding Website: http://codesuppository.blogspot.com
// FundRaising Blog: http://amillionpixels.blogspot.com
// Fundraising site: http://www.amillionpixels.us
// New Temple Site: http://newtemple.blogspot.com
//
// This snippet shows how to 'hide' the complexity of
// the STL by wrapping some useful piece of functionality
// around a handful of discrete API calls.
//
// This API allows you to create an indexed triangle list
// from a collection of raw input triangles. Internally
// it uses an STL set to build the lookup table very rapidly.
//
// Here is how you would use it to build an indexed triangle
// list from a raw list of triangles.
//
// (1) create a 'VertexLookup' interface by calling
//
// VertexLook vl = Vl_createVertexLookup();
//
// (2) For each vertice in each triangle call:
//
// unsigned int i1 = Vl_getIndex(vl,p1);
// unsigned int i2 = Vl_getIndex(vl,p2);
// unsigned int i3 = Vl_getIndex(vl,p3);
//
// save the 3 indices into your triangle list array.
//
// (3) Get the vertex array by calling:
//
// const double *vertices = Vl_getVertices(vl);
//
// (4) Get the number of vertices so you can copy them into
// your own buffer.
// unsigned int vcount = Vl_getVcount(vl);
//
// (5) Release the VertexLookup interface when you are done with it.
// Vl_releaseVertexLookup(vl);
//
// Teaches the following lessons:
//
// How to wrap the complexity of STL and C++ classes around a
// simple API interface.
//
// How to use an STL set and custom comparator operator for
// a complex data type.
//
// How to create a template class.
//
// How to achieve significant performance improvements by
// taking advantage of built in STL containers in just
// a few lines of code.
//
// You could easily modify this code to support other vertex
// formats with any number of interpolants.
//
// Hide C++ classes from the rest of your application by
// keeping them in the CPP and wrapping them in a namespace
// Uses an STL set to create an index table for a bunch of vertex positions
// used typically to re-index a collection of raw triangle data.
namespace ConvexDecomposition
{
typedef void * VertexLookup;
VertexLookup Vl_createVertexLookup(void);
void Vl_releaseVertexLookup(VertexLookup vlook);
unsigned int Vl_getIndex(VertexLookup vlook,const double *pos); // get index.
const double * Vl_getVertices(VertexLookup vlook);
unsigned int Vl_getVcount(VertexLookup vlook);
};
#endif

View File

@ -1,668 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <float.h>
#include <vector>
#include "./ConvexDecomposition/ConvexDecomposition.h"
#include "./ConvexDecomposition/cd_wavefront.h"
using namespace ConvexDecomposition;
// Test application to demonstrate how to use the ConvexDecomposition system.
typedef std::vector< ConvexResult * > ConvexResultVector;
static const char * fstring(float v)
{
static char data[64*16];
static int index=0;
char *ret = &data[index*64];
index++;
if (index == 16 ) index = 0;
if ( v == FLT_MIN ) return "-INF"; // collada notation for FLT_MIN and FLT_MAX
if ( v == FLT_MAX ) return "INF";
if ( v == 1 )
{
strcpy(ret,"1");
}
else if ( v == 0 )
{
strcpy(ret,"0");
}
else if ( v == - 1 )
{
strcpy(ret,"-1");
}
else
{
sprintf(ret,"%.9f", v );
const char *dot = strstr(ret,".");
if ( dot )
{
int len = (int)strlen(ret);
char *foo = &ret[len-1];
while ( *foo == '0' ) foo--;
if ( *foo == '.' )
*foo = 0;
else
foo[1] = 0;
}
}
return ret;
}
class CBuilder : public ConvexDecompInterface
{
public:
CBuilder(const char *fname,const DecompDesc &d)
{
strcpy(mBaseName,fname);
char *dot = strstr(mBaseName,".");
if ( dot ) *dot = 0;
sprintf(mObjName,"%s_convex.obj", mBaseName );
mBaseCount = 0;
mHullCount = 0;
mSkinWidth = (float)d.mSkinWidth;
mFph = fopen(mObjName,"wb");
printf("########################################################################\r\n");
printf("# Perfomring approximate convex decomposition for triangle mesh %s\r\n", fname );
printf("# Input Mesh has %d vertices and %d triangles.\r\n", d.mVcount, d.mTcount );
printf("# Recursion depth: %d\r\n", d.mDepth );
printf("# Concavity Threshold Percentage: %0.2f\r\n", d.mCpercent );
printf("# Hull Merge Volume Percentage: %0.2f\r\n", d.mPpercent );
printf("# Maximum output vertices per hull: %d\r\n", d.mMaxVertices );
printf("# Hull Skin Width: %0.2f\r\n", d.mSkinWidth );
printf("########################################################################\r\n");
if ( mFph )
{
fprintf(mFph,"########################################################################\r\n");
fprintf(mFph,"# Approximate convex decomposition for triangle mesh %s\r\n", fname );
fprintf(mFph,"# Input Mesh has %d vertices and %d triangles.\r\n", d.mVcount, d.mTcount );
fprintf(mFph,"# Recursion depth: %d\r\n", d.mDepth );
fprintf(mFph,"# Concavity Threshold Percentage: %0.2f\r\n", d.mCpercent );
fprintf(mFph,"# Hull Merge Volume Percentage: %0.2f\r\n", d.mPpercent );
fprintf(mFph,"# Maximum output vertices per hull: %d\r\n", d.mMaxVertices );
fprintf(mFph,"# Hull Skin Width: %0.2f\r\n", d.mSkinWidth );
fprintf(mFph,"########################################################################\r\n");
printf("Opened Wavefront file %s for output.\r\n", mObjName );
}
else
{
printf("Failed to open output file %s\r\n", mObjName );
}
}
~CBuilder(void)
{
if ( mFph )
{
fclose(mFph);
}
for (unsigned int i=0; i<mHulls.size(); i++)
{
ConvexResult *cr = mHulls[i];
delete cr;
}
}
virtual void ConvexDecompResult(ConvexResult &result)
{
// we have a hull...
mHullCount++;
printf("Received hull %d HullVolume(%0.3f)\r\n", mHullCount, result.mHullVolume );
if ( mFph )
{
ConvexResult *cr = new ConvexResult(result);
mHulls.push_back(cr);
fprintf(mFph,"########################################################################\r\n");
fprintf(mFph,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount );
fprintf(mFph,"########################################################################\r\n");
for (unsigned int i=0; i<result.mHullVcount; i++)
{
const double *p = &result.mHullVertices[i*3];
fprintf(mFph,"v %0.9f %0.9f %0.9f\r\n", (float)p[0], (float)p[1], (float)p[2] );
}
if ( 1 )
{
const unsigned int *src = result.mHullIndices;
for (unsigned int i=0; i<result.mHullTcount; i++)
{
unsigned int i1 = *src++;
unsigned int i2 = *src++;
unsigned int i3 = *src++;
i1+=mBaseCount;
i2+=mBaseCount;
i3+=mBaseCount;
fprintf(mFph,"f %d %d %d\r\n", i1+1, i2+1, i3+1 );
}
}
mBaseCount+=result.mHullVcount; // advance the 'base index' counter.
}
}
void saveCOLLADA(FILE *fph,unsigned int index,ConvexResult *cr)
{
fprintf(fph," <geometry id=\"%s_%d-Mesh\" name=\"%s_%d-Mesh\">\r\n", mBaseName, index, mBaseName, index);
fprintf(fph," <convex_mesh>\r\n");
fprintf(fph," <source id=\"%s_%d-Position\">\r\n", mBaseName, index);
fprintf(fph," <float_array count=\"%d\" id=\"%s_%d-Position-array\">\r\n", cr->mHullVcount*3, mBaseName, index);
fprintf(fph," ");
for (unsigned int i=0; i<cr->mHullVcount; i++)
{
const double *p = &cr->mHullVertices[i*3];
fprintf(fph,"%s %s %s ", fstring((float)p[0]), fstring((float)p[1]), fstring((float)p[2]) );
if ( ((i+1)&3) == 0 && (i+1) < cr->mHullVcount )
{
fprintf(fph,"\r\n");
fprintf(fph," ");
}
}
fprintf(fph,"\r\n");
fprintf(fph," </float_array>\r\n");
fprintf(fph," <technique_common>\r\n");
fprintf(fph," <accessor count=\"%d\" source=\"#%s_%d-Position-array\" stride=\"3\">\r\n", cr->mHullVcount, mBaseName, index );
fprintf(fph," <param name=\"X\" type=\"float\"/>\r\n");
fprintf(fph," <param name=\"Y\" type=\"float\"/>\r\n");
fprintf(fph," <param name=\"Z\" type=\"float\"/>\r\n");
fprintf(fph," </accessor>\r\n");
fprintf(fph," </technique_common>\r\n");
fprintf(fph," </source>\r\n");
fprintf(fph," <vertices id=\"%s_%d-Vertex\">\r\n", mBaseName, index);
fprintf(fph," <input semantic=\"POSITION\" source=\"#%s_%d-Position\"/>\r\n", mBaseName, index);
fprintf(fph," </vertices>\r\n");
fprintf(fph," <triangles material=\"Material\" count=\"%d\">\r\n", cr->mHullTcount );
fprintf(fph," <input offset=\"0\" semantic=\"VERTEX\" source=\"#%s_%d-Vertex\"/>\r\n", mBaseName, index);
fprintf(fph," <p>\r\n");
fprintf(fph," ");
for (unsigned int i=0; i<cr->mHullTcount; i++)
{
unsigned int *tri = &cr->mHullIndices[i*3];
fprintf(fph,"%d %d %d ", tri[0], tri[1], tri[2] );
if ( ((i+1)&3) == 0 && (i+1) < cr->mHullTcount )
{
fprintf(fph,"\r\n");
fprintf(fph," ");
}
}
fprintf(fph,"\r\n");
fprintf(fph," </p>\r\n");
fprintf(fph," </triangles>\r\n");
fprintf(fph," </convex_mesh>\r\n");
fprintf(fph," </geometry>\r\n");
}
void saveCOLLADA(void)
{
char scratch[512];
sprintf(scratch,"%s.dae", mBaseName );
FILE *fph = fopen(scratch,"wb");
if ( fph )
{
printf("Saving convex decomposition of %d hulls to COLLADA file '%s'\r\n", (int)mHulls.size(), scratch );
fprintf(fph,"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
fprintf(fph,"<COLLADA version=\"1.4.0\" xmlns=\"http://www.collada.org/2005/11/COLLADASchema\">\r\n");
fprintf(fph," <asset>\r\n");
fprintf(fph," <contributor>\r\n");
fprintf(fph," <author>NxuStream2 converter - http://www.ageia.com</author>\r\n");
fprintf(fph," <authoring_tool>PhysX Rocket, PhysX Viewer, or CreateDynamics</authoring_tool>\r\n");
fprintf(fph," <comments>questions to: jratcliff@ageia.com</comments>\r\n");
fprintf(fph," <copyright></copyright>\r\n");
fprintf(fph," <source_data>chair_gothic_tilted</source_data>\r\n");
fprintf(fph," </contributor>\r\n");
fprintf(fph," <unit meter=\"1\" name=\"meter\"/>\r\n");
fprintf(fph," <up_axis>Y_UP</up_axis>\r\n");
fprintf(fph," </asset>\r\n");
fprintf(fph," <library_materials>\r\n");
fprintf(fph," <material id=\"Material\" name=\"Material\">\r\n");
fprintf(fph," <instance_effect url=\"#Material-fx\"></instance_effect>\r\n");
fprintf(fph," </material>\r\n");
fprintf(fph," </library_materials>\r\n");
fprintf(fph," <library_effects>\r\n");
fprintf(fph," <effect id=\"Material-fx\" name=\"Material\">\r\n");
fprintf(fph," <profile_COMMON>\r\n");
fprintf(fph," <technique id=\"Material-fx-COMMON\" sid=\"COMMON\">\r\n");
fprintf(fph," <phong>\r\n");
fprintf(fph," <ambient>\r\n");
fprintf(fph," <color>0.803922 0.588235 0.92549 1</color>\r\n");
fprintf(fph," </ambient>\r\n");
fprintf(fph," <diffuse>\r\n");
fprintf(fph," <color>0.803922 0.588235 0.92549 1</color>\r\n");
fprintf(fph," </diffuse>\r\n");
fprintf(fph," <specular>\r\n");
fprintf(fph," <color>0.631373 0.631373 0.631373 1</color>\r\n");
fprintf(fph," </specular>\r\n");
fprintf(fph," <shininess>\r\n");
fprintf(fph," <float>1</float>\r\n");
fprintf(fph," </shininess>\r\n");
fprintf(fph," <reflective>\r\n");
fprintf(fph," <color>0 0 0 1</color>\r\n");
fprintf(fph," </reflective>\r\n");
fprintf(fph," <transparent>\r\n");
fprintf(fph," <color>1 1 1 1</color>\r\n");
fprintf(fph," </transparent>\r\n");
fprintf(fph," <transparency>\r\n");
fprintf(fph," <float>0</float>\r\n");
fprintf(fph," </transparency>\r\n");
fprintf(fph," </phong>\r\n");
fprintf(fph," </technique>\r\n");
fprintf(fph," </profile_COMMON>\r\n");
fprintf(fph," </effect>\r\n");
fprintf(fph," </library_effects>\r\n");
fprintf(fph," <library_geometries>\r\n");
for (unsigned int i=0; i<mHulls.size(); i++)
{
ConvexResult *cr = mHulls[i];
saveCOLLADA(fph,i,cr);
}
fprintf(fph," </library_geometries>\r\n");
fprintf(fph," <library_visual_scenes>\r\n");
fprintf(fph," <visual_scene id=\"Scene0-Visual\" name=\"Scene0-Visual\">\r\n");
fprintf(fph," <node id=\"%s-Node\" name=\"%s\" type=\"NODE\">\r\n", mBaseName, mBaseName );
fprintf(fph," <translate>0 0 0</translate>\r\n");
fprintf(fph," <rotate>1 0 0 0</rotate>\r\n");
fprintf(fph," </node>\r\n");
fprintf(fph," </visual_scene>\r\n");
fprintf(fph," </library_visual_scenes>\r\n");
fprintf(fph," <library_physics_materials>\r\n");
fprintf(fph," <physics_material id=\"pmat0_0-PhysicsMaterial\" name=\"pmat0_0-PhysicsMaterial\">\r\n");
fprintf(fph," <technique_common>\r\n");
fprintf(fph," <dynamic_friction>0.5</dynamic_friction>\r\n");
fprintf(fph," <restitution>0</restitution>\r\n");
fprintf(fph," <static_friction>0.5</static_friction>\r\n");
fprintf(fph," </technique_common>\r\n");
fprintf(fph," </physics_material>\r\n");
fprintf(fph," </library_physics_materials>\r\n");
fprintf(fph," <library_physics_models>\r\n");
fprintf(fph," <physics_model id=\"Scene0-PhysicsModel\">\r\n");
fprintf(fph," <rigid_body sid=\"%s-RigidBody\" name=\"%s\">\r\n", mBaseName, mBaseName);
fprintf(fph," <technique_common>\r\n");
fprintf(fph," <instance_physics_material url=\"#pmat0_0-PhysicsMaterial\"/>\r\n");
for (unsigned int i=0; i<mHulls.size(); i++)
{
ConvexResult *ch = mHulls[i];
fprintf(fph," <shape>\r\n");
fprintf(fph," <translate>0 0 0</translate>\r\n");
fprintf(fph," <rotate>1 0 0 0</rotate>\r\n");
fprintf(fph," <instance_physics_material url=\"#pmat0_0-PhysicsMaterial\"/>\r\n");
fprintf(fph," <density>1</density>\r\n");
fprintf(fph," <extra>\r\n");
fprintf(fph," <technique profile=\"PhysX\">\r\n");
fprintf(fph," <skinWidth>%s</skinWidth>\r\n", fstring( mSkinWidth ) );
fprintf(fph," </technique>\r\n");
fprintf(fph," </extra>\r\n");
fprintf(fph," <instance_geometry url=\"%s_%d-Mesh\"/>\r\n", mBaseName, i);
fprintf(fph," </shape>\r\n");
}
fprintf(fph," <dynamic>true</dynamic>\r\n");
fprintf(fph," <mass>1</mass>\r\n");
fprintf(fph," </technique_common>\r\n");
fprintf(fph," <extra>\r\n");
fprintf(fph," <technique profile=\"PhysX\">\r\n");
fprintf(fph," <extra>\r\n");
fprintf(fph," <technique profile=\"PhysX\">\r\n");
fprintf(fph," <linearDamping>0</linearDamping>\r\n");
fprintf(fph," <angularDamping>0</angularDamping>\r\n");
fprintf(fph," <solverIterationCount>32</solverIterationCount>\r\n");
fprintf(fph," </technique>\r\n");
fprintf(fph," </extra>\r\n");
fprintf(fph," <disable_collision>false</disable_collision>\r\n");
fprintf(fph," </technique>\r\n");
fprintf(fph," </extra>\r\n");
fprintf(fph," </rigid_body>\r\n");
fprintf(fph," </physics_model>\r\n");
fprintf(fph," </library_physics_models>\r\n");
fprintf(fph," <library_physics_scenes>\r\n");
fprintf(fph," <physics_scene id=\"Scene0-Physics\">\r\n");
fprintf(fph," <instance_physics_model url=\"#Scene0-PhysicsModel\">\r\n");
fprintf(fph," <instance_rigid_body target=\"#%s-Node\" body=\"%s-RigidBody\"/>\r\n", mBaseName, mBaseName );
fprintf(fph," <extra>\r\n");
fprintf(fph," <technique profile=\"PhysX\">\r\n");
fprintf(fph," </technique>\r\n");
fprintf(fph," </extra>\r\n");
fprintf(fph," </instance_physics_model>\r\n");
fprintf(fph," <technique_common>\r\n");
fprintf(fph," <gravity>0 -9.800000191 0</gravity>\r\n");
fprintf(fph," </technique_common>\r\n");
fprintf(fph," </physics_scene>\r\n");
fprintf(fph," </library_physics_scenes>\r\n");
fprintf(fph," <scene>\r\n");
fprintf(fph," <instance_visual_scene url=\"#Scene0-Visual\"/>\r\n");
fprintf(fph," <instance_physics_scene url=\"#Scene0-Physics\"/>\r\n");
fprintf(fph," </scene>\r\n");
fprintf(fph,"</COLLADA>\r\n");
fclose(fph);
}
else
{
printf("Failed to open file '%s' for write access.\r\n", scratch );
}
}
void saveXML(FILE *fph,unsigned int index,ConvexResult *cr)
{
fprintf(fph," <NxConvexMeshDesc id=\"%s_%d\">\r\n", mBaseName, index);
fprintf(fph," <points>\r\n");
fprintf(fph," ");
for (unsigned int i=0; i<cr->mHullVcount; i++)
{
const double *p = &cr->mHullVertices[i*3];
fprintf(fph,"%s %s %s ", fstring((float)p[0]), fstring((float)p[1]), fstring((float)p[2]) );
if ( ((i+1)&3) == 0 && (i+1) < cr->mHullVcount )
{
fprintf(fph,"\r\n");
fprintf(fph," ");
}
}
fprintf(fph,"\r\n");
fprintf(fph," </points>\r\n");
fprintf(fph," <triangles>\r\n");
fprintf(fph," ");
for (unsigned int i=0; i<cr->mHullTcount; i++)
{
unsigned int *tri = &cr->mHullIndices[i*3];
fprintf(fph,"%d %d %d ", tri[0], tri[1], tri[2] );
if ( ((i+1)&3) == 0 && (i+1) < cr->mHullTcount )
{
fprintf(fph,"\r\n");
fprintf(fph," ");
}
}
fprintf(fph,"\r\n");
fprintf(fph," </triangles>\r\n");
fprintf(fph," </NxConvexMeshDesc>\r\n");
}
void saveNxuStream(void)
{
char scratch[512];
sprintf(scratch,"%s.xml", mBaseName );
FILE *fph = fopen(scratch,"wb");
if ( fph )
{
printf("Saving convex decomposition of %d hulls to NxuStream file '%s'\r\n", mHulls.size(), scratch );
fprintf(fph,"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
fprintf(fph," <NXUSTREAM2>\r\n");
fprintf(fph," <NxuPhysicsCollection id=\"beshon\" sdkVersion=\"244\" nxuVersion=\"100\">\r\n");
fprintf(fph," <NxPhysicsSDKDesc id=\"SDK\">\r\n");
fprintf(fph," <hwPageSize>65536</hwPageSize>\r\n");
fprintf(fph," <hwPageMax>256</hwPageMax>\r\n");
fprintf(fph," <hwConvexMax>2048</hwConvexMax>\r\n");
fprintf(fph," </NxPhysicsSDKDesc>\r\n");
for (unsigned int i=0; i<mHulls.size(); i++)
{
saveXML(fph, i, mHulls[i] );
}
fprintf(fph," <NxSceneDesc id=\"%s\">\r\n", mBaseName);
fprintf(fph," <filterBool>false</filterBool>\r\n");
fprintf(fph," <filterOp0>NX_FILTEROP_AND</filterOp0>\r\n");
fprintf(fph," <filterOp1>NX_FILTEROP_AND</filterOp1>\r\n");
fprintf(fph," <filterOp2>NX_FILTEROP_AND</filterOp2>\r\n");
fprintf(fph," <NxGroupsMask id=\"groupMask0\" bits0=\"0\" bits1=\"0\" bits2=\"0\" bits3=\"0\"/>\r\n");
fprintf(fph," <NxGroupsMask id=\"groupMask1\" bits0=\"0\" bits1=\"0\" bits2=\"0\" bits3=\"0\"/>\r\n");
fprintf(fph," <gravity>0 -9.800000191 0</gravity>\r\n");
fprintf(fph," <maxTimestep>0.016666668</maxTimestep>\r\n");
fprintf(fph," <maxIter>8</maxIter>\r\n");
fprintf(fph," <timeStepMethod>NX_TIMESTEP_FIXED</timeStepMethod>\r\n");
fprintf(fph," <maxBounds>FLT_MIN FLT_MIN FLT_MIN FLT_MAX FLT_MAX FLT_MAX</maxBounds>\r\n");
fprintf(fph," <NxSceneLimits id=\"limits\">\r\n");
fprintf(fph," <maxNbActors>0</maxNbActors>\r\n");
fprintf(fph," <maxNbBodies>0</maxNbBodies>\r\n");
fprintf(fph," <maxNbStaticShapes>0</maxNbStaticShapes>\r\n");
fprintf(fph," <maxNbDynamicShapes>0</maxNbDynamicShapes>\r\n");
fprintf(fph," <maxNbJoints>0</maxNbJoints>\r\n");
fprintf(fph," </NxSceneLimits>\r\n");
fprintf(fph," <simType>NX_SIMULATION_SW</simType>\r\n");
fprintf(fph," <groundPlane>true</groundPlane>\r\n");
fprintf(fph," <boundsPlanes>false</boundsPlanes>\r\n");
fprintf(fph," <NxSceneFlags id=\"flags\">\r\n");
fprintf(fph," <NX_SF_DISABLE_SSE>false</NX_SF_DISABLE_SSE>\r\n");
fprintf(fph," <NX_SF_DISABLE_COLLISIONS>false</NX_SF_DISABLE_COLLISIONS>\r\n");
fprintf(fph," <NX_SF_SIMULATE_SEPARATE_THREAD>true</NX_SF_SIMULATE_SEPARATE_THREAD>\r\n");
fprintf(fph," <NX_SF_ENABLE_MULTITHREAD>false</NX_SF_ENABLE_MULTITHREAD>\r\n");
fprintf(fph," </NxSceneFlags>\r\n");
fprintf(fph," <internalThreadCount>0</internalThreadCount>\r\n");
fprintf(fph," <backgroundThreadCount>0</backgroundThreadCount>\r\n");
fprintf(fph," <threadMask>1431655764</threadMask>\r\n");
fprintf(fph," <backgroundThreadMask>1431655764</backgroundThreadMask>\r\n");
fprintf(fph," <NxMaterialDesc id=\"Material_0\" userProperties=\"\" hasSpring=\"false\" materialIndex=\"0\">\r\n");
fprintf(fph," <dynamicFriction>0.5</dynamicFriction>\r\n");
fprintf(fph," <staticFriction>0.5</staticFriction>\r\n");
fprintf(fph," <restitution>0</restitution>\r\n");
fprintf(fph," <dynamicFrictionV>0</dynamicFrictionV>\r\n");
fprintf(fph," <staticFrictionV>0</staticFrictionV>\r\n");
fprintf(fph," <frictionCombineMode>NX_CM_AVERAGE</frictionCombineMode>\r\n");
fprintf(fph," <restitutionCombineMode>NX_CM_AVERAGE</restitutionCombineMode>\r\n");
fprintf(fph," <dirOfAnisotropy>1 0 0</dirOfAnisotropy>\r\n");
fprintf(fph," <NxMaterialFlag id=\"flags\">\r\n");
fprintf(fph," <NX_MF_ANISOTROPIC>false</NX_MF_ANISOTROPIC>\r\n");
fprintf(fph," <NX_MF_DISABLE_FRICTION>false</NX_MF_DISABLE_FRICTION>\r\n");
fprintf(fph," <NX_MF_DISABLE_STRONG_FRICTION>false</NX_MF_DISABLE_STRONG_FRICTION>\r\n");
fprintf(fph," </NxMaterialFlag>\r\n");
fprintf(fph," </NxMaterialDesc>\r\n");
fprintf(fph," <NxActorDesc id=\"%s\" userProperties=\"\" hasBody=\"true\" name=\"%s\">\r\n", mBaseName, mBaseName);
fprintf(fph," <globalPose>1 0 0 0 1 0 0 0 1 0 0 0 </globalPose>\r\n");
fprintf(fph," <NxBodyDesc>\r\n");
fprintf(fph," <mass>1</mass>\r\n");
fprintf(fph," <linearDamping>0</linearDamping>\r\n");
fprintf(fph," <angularDamping>0</angularDamping>\r\n");
fprintf(fph," <solverIterationCount>32</solverIterationCount>\r\n");
fprintf(fph," <NxBodyFlag id=\"flags\">\r\n");
fprintf(fph," <NX_BF_POSE_SLEEP_TEST>true</NX_BF_POSE_SLEEP_TEST>\r\n");
fprintf(fph," <NX_AF_DISABLE_COLLISION>false</NX_AF_DISABLE_COLLISION>\r\n");
fprintf(fph," </NxBodyFlag>\r\n");
fprintf(fph," </NxBodyDesc>\r\n");
fprintf(fph," <name>Bip01 Pelvis</name>\r\n");
for (unsigned int i=0; i<mHulls.size(); i++)
{
fprintf(fph," <NxConvexShapeDesc id=\"Shape_%d\" meshData=\"%s_%d\">\r\n", i, mBaseName, i);
fprintf(fph," <NxShapeDesc>\r\n");
fprintf(fph," <localPose>1 0 0 0 1 0 0 0 1 0 0 0 </localPose>\r\n");
fprintf(fph," <skinWidth>0</skinWidth>\r\n");
fprintf(fph," </NxShapeDesc>\r\n");
fprintf(fph," </NxConvexShapeDesc>\r\n");
}
fprintf(fph," </NxActorDesc>\r\n");
fprintf(fph," </NxSceneDesc>\r\n");
fprintf(fph," <NxSceneInstance id=\"%s\">\r\n", mBaseName);
fprintf(fph," <sceneName>beshon</sceneName>\r\n");
fprintf(fph," <NxuUserProperties></NxuUserProperties>\r\n");
fprintf(fph," <rootNode>1 0 0 0 1 0 0 0 1 0 0 0</rootNode>\r\n");
fprintf(fph," <newScene>false</newScene>\r\n");
fprintf(fph," <ignorePlane>true</ignorePlane>\r\n");
fprintf(fph," <numSceneInstances>0</numSceneInstances>\r\n");
fprintf(fph," </NxSceneInstance>\r\n");
fprintf(fph," </NxuPhysicsCollection>\r\n");
fprintf(fph,"</NXUSTREAM2>\r\n");
}
else
{
printf("Failed to open file '%s' for write access.\r\n", scratch );
}
}
float mSkinWidth;
unsigned int mHullCount;
FILE *mFph;
unsigned int mBaseCount;
char mObjName[512];
char mBaseName[512];
ConvexResultVector mHulls;
};
int main(int argc,const char **argv)
{
if ( argc < 2 )
{
printf("Usage: Test <meshanme.obj> (options)\r\n");
printf("\r\n");
printf("Options:\r\n");
printf("\r\n");
printf(" -d<depth> : How deep to recursively split. Values of 3-7 are reasonable.\r\n");
printf(" -c<percent> : Percentage of concavity to keep splitting. 0-20% is reasonable.\r\n");
printf(" -p<percent> : Percentage of volume delta to collapse hulls. 0-30% is reasonable.\r\n");
printf(" -v<maxverts> : Maximum number of vertices in the output hull. Default is 32.\r\n");
printf(" -s<skinwidth> : Skin Width inflation. Default is 0.\r\n");
}
else
{
unsigned int depth = 5;
float cpercent = 5;
float ppercent = 5;
unsigned int maxv = 32;
float skinWidth = 0;
// process command line switches.
for (int i=2; i<argc; i++)
{
const char *o = argv[i];
if ( strncmp(o,"-d",2) == 0 )
{
depth = (unsigned int) atoi( &o[2] );
if ( depth < 0 || depth > 10 )
{
depth = 5;
printf("Invalid depth value in switch, defaulting to 5.\r\n");
}
}
if ( strncmp(o,"-c",2) == 0 )
{
cpercent = (float) atof( &o[2] );
if ( cpercent < 0 || cpercent > 100 )
{
cpercent = 5;
printf("Invalid concavity percentage in switch, defaulting to 5.\r\n");
}
}
if ( strncmp(o,"-p",2) == 0 )
{
ppercent = (float) atof( &o[2] );
if ( ppercent < 0 || ppercent > 100 )
{
ppercent = 5;
printf("Invalid hull merge percentage in switch, defaulting to 5.\r\n");
}
}
if ( strncmp(o,"-v",2) == 0 )
{
maxv = (unsigned int) atoi( &o[2] );
if ( maxv < 8 || maxv > 256 )
{
maxv = 32;
printf("Invalid max vertices in switch, defaulting to 32.\r\n");
}
}
if ( strncmp(o,"-s",2) == 0 )
{
skinWidth = (float) atof( &o[2] );
if ( skinWidth < 0 || skinWidth > 0.1f )
{
skinWidth = 0;
printf("Invalid skinWidth in switch, defaulting to 0.\r\n");
}
}
}
WavefrontObj wo;
unsigned int tcount = wo.loadObj(argv[1]);
if ( tcount )
{
DecompDesc d;
d.mVcount = wo.mVertexCount;
d.mVertices = wo.mVertices;
d.mTcount = wo.mTriCount;
d.mIndices = (unsigned int *)wo.mIndices;
d.mDepth = depth;
d.mCpercent = cpercent;
d.mPpercent = ppercent;
d.mMaxVertices = maxv;
d.mSkinWidth = skinWidth;
CBuilder cb(argv[1],d); // receives the answers and writes out a wavefront OBJ file.
d.mCallback = &cb;
unsigned int count = performConvexDecomposition(d);
if ( count )
{
printf("Input triangle mesh with %d triangles produced %d output hulls.\r\n", d.mTcount, count );
cb.saveNxuStream(); // save results in NxuStream format.
cb.saveCOLLADA(); // save results in COLLADA physics 1.4.1 format.
}
else
{
printf("Failed to produce any convex hulls.\r\n");
}
}
else
{
// sorry..no
printf("Sorry unable to load file '%s'\r\n", argv[1] );
}
}
}

View File

@ -1,21 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecomposeSample", "DecomposeSample.vcproj", "{0282D4E2-DA97-437D-9BDE-1C9F5E56F6F8}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{0282D4E2-DA97-437D-9BDE-1C9F5E56F6F8}.Debug.ActiveCfg = Debug|Win32
{0282D4E2-DA97-437D-9BDE-1C9F5E56F6F8}.Debug.Build.0 = Debug|Win32
{0282D4E2-DA97-437D-9BDE-1C9F5E56F6F8}.Release.ActiveCfg = Release|Win32
{0282D4E2-DA97-437D-9BDE-1C9F5E56F6F8}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -1,240 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="DecomposeSample"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="TRUE"
PrecompiledHeaderFile=".\Release/DecomposeSample.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile=".\Release/DecomposeSample.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
ProgramDatabaseFile=".\Release/DecomposeSample.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Release/DecomposeSample.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
PrecompiledHeaderFile=".\Debug/DecomposeSample.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile=".\Debug/DecomposeSample.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/DecomposeSample.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Debug/DecomposeSample.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\DecomposeSample.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
<Filter
Name="ConvexDecomposition"
Filter="">
<File
RelativePath=".\ConvexDecomposition\bestfit.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\bestfit.h">
</File>
<File
RelativePath=".\ConvexDecomposition\bestfitobb.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\bestfitobb.h">
</File>
<File
RelativePath=".\ConvexDecomposition\cd_hull.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\cd_hull.h">
</File>
<File
RelativePath=".\ConvexDecomposition\cd_vector.h">
</File>
<File
RelativePath=".\ConvexDecomposition\cd_wavefront.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\cd_wavefront.h">
</File>
<File
RelativePath=".\ConvexDecomposition\concavity.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\concavity.h">
</File>
<File
RelativePath=".\ConvexDecomposition\ConvexDecomposition.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\ConvexDecomposition.h">
</File>
<File
RelativePath=".\ConvexDecomposition\fitsphere.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\fitsphere.h">
</File>
<File
RelativePath=".\ConvexDecomposition\float_math.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\float_math.h">
</File>
<File
RelativePath=".\ConvexDecomposition\meshvolume.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\meshvolume.h">
</File>
<File
RelativePath=".\ConvexDecomposition\planetri.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\planetri.h">
</File>
<File
RelativePath=".\ConvexDecomposition\raytri.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\raytri.h">
</File>
<File
RelativePath=".\ConvexDecomposition\splitplane.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\splitplane.h">
</File>
<File
RelativePath=".\ConvexDecomposition\triangulate.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\triangulate.h">
</File>
<File
RelativePath=".\ConvexDecomposition\vlookup.cpp">
</File>
<File
RelativePath=".\ConvexDecomposition\vlookup.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -1,93 +0,0 @@
OBJS = DecomposeSample.o \
ConvexDecomposition/bestfit.o ConvexDecomposition/float_math.o \
ConvexDecomposition/bestfitobb.o ConvexDecomposition/meshvolume.o \
ConvexDecomposition/cd_hull.o ConvexDecomposition/planetri.o \
ConvexDecomposition/cd_wavefront.o ConvexDecomposition/raytri.o \
ConvexDecomposition/concavity.o ConvexDecomposition/splitplane.o \
ConvexDecomposition/ConvexDecomposition.o ConvexDecomposition/triangulate.o \
ConvexDecomposition/fitsphere.o ConvexDecomposition/vlookup.o
HEADERS = \
ConvexDecomposition/bestfit.h \
ConvexDecomposition/bestfitobb.h \
ConvexDecomposition/cd_hull.h \
ConvexDecomposition/cd_vector.h \
ConvexDecomposition/cd_wavefront.h \
ConvexDecomposition/concavity.h \
ConvexDecomposition/ConvexDecomposition.h \
ConvexDecomposition/fitsphere.h \
ConvexDecomposition/float_math.h \
ConvexDecomposition/meshvolume.h \
ConvexDecomposition/planetri.h \
ConvexDecomposition/raytri.h \
ConvexDecomposition/splitplane.h \
ConvexDecomposition/triangulate.h \
ConvexDecomposition/vlookup.h
CC = g++
DEBUG = -ggdb
CFLAGS = -IConvexDecomposition -Wall -c $(DEBUG)
LFLAGS = $(DEBUG)
convex_decomposition: $(OBJS)
$(CC) $(LFLAGS) $(OBJS) -o convex_decomposition
DecomposeSample.o: DecomposeSample.cpp
$(CC) $(CFLAGS) DecomposeSample.cpp -o $@
ConvexDecomposition/bestfit.o: ConvexDecomposition/bestfit.cpp
$(CC) $(CFLAGS) ConvexDecomposition/bestfit.cpp -o $@
ConvexDecomposition/bestfitobb.o: ConvexDecomposition/bestfitobb.cpp
$(CC) $(CFLAGS) ConvexDecomposition/bestfitobb.cpp -o $@
ConvexDecomposition/cd_hull.o: ConvexDecomposition/cd_hull.cpp
$(CC) $(CFLAGS) ConvexDecomposition/cd_hull.cpp -o $@
ConvexDecomposition/cd_wavefront.o: ConvexDecomposition/cd_wavefront.cpp
$(CC) $(CFLAGS) ConvexDecomposition/cd_wavefront.cpp -o $@
ConvexDecomposition/concavity.o: ConvexDecomposition/concavity.cpp
$(CC) $(CFLAGS) ConvexDecomposition/concavity.cpp -o $@
ConvexDecomposition/ConvexDecomposition.o: ConvexDecomposition/ConvexDecomposition.cpp
$(CC) $(CFLAGS) ConvexDecomposition/ConvexDecomposition.cpp -o $@
ConvexDecomposition/fitsphere.o: ConvexDecomposition/fitsphere.cpp
$(CC) $(CFLAGS) ConvexDecomposition/fitsphere.cpp -o $@
ConvexDecomposition/float_math.o: ConvexDecomposition/float_math.cpp
$(CC) $(CFLAGS) ConvexDecomposition/float_math.cpp -o $@
ConvexDecomposition/meshvolume.o: ConvexDecomposition/meshvolume.cpp
$(CC) $(CFLAGS) ConvexDecomposition/meshvolume.cpp -o $@
ConvexDecomposition/planetri.o: ConvexDecomposition/planetri.cpp
$(CC) $(CFLAGS) ConvexDecomposition/planetri.cpp -o $@
ConvexDecomposition/raytri.o: ConvexDecomposition/raytri.cpp
$(CC) $(CFLAGS) ConvexDecomposition/raytri.cpp -o $@
ConvexDecomposition/splitplane.o: ConvexDecomposition/splitplane.cpp
$(CC) $(CFLAGS) ConvexDecomposition/splitplane.cpp -o $@
ConvexDecomposition/triangulate.o: ConvexDecomposition/triangulate.cpp
$(CC) $(CFLAGS) ConvexDecomposition/triangulate.cpp -o $@
ConvexDecomposition/vlookup.o: ConvexDecomposition/vlookup.cpp ConvexDecomposition/vlookup.cpp
$(CC) $(CFLAGS) ConvexDecomposition/vlookup.cpp -o $@
install:
cp convex_decomposition ../../convex_decomposition/bin/
clean:
\rm *.o */*.o convex_decomposition
tar:
tar cfv ConvexDecomposition.tar DecomposeSample.cpp convex_decomposition Makefile \
ConvexDecomposition

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
ConvexDecomposition library written by John W. Ratcliff
Usage: Test <meshanme.obj> (options)
Options:
-d<depth> : How deep to recursively split. Values of 3-7 are reasonable.
-c<percent> : Percentage of concavity to keep splitting. 0-20 4324640s reasonable.
-p<percent> : Percentage of volume delta to collapse hulls. 0-30 4324544s reasonable.
-v<maxverts> : Maximum number of vertices in the output hull. Default is 32.
-s<skinwidth> : Skin Width inflation. Default is 0.0
To run the sample provided with defaults:
DecomposeSample chair.obj
Will produce 'chair_convex.obj' a Wavefront OBJ file useful for debug visualization.
'chair.dae' a COLLADA physics representation of the model.
'chair.xml' an Ageia PhysX NxuStream representation of the model.
/*!
**
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
** Personal website: http://jratcliffscarab.blogspot.com
** Coding Website: http://codesuppository.blogspot.com
** FundRaising Blog: http://amillionpixels.blogspot.com
** Fundraising site: http://www.amillionpixels.us
** New Temple Site: http://newtemple.blogspot.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.
*/

View File

@ -1,33 +0,0 @@
all: installed
TARBALL = build/ConvexDecomposition.zip
TARBALL_URL = http://pr.willowgarage.com/downloads/ConvexDecomposition.zip
SOURCE_DIR = build/convex_decomposition
INITIAL_DIR = build/ConvexDecomposition
UNPACK_CMD = unzip
TARBALL_PATCH=convex_decomposition.patch
include $(shell rospack find mk)/download_unpack_build.mk
ROOT = $(shell rospack find convex_decomposition)/convex_decomposition
installed: wiped $(SOURCE_DIR)/unpacked
@echo "making it"
@echo "ROOT is: $(ROOT)"
-mkdir -p $(ROOT)
-mkdir -p $(ROOT)/bin
cd $(SOURCE_DIR) ; make $(ROS_PARALLEL_JOBS); make install
touch installed
wiped: Makefile
make wipe
touch wiped
clean:
-cd $(SOURCE_DIR) && make clean
rm -rf $(ROOT) installed
wipe: clean
rm -rf build
.PHONY : clean download wipe

View File

@ -1,429 +0,0 @@
Index: ConvexDecomposition/vlookup.cpp
===================================================================
--- ConvexDecomposition/vlookup.cpp (revision 8299)
+++ ConvexDecomposition/vlookup.cpp (working copy)
@@ -164,7 +164,7 @@
};
-template <class Type> class VertexLess
+template <typename Type> class VertexLess
{
public:
typedef std::vector< Type > VertexVector;
@@ -188,7 +188,7 @@
static VertexVector *mList;
};
-template <class Type> class VertexPool
+template <typename Type> class VertexPool
{
public:
typedef std::set<int, VertexLess<Type> > VertexSet;
@@ -197,7 +197,7 @@
int GetVertex(const Type& vtx)
{
VertexLess<Type>::SetSearch(vtx,&mVtxs);
- VertexSet::iterator found;
+ typename VertexSet::iterator found;
found = mVertSet.find( -1 );
if ( found != mVertSet.end() )
{
@@ -254,10 +254,10 @@
VertexVector mVtxs; // set of vertices.
};
+double tmpp[3] = {0,0,0};
+template<> VertexPosition VertexLess<VertexPosition>::mFind = tmpp;
+template<> std::vector<VertexPosition > *VertexLess<VertexPosition>::mList =0;
-VertexPosition VertexLess<VertexPosition>::mFind;
-std::vector<VertexPosition > *VertexLess<VertexPosition>::mList=0;
-
enum RDIFF
{
RD_EQUAL,
@@ -288,6 +288,7 @@
}
+template<>
bool VertexLess<VertexPosition>::operator()(int v1,int v2) const
{
bool ret = false;
Index: ConvexDecomposition/ConvexDecomposition.cpp
===================================================================
--- ConvexDecomposition/ConvexDecomposition.cpp (revision 8299)
+++ ConvexDecomposition/ConvexDecomposition.cpp (working copy)
@@ -66,7 +66,7 @@
#include "cd_vector.h"
#include "cd_hull.h"
#include "bestfit.h"
-#include "PlaneTri.h"
+#include "planetri.h"
#include "vlookup.h"
#include "splitplane.h"
#include "meshvolume.h"
@@ -760,3 +760,3 @@
- assert( fcount >= 3 && fcount <= 4);
- assert( bcount >= 3 && bcount <= 4);
-
+ if ( fcount >= 3 && fcount <= 4)
+ if ( bcount >= 3 && bcount <= 4)
+ {
@@ -777,1 +777,1 @@
-
+ }
Index: ConvexDecomposition/splitplane.cpp
===================================================================
--- ConvexDecomposition/splitplane.cpp (revision 8299)
+++ ConvexDecomposition/splitplane.cpp (working copy)
@@ -67,7 +67,7 @@
#include "cd_hull.h"
#include "cd_wavefront.h"
#include "bestfit.h"
-#include "PlaneTri.h"
+#include "planetri.h"
#include "vlookup.h"
#include "meshvolume.h"
#include "bestfitobb.h"
Index: ConvexDecomposition/cd_vector.h
===================================================================
--- ConvexDecomposition/cd_vector.h (revision 8299)
+++ ConvexDecomposition/cd_vector.h (working copy)
@@ -309,12 +309,12 @@
Type FastMagnitude(void) const
{
- return Type(fast_sqrt(x * x + y * y + z * z));
+ return Type(sqrt(x * x + y * y + z * z));
};
Type FasterMagnitude(void) const
{
- return Type(faster_sqrt(x * x + y * y + z * z));
+ return Type(sqrt(x * x + y * y + z * z));
};
void Lerp(const Vector3d<Type>& from,const Vector3d<Type>& to,double slerp)
@@ -436,13 +436,13 @@
Type FastLength(void) const // length of vector.
{
- return Type(fast_sqrt( x*x + y*y + z*z ));
+ return Type(sqrt( x*x + y*y + z*z ));
};
Type FasterLength(void) const // length of vector.
{
- return Type(faster_sqrt( x*x + y*y + z*z ));
+ return Type(sqrt( x*x + y*y + z*z ));
};
Type Length2(void) const // squared distance, prior to square root.
@@ -518,7 +518,7 @@
inline double FastNormalize(void) // normalize to a unit vector, returns distance.
{
- double d = fast_sqrt( static_cast< double >( x*x + y*y + z*z ) );
+ double d = sqrt( static_cast< double >( x*x + y*y + z*z ) );
if ( d > 0 )
{
double r = 1.0f / d;
@@ -535,7 +535,7 @@
inline double FasterNormalize(void) // normalize to a unit vector, returns distance.
{
- double d = faster_sqrt( static_cast< double >( x*x + y*y + z*z ) );
+ double d = sqrt( static_cast< double >( x*x + y*y + z*z ) );
if ( d > 0 )
{
double r = 1.0f / d;
@@ -1029,7 +1029,8 @@
void Zero(void)
{
- x = y = z = 0;
+ x = 0;
+ y = 0;
};
Vector2d negative(void) const
@@ -1047,12 +1048,12 @@
Type fastmagnitude(void) const
{
- return (Type) fast_sqrt(x * x + y * y );
+ return (Type) sqrt(x * x + y * y );
}
Type fastermagnitude(void) const
{
- return (Type) faster_sqrt( x * x + y * y );
+ return (Type) sqrt( x * x + y * y );
}
void Reflection(Vector2d &a,Vector2d &b); // compute reflection vector.
@@ -1064,12 +1065,12 @@
Type FastLength(void) const // length of vector.
{
- return Type(fast_sqrt( x*x + y*y ));
+ return Type(sqrt( x*x + y*y ));
};
Type FasterLength(void) const // length of vector.
{
- return Type(faster_sqrt( x*x + y*y ));
+ return Type(sqrt( x*x + y*y ));
};
Type Length2(void) // squared distance, prior to square root.
@@ -1090,7 +1091,7 @@
Type dx = a.x - x;
Type dy = a.y - y;
Type d = dx*dx+dy*dy;
- return fast_sqrt(d);
+ return sqrt(d);
};
Type FasterDistance(const Vector2d &a) const // distance between two points.
@@ -1098,7 +1099,7 @@
Type dx = a.x - x;
Type dy = a.y - y;
Type d = dx*dx+dy*dy;
- return faster_sqrt(d);
+ return sqrt(d);
};
Type Distance2(Vector2d &a) // squared distance.
Index: ConvexDecomposition/float_math.cpp
===================================================================
--- ConvexDecomposition/float_math.cpp (revision 8299)
+++ ConvexDecomposition/float_math.cpp (working copy)
@@ -212,8 +212,14 @@
matrix[1*4+2] = 2 * ( yz + wx );
matrix[2*4+2] = 1 - 2 * ( xx + yy );
- matrix[3*4+0] =(double) matrix[3*4+1] = matrix[3*4+2] = 0.0f;
- matrix[0*4+3] =(double) matrix[1*4+3] = matrix[2*4+3] = 0.0f;
+ matrix[3*4+0] = 0.0f;
+ matrix[3*4+1] = 0.0f;
+ matrix[3*4+2] = 0.0f;
+
+ matrix[0*4+3] = 0.0f;
+ matrix[1*4+3] = 0.0f;
+ matrix[2*4+3] = 0.0f;
+
matrix[3*4+3] =(double) 1.0f;
}
Index: ConvexDecomposition/cd_wavefront.cpp
===================================================================
--- ConvexDecomposition/cd_wavefront.cpp (revision 8299)
+++ ConvexDecomposition/cd_wavefront.cpp (working copy)
@@ -672,7 +672,7 @@
const char *foo = argv[0];
if ( *foo != '#' )
{
- if ( stricmp(argv[0],"v") == 0 && argc == 4 )
+ if ( strcmp(argv[0],"v") == 0 && argc == 4 )
{
double vx = (double) atof( argv[1] );
double vy = (double) atof( argv[2] );
@@ -681,14 +681,14 @@
mVerts.push_back(vy);
mVerts.push_back(vz);
}
- else if ( stricmp(argv[0],"vt") == 0 && argc == 3 )
+ else if ( strcmp(argv[0],"vt") == 0 && argc == 3 )
{
double tx = (double) atof( argv[1] );
double ty = (double) atof( argv[2] );
mTexels.push_back(tx);
mTexels.push_back(ty);
}
- else if ( stricmp(argv[0],"vn") == 0 && argc == 4 )
+ else if ( strcmp(argv[0],"vn") == 0 && argc == 4 )
{
double normalx = (double) atof(argv[1]);
double normaly = (double) atof(argv[2]);
@@ -697,7 +697,7 @@
mNormals.push_back(normaly);
mNormals.push_back(normalz);
}
- else if ( stricmp(argv[0],"f") == 0 && argc >= 4 )
+ else if ( strcmp(argv[0],"f") == 0 && argc >= 4 )
{
GeometryVertex v[32];
Index: Makefile
===================================================================
--- Makefile (revision 0)
+++ Makefile (revision 8581)
@@ -0,0 +1,93 @@
+
+
+OBJS = DecomposeSample.o \
+ ConvexDecomposition/bestfit.o ConvexDecomposition/float_math.o \
+ ConvexDecomposition/bestfitobb.o ConvexDecomposition/meshvolume.o \
+ ConvexDecomposition/cd_hull.o ConvexDecomposition/planetri.o \
+ ConvexDecomposition/cd_wavefront.o ConvexDecomposition/raytri.o \
+ ConvexDecomposition/concavity.o ConvexDecomposition/splitplane.o \
+ ConvexDecomposition/ConvexDecomposition.o ConvexDecomposition/triangulate.o \
+ ConvexDecomposition/fitsphere.o ConvexDecomposition/vlookup.o
+
+HEADERS = \
+ ConvexDecomposition/bestfit.h \
+ ConvexDecomposition/bestfitobb.h \
+ ConvexDecomposition/cd_hull.h \
+ ConvexDecomposition/cd_vector.h \
+ ConvexDecomposition/cd_wavefront.h \
+ ConvexDecomposition/concavity.h \
+ ConvexDecomposition/ConvexDecomposition.h \
+ ConvexDecomposition/fitsphere.h \
+ ConvexDecomposition/float_math.h \
+ ConvexDecomposition/meshvolume.h \
+ ConvexDecomposition/planetri.h \
+ ConvexDecomposition/raytri.h \
+ ConvexDecomposition/splitplane.h \
+ ConvexDecomposition/triangulate.h \
+ ConvexDecomposition/vlookup.h
+
+CC = g++
+
+DEBUG = -ggdb
+
+CFLAGS = -IConvexDecomposition -Wall -c $(DEBUG)
+
+LFLAGS = $(DEBUG)
+
+convex_decomposition: $(OBJS)
+ $(CC) $(LFLAGS) $(OBJS) -o convex_decomposition
+
+DecomposeSample.o: DecomposeSample.cpp
+ $(CC) $(CFLAGS) DecomposeSample.cpp -o $@
+
+ConvexDecomposition/bestfit.o: ConvexDecomposition/bestfit.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/bestfit.cpp -o $@
+
+ConvexDecomposition/bestfitobb.o: ConvexDecomposition/bestfitobb.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/bestfitobb.cpp -o $@
+
+ConvexDecomposition/cd_hull.o: ConvexDecomposition/cd_hull.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/cd_hull.cpp -o $@
+
+ConvexDecomposition/cd_wavefront.o: ConvexDecomposition/cd_wavefront.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/cd_wavefront.cpp -o $@
+
+ConvexDecomposition/concavity.o: ConvexDecomposition/concavity.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/concavity.cpp -o $@
+
+ConvexDecomposition/ConvexDecomposition.o: ConvexDecomposition/ConvexDecomposition.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/ConvexDecomposition.cpp -o $@
+
+ConvexDecomposition/fitsphere.o: ConvexDecomposition/fitsphere.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/fitsphere.cpp -o $@
+
+ConvexDecomposition/float_math.o: ConvexDecomposition/float_math.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/float_math.cpp -o $@
+
+ConvexDecomposition/meshvolume.o: ConvexDecomposition/meshvolume.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/meshvolume.cpp -o $@
+
+ConvexDecomposition/planetri.o: ConvexDecomposition/planetri.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/planetri.cpp -o $@
+
+ConvexDecomposition/raytri.o: ConvexDecomposition/raytri.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/raytri.cpp -o $@
+
+ConvexDecomposition/splitplane.o: ConvexDecomposition/splitplane.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/splitplane.cpp -o $@
+
+ConvexDecomposition/triangulate.o: ConvexDecomposition/triangulate.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/triangulate.cpp -o $@
+
+ConvexDecomposition/vlookup.o: ConvexDecomposition/vlookup.cpp ConvexDecomposition/vlookup.cpp
+ $(CC) $(CFLAGS) ConvexDecomposition/vlookup.cpp -o $@
+
+install:
+ cp convex_decomposition ../../convex_decomposition/bin/
+
+clean:
+ \rm *.o */*.o convex_decomposition
+
+tar:
+ tar cfv ConvexDecomposition.tar DecomposeSample.cpp convex_decomposition Makefile \
+ ConvexDecomposition
Index: DecomposeSample.cpp
===================================================================
--- DecomposeSample.cpp (revision 8299)
+++ DecomposeSample.cpp (working copy)
@@ -6,7 +6,7 @@
#include <vector>
-#include "./ConvexDecomposition/convexdecomposition.h"
+#include "./ConvexDecomposition/ConvexDecomposition.h"
#include "./ConvexDecomposition/cd_wavefront.h"
using namespace ConvexDecomposition;
@@ -227,7 +227,7 @@
if ( fph )
{
- printf("Saving convex decomposition of %d hulls to COLLADA file '%s'\r\n", mHulls.size(), scratch );
+ printf("Saving convex decomposition of %d hulls to COLLADA file '%s'\r\n", (int)mHulls.size(), scratch );
fprintf(fph,"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
fprintf(fph,"<COLLADA version=\"1.4.0\" xmlns=\"http://www.collada.org/2005/11/COLLADASchema\">\r\n");
@@ -537,7 +537,7 @@
};
-void main(int argc,const char **argv)
+int main(int argc,const char **argv)
{
if ( argc < 2 )
{
Index: DecomposeSample.cpp
===================================================================
--- DecomposeSample.cpp (revision 8299)
+++ DecomposeSample.cpp (working copy)
@@ -67,3 +67,3 @@
strcpy(mBaseName,fname);
- char *dot = strstr(mBaseName,".");
+ char *dot = strstr(mBaseName,".obj");
if ( dot ) *dot = 0;
Index: ConvexDecomposition/cd_wavefront.cpp
===================================================================
--- ConvexDecomposition/cd_wavefront.cpp (revision 8299)
+++ ConvexDecomposition/cd_wavefront.cpp (working copy)
@@ -573,6 +573,7 @@
FloatVector mNormals;
GeometryInterface *mCallback;
+ friend class WavefrontObj;
};
@@ -839,7 +840,17 @@
memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);
ret = mTriCount;
}
-
+ else if( obj.mVerts.size() > 0 ) {
+ // take consecutive vertices
+ mVertexCount = obj.mVerts.size()/3;
+ mVertices = new double[mVertexCount*3];
+ memcpy( mVertices, &obj.mVerts[0], sizeof(double)*mVertexCount*3 );
+ mTriCount = mVertexCount/3;
+ mIndices = new int[mTriCount*3*sizeof(int)];
+ for(int i = 0; i < mVertexCount; ++i)
+ mIndices[i] = i;
+ ret = mTriCount;
+ }
return ret;
}

View File

@ -1,29 +0,0 @@
<package>
<description brief="Convex Mesh Generation Library">
<p>
<tt>convex_decomposition</tt> contains the Convex Mesh Generation Library, by John Ratcliff. This library is used to auto-generate convex decomposed meshes for
collision and visualization of robot links.
</p>
<p>
We are using the latest and the only version available. We plan on deprecating this package
once we find a better alternative.
</p>
<p>
The Convex Mesh Generation Library is not provided by
any of the major OS package managers, and this version provided
here contains patches required for compilation.
These patches have not been submitted back as there
appears to be no available revision control.
</p>
</description>
<author>John Ratcliff</author>
<license>MIT</license>
<review status="3rdparty doc reviewed" notes=""/>
<url>http://www.amillionpixels.us/ConvexDecomposition.zip</url>
<rosdep name="unzip"/>
<platform os="ubuntu" version="9.04"/>
<platform os="ubuntu" version="9.10"/>
<platform os="ubuntu" version="10.04"/>
</package>

View File

@ -1,10 +0,0 @@
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
#uncomment for profiling
set(ROS_LINK_FLAGS "-lm" ${ROS_LINK_FLAGS})
rosbuild_add_executable(bin/ivcon src/ivcon.c)
target_link_libraries(bin/ivcon m)

View File

@ -1 +0,0 @@
include $(shell rospack find mk)/cmake.mk

View File

@ -1,23 +0,0 @@
<package>
<description brief="Mesh Conversion Utility">
Mesh Conversion Utility
Used to generate '.iv' files from '.stl' files. This package has not
been changed since 2001 and appears to be very stable. We plan on
keeping this package in this revision for mesh conversions. This
package is only available as a single source file for download. There
are no local modifications to this package.
</description>
<author>John Burkardt</author>
<license>GPL</license>
<review status="3rdparty doc reviewed" notes=""/>
<url>https://sourceforge.net/projects/ivcon/</url>
<export>
<cpp lflags="" cflags=""/>
</export>
<platform os="ubuntu" version="9.04"/>
<platform os="ubuntu" version="9.10"/>
<platform os="ubuntu" version="10.04"/>
</package>

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
# Set the build type. Options are:
# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage
# Debug : w/ debug symbols, w/o optimization
# Release : w/o debug symbols, w/ optimization
# RelWithDebInfo : w/ debug symbols, w/ optimization
# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries
#set(ROS_BUILD_TYPE RelWithDebInfo)
rosbuild_init()
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#uncomment if you have defined messages
#rosbuild_genmsg()
#uncomment if you have defined services
#rosbuild_gensrv()
#common commands for building c++ executables and libraries
#rosbuild_add_library(${PROJECT_NAME} src/example.cpp)
#target_link_libraries(${PROJECT_NAME} another_library)
#rosbuild_add_boost_directories()
#rosbuild_link_boost(${PROJECT_NAME} thread)
#rosbuild_add_executable(example examples/example.cpp)
#target_link_libraries(example ${PROJECT_NAME})

View File

@ -1 +0,0 @@
include $(shell rospack find mk)/cmake.mk

View File

@ -1,667 +0,0 @@
#!/usr/bin/python
import roslib; roslib.load_manifest('simmechanics_to_urdf')
import rospy
import sys
import tf
from tf.transformations import euler_from_quaternion, quaternion_from_matrix
from geometry_msgs.msg import TransformStamped
import xml.dom.minidom
from xml.dom.minidom import Document
import math
import numpy #for creating matrix to convert to quaternion
import yaml
from urdf_python.urdf import *
# Conversion Factors
INCH2METER = 0.0254
SLUG2KG = 14.5939029
SLUGININ2KGMM = .009415402
MM2M = .001
# Special Reference Frame(s)
WORLD = "WORLD"
# Arbitrary List of colors to give pieces different looks
COLORS =[("green", (0, 1, 0, 1)), ("black", (0, 0, 0, 1)), ("red", (1, 0, 0, 1)),
("blue", (0, 0, 1, 1)), ("yellow", (1, 1, 0, 1)), ("pink", (1, 0, 1, 1)),
("cyan", (0, 1, 1, 1)), ("green", (0, 1, 0, 1)), ("white", (1, 1, 1, 1)),
("dblue", (0, 0, .8, 1)), ("dgreen", (.1, .8, .1, 1)), ("gray", (.5, .5, .5, 1))]
class Converter:
def __init__(self):
# initialize member variables
self.links = {}
self.frames = {}
self.joints = {}
self.names = {}
self.colormap = {}
self.colorindex = 0
self.usedcolors = {}
# Start the Transform Manager
self.tfman = TransformManager()
# Extra Transforms for Debugging
self.tfman.add([0,0,0], [0.70682518,0,0,0.70682518], "ROOT", WORLD) # rotate so Z axis is up
def convert(self, filename, configfile, mode):
self.mode = mode
# Parse the configuration file
self.parseConfig(configfile)
# Parse the input file
self.parse(xml.dom.minidom.parse(filename))
self.buildTree(self.root)
# Create the output
self.output(self.root)
# output the output
if mode == "xml":
print self.result.to_xml()
if mode == "graph":
print self.graph()
if mode == "groups":
print self.groups(root)
def parseConfig(self, configFile):
"""Parse the Configuration File, if it exists.
Set the fields the default if the config does
not set them """
if configFile == None:
configuration = {}
else:
configuration = yaml.load(file(configFile, 'r'))
if configuration == None:
configuration = {}
self.freezeList = []
self.redefinedjoints = {}
self.root = configuration.get('root', None)
self.extrajoints = configuration.get('extrajoints', {})
self.filenameformat = configuration.get('filenameformat', "%s")
self.forcelowercase = configuration.get('forcelowercase', False)
self.scale = configuration.get('scale', None)
self.freezeAll = configuration.get('freezeAll', False)
self.baseframe = configuration.get('baseframe', WORLD)
# Get lists converted to strings
self.removeList = [ str(e) for e in configuration.get('remove', []) ]
self.freezeList = [ str(e) for e in configuration.get('freeze', []) ]
# Get map with key converted to strings
jointmap = configuration.get('redefinedjoints', {})
for x in jointmap.keys():
self.redefinedjoints[str(x)] = jointmap[x]
# Add Extra Frames
for frame in configuration.get('moreframes', []):
self.tfman.add(frame['offset'], frame['orientation'], frame['parent'], frame['child'])
def parse(self, element):
"""Recursively goes through all XML elements
and branches off for important elements"""
name = element.localName
# Grab name from root element AND recursively parse
if name == "PhysicalModelingXMLFile":
dict = getDictionary(element)
self.name = dict['name']
if name == "Body":
self.parseLink(element)
elif name == "SimpleJoint":
self.parseJoint(element)
elif name == "Ground":
dict = getDictionary(element)
self.parseFrames(dict['frame'], "GROUND")
else:
for child in element.childNodes:
self.parse(child)
def parseLink(self, link):
"""Parse the important bits of a link element"""
linkdict = getDictionary(link)
uid = self.getName(linkdict['name'])
linkdict['neighbors'] = []
linkdict['children'] = []
linkdict['jointmap'] = {}
# Save the frames for separate parsing
frames = linkdict['frames']
linkdict['frames'] = None
# Save the color if it exists
if 'MaterialProp' in linkdict:
colorelement = linkdict['MaterialProp'][1]
color = colorelement.childNodes[0].data
linkdict['MaterialProp'] = None
linkdict['color'] = map(float, color.split(",")) + [1.0]
self.links[uid] = linkdict
self.parseFrames(frames, uid)
# Save First Actual Element as Root, if not defined already
if self.root == None and "geometryFileName" in linkdict:
self.root = uid
def parseFrames(self, frames, parent):
"""Parse the frames from xml"""
for frame in frames:
if frame.nodeType is frame.TEXT_NODE:
continue
fdict = getDictionary(frame)
fid = str(frame.getAttribute("ref"))
fdict['parent'] = parent
offset = getlist(fdict['position'])
units = fdict['positionUnits']
for i in range(0, len(offset)):
offset[i] = convert(offset[i], units)
orientation = getlist(fdict['orientation'])
quat = matrixToQuaternion(orientation)
# If the frame does not have a reference number,
# use the name plus a suffix (for CG or CS1...
# otherwise ignore the frame
if fid == "":
name = fdict['name']
if name == "CG":
fid = parent + "CG"
elif name == "CS1":
fid = parent + "CS1"
else:
continue
self.tfman.add(offset, quat, WORLD, fid)
self.frames[fid] = fdict
def parseJoint(self, element):
"""Parse the joint from xml"""
dict = getDictionary(element)
joint = {}
joint['name'] = dict['name']
uid = self.getName(joint['name'])
frames = element.getElementsByTagName("Frame")
joint['parent'] = str(frames[0].getAttribute("ref"))
joint['child'] = str(frames[1].getAttribute("ref"))
type = element.getElementsByTagName("Primitive")
# If there multiple elements, assume a fixed joint
if len(type)==1:
pdict = getDictionary(type[0])
joint['type'] = pdict['name']
joint['axis'] = pdict['axis']
if joint['type'] == 'weld':
joint['type'] = 'fixed'
else:
joint['type'] = 'fixed'
# Ignore joints on the remove list
if joint['parent'] in self.removeList:
return
# Force joints to be fixed on the freezeList
if joint['parent'] in self.freezeList or self.freezeAll:
joint['type'] = 'fixed'
# Redefine specified joints on redefined list
if joint['parent'] in self.redefinedjoints.keys():
jdict = self.redefinedjoints[joint['parent']]
if 'name' in jdict:
uid = jdict['name']
# Default to continuous joints
joint['type'] = jdict.get('type', 'continuous')
if 'axis' in jdict:
joint['axis'] = jdict['axis']
if 'limits' in jdict:
joint['limits'] = jdict['limits']
self.joints[uid] = joint
def buildTree(self, root):
"""Reduce the graph structure of links and joints to a tree
by breadth first search. Then construct new coordinate frames
from new tree structure"""
# Create a list of all neighboring links at each link
for jid in self.joints:
jointdict = self.joints[jid]
if "Root" in jointdict['name']:
continue
pid = self.getLinkNameByFrame(jointdict['parent'])
cid = self.getLinkNameByFrame(jointdict['child'])
parent = self.links[pid]
child = self.links[cid]
parent['neighbors'].append(cid)
parent['jointmap'][cid] = jid
child['neighbors'].append(pid)
child['jointmap'][pid] = jid
# Add necessary information for any user-defined joints
for (name, extrajoint) in self.extrajoints.items():
pid = extrajoint['pid']
cid = extrajoint['cid']
jorigin = extrajoint['jorigin']
newframe = name + "_frame"
self.links[pid]['neighbors'].append(cid)
self.links[pid]['jointmap'][cid] = name
self.links[cid]['neighbors'].append(pid)
self.links[cid]['jointmap'][pid] = name
self.joints[name] = {'name': name, 'parent': jorigin, 'child': newframe}
for (k,v) in extrajoint['attributes'].items():
self.joints[name][k] = v
self.frames[jorigin] = {'parent': pid}
self.frames[newframe] = {'parent': cid}
# Starting with designated root node, perform BFS to
# create the tree
queue = [ root ]
self.links[root]['parent'] = "GROUND"
while len(queue) > 0:
id = queue.pop(0)
link = self.links[id]
for n in link['neighbors']:
nbor = self.links[n]
# if a neighbor has not been visited yet,
# add it as a child node
if not 'parent' in nbor:
nbor['parent'] = id
queue.append(n)
link['children'].append(n)
# build new coordinate frames
for id in self.links:
link = self.links[id]
if not 'parent' in link:
continue
parentid = link['parent']
if parentid == "GROUND":
ref = self.baseframe
else:
joint = self.joints[link['jointmap'][parentid]]
ref = joint['parent']
# The root of each link is the offset to the joint
# and the rotation of the CS1 frame
(off1, rot1) = self.tfman.get(WORLD, ref)
(off2, rot2) = self.tfman.get(WORLD, id + "CS1")
self.tfman.add(off1, rot2, WORLD, "X" + id)
def output(self, rootid):
"""Creates the URDF from the parsed document.
Makes the document and starts the recursive build process"""
self.result = URDF(self.name)
self.outputLink(rootid)
self.processLink(rootid)
def processLink(self, id):
""" Creates the output for the specified node's
child links, the connecting joints, then
recursively processes each child """
link = self.links[id]
for cid in link['children']:
jid = link['jointmap'][cid]
self.outputLink(cid)
self.outputJoint(jid, id)
self.processLink(cid)
def outputLink(self, id):
""" Creates the URDF output for a single link """
linkdict = self.links[id]
if linkdict['name'] == "RootPart":
return
visual = Visual()
inertial = Inertial()
collision = Collision()
# Define Geometry
filename = linkdict['geometryFileName']
if self.forcelowercase:
filename = filename.lower()
filename = self.filenameformat % filename
visual.geometry = Mesh(filename, self.scale)
collision.geometry = visual.geometry
# Define Inertial Frame
units = linkdict['massUnits']
massval = convert(float(linkdict['mass']), units)
inertial.mass = massval
matrix = getlist(linkdict["inertia"])
units = linkdict['inertiaUnits']
for i in range(0,len(matrix)):
matrix[i] = convert(matrix[i], units)
inertial.matrix['ixx'] = matrix[0]
inertial.matrix['ixy'] = matrix[1]
inertial.matrix['ixz'] = matrix[2]
inertial.matrix['iyy'] = matrix[4]
inertial.matrix['iyz'] = matrix[5]
inertial.matrix['izz'] = matrix[8]
# Inertial origin is the center of gravity
(off, rot) = self.tfman.get("X" + id, id+"CG")
rpy = list(euler_from_quaternion(rot))
inertial.origin = Pose(zero(off), zero(rpy))
# Visual offset is difference between origin and CS1
(off, rot) = self.tfman.get("X" + id, id+"CS1")
rpy = list(euler_from_quaternion(rot))
visual.origin = Pose(zero(off), zero(rpy))
collision.origin = visual.origin
# Define Material
visual.material = Material()
# Use specified color, if exists. Otherwise, get random color
if 'color' in linkdict:
cname = "%s_color"%id
(r,g,b,a) = linkdict['color']
else:
(cname, (r,g,b,a)) = self.getColor(linkdict['name'])
visual.material.name = cname
# If color has already been output, only output name
if not cname in self.usedcolors:
visual.material.color = Color(r,g,b,a)
self.usedcolors[cname] = True
link = Link(id, visual, inertial, collision)
self.result.add_link(link)
def getColor(self, s):
""" Gets a two element list containing a color name,
and it's rgba. The color selected is based on the mesh name.
If already seen, returns the saved color
Otherwise, returns the next available color"""
if s in self.colormap:
return self.colormap[s]
color = COLORS[self.colorindex]
self.colormap[s] = color
self.colorindex = (self.colorindex + 1) % len(COLORS)
return color
def outputJoint(self, id, parentname):
""" Outputs URDF for a single joint """
jointdict = self.joints[id]
if "Root" in jointdict['name']:
return
# Define the parent and child
pid = self.getLinkNameByFrame(jointdict['parent'])
cid = self.getLinkNameByFrame(jointdict['child'])
# If the original joint was reversed while building the tree,
# swap the two ids
if parentname != pid:
cid = pid
pid = parentname
# Define joint type
jtype = jointdict['type']
limits = None
axis = None
if 'limits' in jointdict:
limits = JointLimit(None, None)
for (k,v) in jointdict['limits'].items():
setattr(limits, k, v)
if 'axis' in jointdict and jtype != 'fixed':
axis = jointdict['axis'].replace(',', ' ')
# Define the origin
(off, rot) = self.tfman.get("X" + pid, "X" + cid)
rpy = list(euler_from_quaternion(rot))
origin = Pose(zero(off), zero(rpy))
joint = Joint(id, pid, cid, jtype, limits=limits, axis=axis, origin=origin)
self.result.add_joint(joint)
def getName(self, basename):
"""Return a unique name of the format
basenameD where D is the lowest number
to make the name unique"""
index = 1
name = basename + str(index)
while name in self.names:
index = index + 1
name = basename + str(index)
self.names[name] = 1
return name
def getLinkNameByFrame(self, key):
"""Gets the link name from the frame object"""
return self.frames[key]['parent']
def graph(self):
"""For debugging purposes, output a graphviz
representation of the tree structure, noting
which joints have been reversed and which have
been removed"""
graph = "digraph proe {\n"
for jkey in self.joints:
joint = self.joints[jkey]
pref = joint['parent']
cref = joint['child']
label = pref + ":" + cref
pkey = self.getLinkNameByFrame(pref)
ckey = self.getLinkNameByFrame(cref)
case = 'std'
if pkey != "GROUND":
parent = self.links[pkey]
if not ckey in parent['children']:
child = self.links[ckey]
if pkey in child['children']:
case = 'rev'
else:
case = 'not'
pkey = pkey.replace("-", "_")
ckey = ckey.replace("-", "_")
if (case == 'std' or case == 'rev') and (joint['type'] != "fixed"):
style = " penwidth=\"5\""
else:
style = "";
if case == 'std':
s = pkey + " -> " + ckey + " [ label = \""+label+"\"";
elif case == 'not':
s = pkey + " -> " + ckey + " [ label = \""+label+"\" color=\"yellow\""
elif case == 'rev':
s = ckey + " -> " + pkey + " [ label = \""+label+"\" color=\"blue\""
s = s + style + "];"
if not "Root" in s and "-> SCR_" not in s:
graph = graph + s + "\n"
return graph + "}\n"
def groups(self, root):
""" For planning purposes, print out lists of
all the links between the different joints"""
self.groups = {}
self.makeGroup(root, "BASE")
s = ""
for key in self.groups.keys():
s = s + key + ":\n\t"
ids = self.groups[key]
for id in ids:
s = s+id + " "
s = s + "\n\n"
return s
def makeGroup(self, id, gid):
""" Helper function for recursively gathering
groups of joints. """
if gid in self.groups:
idlist = self.groups[gid]
idlist.append(id)
else:
idlist = [id]
self.groups[gid] = idlist
link = self.links[id]
for child in link['children']:
jid = link['jointmap'][child]
joint = self.joints[jid]
if joint['type'] == 'weld':
ngid = gid
else:
ngid = jid
self.makeGroup(child, ngid)
def getDictionary(tag):
"""Builds a dictionary from the specified xml tag
where each child of the tag is entered into the dictionary
with the name of the child tag as the key, and the contents
as the value. Also removes quotes from quoted values"""
x = {}
for child in tag.childNodes:
if child.nodeType is child.TEXT_NODE:
continue
key = str(child.localName)
if len(child.childNodes) == 1:
data = str(child.childNodes[0].data)
if data[0] == '"' and data[-1] == '"':
if len(data) != 2:
x[key] = data[1:-1]
else:
x[key] = data
else:
data = child.childNodes
x[key] = data
return x
def getlist(string):
"""Splits a string of comma delimited floats to
a list of floats"""
slist = string.split(",")
flist = []
for s in slist:
flist.append(float(s))
return flist
def convert(value, units):
"""Convert value from the specified units to mks units"""
if units == 'kg' or units == 'm' or units == 'kg*m^2':
return value
elif units == 'slug*in^2':
return value * SLUGININ2KGMM
elif units == 'slug':
return value * SLUG2KG
elif units == 'in':
return value * INCH2METER
elif units == 'mm':
return value * MM2M
else:
raise Exception("unsupported mass unit: %s" % units)
def matrixToQuaternion(matrix):
"""Concert 3x3 rotation matrix into a quaternion"""
(R11, R12, R13, R21, R22, R23, R31, R32, R33) = matrix
# Build 4x4 matrix
M = [[R11, R21, R31, 0],
[R12, R22, R32, 0],
[R13, R23, R33, 0],
[0, 0, 0, 1]]
A = numpy.array(M)
[w,x,y,z] = quaternion_from_matrix(A)
return [w,x,y,z]
def quaternion_to_rpy(quat):
"""Convert quaternion into roll pitch yaw list (in degrees)"""
rpy = list(euler_from_quaternion(quat))
for i in range(0, len(rpy)):
rpy[i] = rpy[i]*180/math.pi
return rpy
def zero(arr):
"""Converts any numbers less than 1e-7 to 0 in the array"""
for i in range(0,len(arr)):
if math.fabs(arr[i]) < 1e-7:
arr[i] = 0
return arr
class TransformManager:
def __init__(self):
self.tf = tf.Transformer(True, rospy.Duration(10.0))
def add(self, offset, angle, parent, child):
"""Adds a new transform to the set"""
m = TransformStamped()
m.header.frame_id = parent
m.child_frame_id = child
m.transform.translation.x = offset[0]
m.transform.translation.y = offset[1]
m.transform.translation.z = offset[2]
m.transform.rotation.x = angle[0]
m.transform.rotation.y = angle[1]
m.transform.rotation.z = angle[2]
m.transform.rotation.w = angle[3]
self.tf.setTransform(m)
def get(self, parent, child):
"""Retrieves a transform"""
(off,rpy) = self.tf.lookupTransform(parent, child, rospy.Time(0))
return [list(off), list(rpy)]
def printTransform(self, parent, child):
"""Attempts to print the specified transform"""
(off, rot) = self.get(parent, child)
rpy = quaternion_to_rpy(rot)
s = parent + "-->" + child
l = (30 - len(s))*" "
print "%s%s[%+.5f %+.5f %+.5f] \t [%+3.3f %+.3f %+.3f] \t [%+.6f %+.6f %+.6f %+.6f] " \
% (s, l, off[0], off[1], off[2], rpy[0], rpy[1], rpy[2], rot[0], rot[1], rot[2], rot[3])
def kill(self):
"""Stops thread from running"""
self.running = False
if __name__ == '__main__':
argc = len(sys.argv)
if argc == 3:
filename = sys.argv[1]
config = None
mode = sys.argv[2]
elif argc == 4:
filename = sys.argv[1]
config = sys.argv[2]
mode = sys.argv[3]
else:
print "Usage: " + sys.argv[0] + " {XML filename} [configfile] {tf|xml|graph|groups|none}"
sys.exit(-1)
try:
rospy.init_node('convert')
con = Converter()
try:
con.convert(filename, config, mode)
while mode == "tf" and not rospy.is_shutdown():
None
except Exception:
raise
except rospy.ROSInterruptException: pass

View File

@ -1,18 +0,0 @@
#!/usr/bin/python
import os
import sys
import subprocess
if __name__ == '__main__':
if len(sys.argv) != 2:
print "Usage: " + sys.argv[0] + " [directory]"
sys.exit(-1)
path= sys.argv[1]
dirList=os.listdir(path)
for fname in dirList:
path1 = path + fname
path2 = path + fname + "b"
cmd = "rosrun ivcon ivcon " + path1 + " " + path2
proc = subprocess.Popen([cmd], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print err

View File

@ -1,26 +0,0 @@
/**
\mainpage
\htmlinclude manifest.html
\b simmechanics_to_urdf is ...
<!--
Provide an overview of your package.
-->
\section codeapi Code API
<!--
Provide links to specific auto-generated API documentation within your
package that is of particular interest to a reader. Doxygen will
document pretty much every part of your code, so do your best here to
point the reader to the actual API.
If your codebase is fairly large or has different sets of APIs, you
should use the doxygen 'group' tag to keep these APIs together. For
example, the roscpp documentation has 'libros' group.
-->
*/

View File

@ -1,16 +0,0 @@
<package>
<description brief="Converts SimMechanics XML to URDF">
Converts SimMechanics XML to URDF
</description>
<author>David Lu!!</author>
<license>BSD</license>
<review status="unreviewed" notes=""/>
<url>http://ros.org/wiki/simmechanics_to_urdf</url>
<depend package="rospy"/>
<depend package="sensor_msgs"/>
<depend package="tf"/>
<depend package="urdf_python"/>
<rosdep name="python-yaml"/>
</package>