//----------------------------------------------------------------------------
void TestEllipsoidsE1ContainsE0 ()
{
	Ellipsoid3f ellipsoid0;
	ellipsoid0.Center = Vector3f::ZERO;
	ellipsoid0.Axis[0] = Vector3f::UNIT_X;
	ellipsoid0.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid0.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid0.Extent[0] = 1.0f;
	ellipsoid0.Extent[1] = 1.0f;
	ellipsoid0.Extent[2] = 1.0f;

	Ellipsoid3f ellipsoid1;
	ellipsoid1.Center = Vector3f(0.01f, 0.02f, 0.03f);
	ellipsoid1.Axis[0] = Vector3f::UNIT_X;
	ellipsoid1.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid1.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid1.Extent[0] = 9.0f;
	ellipsoid1.Extent[1] = 10.0f;
	ellipsoid1.Extent[2] = 8.0f;

	AffineTransform(3, ellipsoid0, ellipsoid1);

	IntrEllipsoid3Ellipsoid3f calc(ellipsoid0, ellipsoid1);
	IntrEllipsoid3Ellipsoid3f::Classification type = calc.GetClassification();
	assertion(
	    type == IntrEllipsoid3Ellipsoid3f::EC_ELLIPSOID1_CONTAINS_ELLIPSOID0,
	    "Incorrect result.\n");
	WM5_UNUSED(type);
}
//----------------------------------------------------------------------------
void TestEllipsoidsIntersecting ()
{
	Ellipsoid3f ellipsoid0;
	ellipsoid0.Center = Vector3f::ZERO;
	ellipsoid0.Axis[0] = Vector3f::UNIT_X;
	ellipsoid0.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid0.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid0.Extent[0] = 1.0f;
	ellipsoid0.Extent[1] = 1.0f;
	ellipsoid0.Extent[2] = 1.0f;

	Ellipsoid3f ellipsoid1;
	ellipsoid1.Center = Vector3f(0.01f, 0.02f, 0.03f);
	ellipsoid1.Axis[0] = Vector3f::UNIT_X;
	ellipsoid1.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid1.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid1.Extent[0] = 0.1f;
	ellipsoid1.Extent[1] = 10.0f;
	ellipsoid1.Extent[2] = 8.0f;

	AffineTransform(4, ellipsoid0, ellipsoid1);

	IntrEllipsoid3Ellipsoid3f calc(ellipsoid0, ellipsoid1);
	IntrEllipsoid3Ellipsoid3f::Classification type = calc.GetClassification();
	assertion(
	    type == IntrEllipsoid3Ellipsoid3f::EC_ELLIPSOIDS_INTERSECTING,
	    "Incorrect result.\n");
	WM5_UNUSED(type);
}
//----------------------------------------------------------------------------
void TestEllipsoidsSeparated1 ()
{
	Ellipsoid3f ellipsoid0;
	ellipsoid0.Center = Vector3f::ZERO;
	ellipsoid0.Axis[0] = Vector3f::UNIT_X;
	ellipsoid0.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid0.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid0.Extent[0] = 1.0f;
	ellipsoid0.Extent[1] = 1.0f;
	ellipsoid0.Extent[2] = 1.0f;

	Ellipsoid3f ellipsoid1;
	ellipsoid1.Center = Vector3f(4.0f, 4.0f, 4.0f);
	ellipsoid1.Axis[0] = Vector3f::UNIT_X;
	ellipsoid1.Axis[1] = Vector3f::UNIT_Y;
	ellipsoid1.Axis[2] = Vector3f::UNIT_Z;
	ellipsoid1.Extent[0] = 0.1f;
	ellipsoid1.Extent[1] = 0.3f;
	ellipsoid1.Extent[2] = 0.2f;

	AffineTransform(1, ellipsoid0, ellipsoid1);

	IntrEllipsoid3Ellipsoid3f calc(ellipsoid0, ellipsoid1);
	IntrEllipsoid3Ellipsoid3f::Classification type = calc.GetClassification();
	assertion(type == IntrEllipsoid3Ellipsoid3f::EC_ELLIPSOIDS_SEPARATED,
	          "Incorrect result.\n");
	WM5_UNUSED(type);
}
Beispiel #4
0
Delaunay1<Real>::Delaunay1 (const char* filename, int mode)
	:
	Delaunay<Real>(0, (Real)0, false, Query::QT_REAL)
{
	mVertices = 0;
	bool loaded = Load(filename, mode);
	assertion(loaded, "Cannot open file %s\n", filename);
	WM5_UNUSED(loaded);
}
Beispiel #5
0
//----------------------------------------------------------------------------
void CollisionsMovingSpheres::UpdateSpheres ()
{
    float contactTime;
    Colliders::CollisionType eType = mColliders.Find(mSimTime, mVelocity0,
        mVelocity1, contactTime);
    WM5_UNUSED(eType);

    if (contactTime < 0.0f)
    {
        contactTime = 0.0f;
    }

    if (contactTime <= mSimTime)
    {
        // Move the spheres through the time to make contact.
        mSphere0.Center += contactTime*mVelocity0;
        mSphere1.Center += contactTime*mVelocity1;
        Vector3f contactPoint = mColliders.GetContactPoint();

        // Compute the unit-length normals at the contact point.
        Vector3f normal0 = contactPoint - mSphere0.Center;
        normal0.Normalize();
        Vector3f normal1 = contactPoint - mSphere1.Center;
        normal1.Normalize();

        // Reflect the velocities through the normals.
        mVelocity0 -= 2.0f*mVelocity0.Dot(normal1)*normal1;
        mVelocity1 -= 2.0f*mVelocity1.Dot(normal0)*normal0;
        mSimTime -= contactTime;
    }
    else
    {
        mSphere0.Center += mSimDelta*mVelocity0;
        mSphere1.Center += mSimDelta*mVelocity1;
        mSimTime = mSimDelta;
    }

    // Keep the spheres inside the world sphere.
    Vector3f diff = mSphere0.Center - mBoundingSphere.Center;
    float length = diff.Normalize();
    if (length >= mBoundingSphere.Radius)
    {
        mSphere0.Center = mBoundingSphere.Radius*diff;
        mVelocity0 -= 2.0f*mVelocity0.Dot(diff)*diff;
    }
    diff = mSphere1.Center - mBoundingSphere.Center;
    length = diff.Normalize();
    if (length >= mBoundingSphere.Radius)
    {
        mSphere1.Center = mBoundingSphere.Radius*diff;
        mVelocity1 -= 2.0f*mVelocity1.Dot(diff)*diff;
    }

    mMesh0->LocalTransform.SetTranslate(mSphere0.Center);
    mMesh1->LocalTransform.SetTranslate(mSphere1.Center);
    mScene->Update();
}
Beispiel #6
0
 ConvexHull2<Real>::ConvexHull2 ( const char* filename, int mode )
     :
     ConvexHull<Real>( 0, ( Real )0, false, Query::QT_REAL ),
     mVertices( 0 ),
     mSVertices( 0 ),
     mQuery( 0 )
 {
     bool loaded = Load( filename, mode );
     assertion( loaded, "Cannot open file %s\n", filename );
     WM5_UNUSED( loaded );
 }
    void NaturalSpline1<Real>::CreateClampedSpline ( Real slopeFirst,
            Real slopeLast )
    {
        mB = new1<Real>( mNumSegments + 1 );
        mC = new1<Real>( mNumSegments );
        mD = new1<Real>( mNumSegments );

        Real* delta = new1<Real>( mNumSamples );
        Real* invDelta = new1<Real>( mNumSamples );
        Real* fDeriv = new1<Real>( mNumSamples );
        int i;
        for ( i = 0; i < mNumSamples; ++i )
        {
            delta[i] = mTimes[i + 1] - mTimes[i];
            invDelta[i] = ( ( Real )1 ) / delta[i];
            fDeriv[i] = ( mA[i + 1] - mA[i] ) * invDelta[i];
        }

        const int numSegmentsM1 = mNumSegments - 1;
        Real* diagonal = new1<Real>( numSegmentsM1 );
        Real* rhs = new1<Real>( numSegmentsM1 );
        for ( i = 0; i < numSegmentsM1; ++i )
        {
            diagonal[i] = ( ( Real )2 ) * ( delta[i + 1] + delta[i] );
            rhs[i] = ( ( Real )3 ) * ( delta[i] * fDeriv[i + 1] + delta[i + 1] * fDeriv[i] );
        }
        rhs[0] -= slopeFirst * delta[1];
        rhs[mNumSegments - 2] -= slopeLast * delta[mNumSegments - 2];

        // The boundary conditions.
        mB[0] = slopeFirst;
        mB[mNumSegments] = slopeLast;

        // The linear system that determines B[1] through B[numSegs-1].
        bool solved = LinearSystem<Real>().SolveTri( numSegmentsM1, &delta[2],
                      diagonal, delta, rhs, &mB[1] );
        assertion( solved, "Failed to solve linear system\n" );
        WM5_UNUSED( solved );

        const Real oneThird = ( ( Real )1 ) / ( Real )3;
        for ( i = 0; i < mNumSegments; ++i )
        {
            mC[i] = ( ( ( Real )3 ) * fDeriv[i] - mB[i + 1] - ( ( Real )2 ) * mB[i] ) * invDelta[i];
            mD[i] = oneThird * ( mB[i + 1] - mB[i] -
                                 ( ( Real )2 ) * delta[i] * mC[i] ) * invDelta[i] * invDelta[i];
        }

        delete1( delta );
        delete1( invDelta );
        delete1( fDeriv );
        delete1( diagonal );
        delete1( rhs );
    }
//----------------------------------------------------------------------------
void NonlocalBlowup::SquareGaussFour0p50 (float dt, float dx, float dy)
{
    BuildSquareDomain();
    BuildInitialDataGaussFour();

    float p = 0.50f;
    bool success = false;
    mSolver = new0 NonlocalSolver2(DIMENSION, DIMENSION, &mInitialData,
        &mDomain, dt, dx, dy, p, success);
    assertion(success, "Failed to create solver.\n");
    WM5_UNUSED(success);

    mPrefix = ThePath + "Movies/SquareGaussFour0p50_";
}
    void NaturalSpline1<Real>::CreateFreeSpline ()
    {
        mB = new1<Real>( mNumSegments );
        mC = new1<Real>( mNumSegments + 1 );
        mD = new1<Real>( mNumSegments );

        Real* delta = new1<Real>( mNumSamples );
        Real* invDelta = new1<Real>( mNumSamples );
        Real* fDeriv = new1<Real>( mNumSamples );
        int i;
        for ( i = 0; i < mNumSamples; ++i )
        {
            delta[i] = mTimes[i + 1] - mTimes[i];
            invDelta[i] = ( ( Real )1 ) / delta[i];
            fDeriv[i] = ( mA[i + 1] - mA[i] ) * invDelta[i];
        }

        const int numSegmentsM1 = mNumSegments - 1;
        Real* diagonal = new1<Real>( numSegmentsM1 );
        Real* rhs = new1<Real>( numSegmentsM1 );
        for ( i = 0; i < numSegmentsM1; ++i )
        {
            diagonal[i] = ( ( Real )2 ) * ( delta[i + 1] + delta[i] );
            rhs[i] = ( ( Real )3 ) * ( fDeriv[i + 1] - fDeriv[i] );
        }

        // The boundary conditions.
        mC[0] = ( Real )0;
        mC[mNumSegments] = ( Real )0;

        // The linear system that determines C[1] through C[numSegs-1].
        bool solved = LinearSystem<Real>().SolveTri( numSegmentsM1, &delta[1],
                      diagonal, &delta[1], rhs, &mC[1] );
        assertion( solved, "Failed to solve linear system\n" );
        WM5_UNUSED( solved );

        const Real oneThird = ( ( Real )1 ) / ( Real )3;
        for ( i = 0; i < mNumSegments; ++i )
        {
            mB[i] = fDeriv[i] - delta[i] * oneThird * ( mC[i + 1] + ( ( Real )2 ) * mC[i] );
            mD[i] = oneThird * ( mC[i + 1] - mC[i] ) * invDelta[i];
        }

        delete1( delta );
        delete1( invDelta );
        delete1( fDeriv );
        delete1( diagonal );
        delete1( rhs );
    }
//----------------------------------------------------------------------------
void NonlocalBlowup::NonconvexDomain0p50 (float dt, float dx, float dy)
{
    BuildPolygonDomain();

    //BuildInitialData0();
    //BuildInitialDataGaussXY();  // Appears to blow up everywhere.
    BuildInitialDataGaussXYOff();

    float p = 0.50f;
    bool success = false;
    mSolver = new0 NonlocalSolver2(DIMENSION, DIMENSION, &mInitialData,
        &mDomain, dt, dx, dy, p, success);
    assertion(success, "Failed to create solver.\n");
    WM5_UNUSED(success);

    mPrefix = ThePath + "Movies/Nonconvex0p50_";
}
//----------------------------------------------------------------------------
bool GpuLocalSolver2::OnPreIteration (uint64_t iteration)
{
#ifdef PRE_GAUSSSEIDEL_SAVE
    int j0 = mDimension[0]*(mDimension[1]/2);
    for (int i0 = 0; i0 < mDimension[0]; ++i0, ++j0)
    {
        mSlice[i0] = mReadBack[j0];
    }

    int frame = (int)iteration;
    SaveGraph(mFolder, frame, 100.0f, mDimension[0], mSlice);

    float umax = mSlice[mDimension[0]/2];
    std::cout << "frame = " << frame << " : umax = " << umax << std::endl;
#else
    WM5_UNUSED(iteration);
#endif
    return true;
}
Beispiel #12
0
//----------------------------------------------------------------------------
bool GpuLocalSolver3::OnPreIteration (uint64_t iteration)
{
#ifdef PRE_GAUSSSEIDEL_SAVE
	int u, v;
	for (int i0 = 0; i0 < mDimension[0]; ++i0)
	{
		Map3Dto2D(i0, mDimension[1]/2, mDimension[2]/2, u, v);
		mSlice[i0] = mReadBack[u + mBound[0]*v];
	}

	int frame = (int)iteration;
	SaveGraph(mFolder, frame, 100.0f, mDimension[0], mSlice);

	float umax = mSlice[mDimension[0]/2];
	std::cout << "frame = " << frame << " : umax = " << umax << std::endl;
#else
	WM5_UNUSED(iteration);
#endif
	return true;
}
//----------------------------------------------------------------------------
void TestEllipsesE1ContainsE0 ()
{
	Ellipse2f ellipse0;
	ellipse0.Center = Vector2f::ZERO;
	ellipse0.Axis[0] = Vector2f::UNIT_X;
	ellipse0.Axis[1] = Vector2f::UNIT_Y;
	ellipse0.Extent[0] = 1.0f;
	ellipse0.Extent[1] = 1.0f;

	Ellipse2f ellipse1;
	ellipse1.Center = Vector2f(0.01f, 0.02f);
	ellipse1.Axis[0] = Vector2f::UNIT_X;
	ellipse1.Axis[1] = Vector2f::UNIT_Y;
	ellipse1.Extent[0] = 9.0f;
	ellipse1.Extent[1] = 10.0f;

	AffineTransform(3, ellipse0, ellipse1);

	IntrEllipse2Ellipse2f calc(ellipse0, ellipse1);
	IntrEllipse2Ellipse2f::Classification type = calc.GetClassification();
	assertion(type == IntrEllipse2Ellipse2f::EC_ELLIPSE1_CONTAINS_ELLIPSE0,
	          "Incorrect result.\n");
	WM5_UNUSED(type);
}
//----------------------------------------------------------------------------
void TestEllipsesIntersecting ()
{
	Ellipse2f ellipse0;
	ellipse0.Center = Vector2f::ZERO;
	ellipse0.Axis[0] = Vector2f::UNIT_X;
	ellipse0.Axis[1] = Vector2f::UNIT_Y;
	ellipse0.Extent[0] = 1.0f;
	ellipse0.Extent[1] = 1.0f;

	Ellipse2f ellipse1;
	ellipse1.Center = Vector2f(0.01f, 0.02f);
	ellipse1.Axis[0] = Vector2f::UNIT_X;
	ellipse1.Axis[1] = Vector2f::UNIT_Y;
	ellipse1.Extent[0] = 0.1f;
	ellipse1.Extent[1] = 10.0f;

	AffineTransform(4, ellipse0, ellipse1);

	IntrEllipse2Ellipse2f calc(ellipse0, ellipse1);
	IntrEllipse2Ellipse2f::Classification type = calc.GetClassification();
	assertion(type == IntrEllipse2Ellipse2f::EC_ELLIPSES_INTERSECTING,
	          "Incorrect result.\n");
	WM5_UNUSED(type);
}
//----------------------------------------------------------------------------
void TestEllipsesSeparated1 ()
{
	Ellipse2f ellipse0;
	ellipse0.Center = Vector2f::ZERO;
	ellipse0.Axis[0] = Vector2f::UNIT_X;
	ellipse0.Axis[1] = Vector2f::UNIT_Y;
	ellipse0.Extent[0] = 1.0f;
	ellipse0.Extent[1] = 1.0f;

	Ellipse2f ellipse1;
	ellipse1.Center = Vector2f(4.0f, 4.0f);
	ellipse1.Axis[0] = Vector2f::UNIT_X;
	ellipse1.Axis[1] = Vector2f::UNIT_Y;
	ellipse1.Extent[0] = 0.1f;
	ellipse1.Extent[1] = 0.3f;

	AffineTransform(1, ellipse0, ellipse1);

	IntrEllipse2Ellipse2f calc(ellipse0, ellipse1);
	IntrEllipse2Ellipse2f::Classification type = calc.GetClassification();
	assertion(type == IntrEllipse2Ellipse2f::EC_ELLIPSES_SEPARATED,
	          "Incorrect result.\n");
	WM5_UNUSED(type);
}
BSplineSurfaceFit<Real>::BSplineSurfaceFit (int degree0, int numControls0,
    int numSamples0, int degree1, int numControls1, int numSamples1,
    Vector3<Real>** samples)
{
    assertion(1 <= degree0 && degree0 + 1 < numControls0, "Invalid input\n");
    assertion(numControls0 <= numSamples0, "Invalid input\n");
    assertion(1 <= degree1 && degree1 + 1 < numControls1, "Invalid input\n");
    assertion(numControls1 <= numSamples1, "Invalid input\n");

    mDegree[0] = degree0;
    mNumSamples[0] = numSamples0;
    mNumControls[0] = numControls0;
    mDegree[1] = degree1;
    mNumSamples[1] = numSamples1;
    mNumControls[1] = numControls1;
    mSamples = samples;
    mControls = new2<Vector3<Real> >(numControls0, numControls1);

    // The double-precision basis functions are used to help with the
    // numerical round-off errors.
    BSplineFitBasisd* dBasis[2];
    double tMultiplier[2];
    int dim;
    for (dim = 0; dim < 2; ++dim)
    {
        mBasis[dim] = new0 BSplineFitBasis<Real>(mNumControls[dim],
            mDegree[dim]);

        dBasis[dim] = new0 BSplineFitBasisd(mNumControls[dim],
            mDegree[dim]);

        tMultiplier[dim] = 1.0/(double)(mNumSamples[dim] - 1);
    }

    // Fit the data points with a B-spline surface using a least-squares error
    // metric.  The problem is of the form A0^T*A0*Q*A1^T*A1 = A0^T*P*A1, where
    // A0^T*A0 and A1^T*A1 are banded matrices, P contains the sample data, and
    // Q is the unknown matrix of control points.

    double t;
    int i0, i1, i2, imin, imax;

    // Construct the matrices A0^T*A0 and A1^T*A1.
    BandedMatrixd* ATAMat[2];
    for (dim = 0; dim < 2; ++dim)
    {
        ATAMat[dim] = new0 BandedMatrixd(mNumControls[dim],
            mDegree[dim] + 1, mDegree[dim] + 1);

        for (i0 = 0; i0 < mNumControls[dim]; ++i0)
        {
            for (i1 = 0; i1 < i0; ++i1)
            {
                (*ATAMat[dim])(i0, i1) = (*ATAMat[dim])(i1, i0);
            }

            int i1Max = i0 + mDegree[dim];
            if (i1Max >= mNumControls[dim])
            {
                i1Max = mNumControls[dim] - 1;
            }

            for (i1 = i0; i1 <= i1Max; ++i1)
            {
                double value = 0.0;
                for (i2 = 0; i2 < mNumSamples[dim]; ++i2)
                {
                    t = tMultiplier[dim]*(double)i2;
                    dBasis[dim]->Compute(t, imin, imax);
                    if (imin <= i0 && i0 <= imax && imin <= i1 && i1 <= imax)
                    {
                        double b0 = dBasis[dim]->GetValue(i0 - imin);
                        double b1 = dBasis[dim]->GetValue(i1 - imin);
                        value += b0*b1;
                    }
                }
                (*ATAMat[dim])(i0, i1) = value;
            }
        }
    }

    // Construct the matrices A0^T and A1^T.  A[d]^T has mNumControls[d]
    // rows and mNumSamples[d] columns.
    double** ATMat[2];
    for (dim = 0; dim < 2; dim++)
    {
        ATMat[dim] = new2<double>(mNumSamples[dim], mNumControls[dim]);
        memset(ATMat[dim][0], 0,
            mNumControls[dim]*mNumSamples[dim]*sizeof(double));

        for (i0 = 0; i0 < mNumControls[dim]; ++i0)
        {
            for (i1 = 0; i1 < mNumSamples[dim]; ++i1)
            {
                t = tMultiplier[dim]*(double)i1;
                dBasis[dim]->Compute(t, imin, imax);
                if (imin <= i0 && i0 <= imax)
                {
                    ATMat[dim][i0][i1] = dBasis[dim]->GetValue(i0 - imin);
                }
            }
        }
    }

    // Compute X0 = (A0^T*A0)^{-1}*A0^T and X1 = (A1^T*A1)^{-1}*A1^T by
    // solving the linear systems A0^T*A0*X0 = A0^T and A1^T*A1*X1 = A1^T.
    for (dim = 0; dim < 2; ++dim)
    {
        bool solved = ATAMat[dim]->SolveSystem(ATMat[dim], mNumSamples[dim]);
        assertion(solved, "Failed to solve linear system\n");
        WM5_UNUSED(solved);
    }

    // The control points for the fitted surface are stored in the matrix
    // Q = X0*P*X1^T, where P is the matrix of sample data.
    for (i1 = 0; i1 < mNumControls[1]; ++i1)
    {
        for (i0 = 0; i0 < mNumControls[0]; ++i0)
        {
            Vector3<Real> sum = Vector3<Real>::ZERO;
            for (int j1 = 0; j1 < mNumSamples[1]; ++j1)
            {
                Real x1Value = (Real)ATMat[1][i1][j1];
                for (int j0 = 0; j0 < mNumSamples[0]; ++j0)
                {
                    Real x0Value = (Real)ATMat[0][i0][j0];
                    sum += (x0Value*x1Value)*mSamples[j1][j0];
                }
            }
            mControls[i1][i0] = sum;
        }
    }

    for (dim = 0; dim < 2; ++dim)
    {
        delete0(dBasis[dim]);
        delete0(ATAMat[dim]);
        delete2(ATMat[dim]);
    }
}
    void NaturalSpline1<Real>::CreatePeriodicSpline ()
    {
        mB = new1<Real>( mNumSegments );
        mC = new1<Real>( mNumSegments );
        mD = new1<Real>( mNumSegments );

#if 1
        // Solving the system using a standard linear solver appears to be
        // numerically stable.
        const int size = 4 * mNumSegments;
        GMatrix<Real> mat( size, size );
        GVector<Real> rhs( size );
        int i, j, k;
        Real delta, delta2, delta3;
        for ( i = 0, j = 0; i < mNumSegments - 1; ++i, j += 4 )
        {
            delta = mTimes[i + 1] - mTimes[i];
            delta2 = delta * delta;
            delta3 = delta * delta2;

            mat[j + 0][j + 0] = ( Real )1;
            mat[j + 0][j + 1] = ( Real )0;
            mat[j + 0][j + 2] = ( Real )0;
            mat[j + 0][j + 3] = ( Real )0;
            mat[j + 1][j + 0] = ( Real )1;
            mat[j + 1][j + 1] = delta;
            mat[j + 1][j + 2] = delta2;
            mat[j + 1][j + 3] = delta3;
            mat[j + 2][j + 0] = ( Real )0;
            mat[j + 2][j + 1] = ( Real )1;
            mat[j + 2][j + 2] = ( ( Real )2 ) * delta;
            mat[j + 2][j + 3] = ( ( Real )3 ) * delta2;
            mat[j + 3][j + 0] = ( Real )0;
            mat[j + 3][j + 1] = ( Real )0;
            mat[j + 3][j + 2] = ( Real )1;
            mat[j + 3][j + 3] = ( ( Real )3 ) * delta;

            k = j + 4;
            mat[j + 0][k + 0] = ( Real )0;
            mat[j + 0][k + 1] = ( Real )0;
            mat[j + 0][k + 2] = ( Real )0;
            mat[j + 0][k + 3] = ( Real )0;
            mat[j + 1][k + 0] = ( Real ) - 1;
            mat[j + 1][k + 1] = ( Real )0;
            mat[j + 1][k + 2] = ( Real )0;
            mat[j + 1][k + 3] = ( Real )0;
            mat[j + 2][k + 0] = ( Real )0;
            mat[j + 2][k + 1] = ( Real ) - 1;
            mat[j + 2][k + 2] = ( Real )0;
            mat[j + 2][k + 3] = ( Real )0;
            mat[j + 3][k + 0] = ( Real )0;
            mat[j + 3][k + 1] = ( Real )0;
            mat[j + 3][k + 2] = ( Real ) - 1;
            mat[j + 3][k + 3] = ( Real )0;
        }

        delta = mTimes[i + 1] - mTimes[i];
        delta2 = delta * delta;
        delta3 = delta * delta2;

        mat[j + 0][j + 0] = ( Real )1;
        mat[j + 0][j + 1] = ( Real )0;
        mat[j + 0][j + 2] = ( Real )0;
        mat[j + 0][j + 3] = ( Real )0;
        mat[j + 1][j + 0] = ( Real )1;
        mat[j + 1][j + 1] = delta;
        mat[j + 1][j + 2] = delta2;
        mat[j + 1][j + 3] = delta3;
        mat[j + 2][j + 0] = ( Real )0;
        mat[j + 2][j + 1] = ( Real )1;
        mat[j + 2][j + 2] = ( ( Real )2 ) * delta;
        mat[j + 2][j + 3] = ( ( Real )3 ) * delta2;
        mat[j + 3][j + 0] = ( Real )0;
        mat[j + 3][j + 1] = ( Real )0;
        mat[j + 3][j + 2] = ( Real )1;
        mat[j + 3][j + 3] = ( ( Real )3 ) * delta;

        k = 0;
        mat[j + 0][k + 0] = ( Real )0;
        mat[j + 0][k + 1] = ( Real )0;
        mat[j + 0][k + 2] = ( Real )0;
        mat[j + 0][k + 3] = ( Real )0;
        mat[j + 1][k + 0] = ( Real ) - 1;
        mat[j + 1][k + 1] = ( Real )0;
        mat[j + 1][k + 2] = ( Real )0;
        mat[j + 1][k + 3] = ( Real )0;
        mat[j + 2][k + 0] = ( Real )0;
        mat[j + 2][k + 1] = ( Real ) - 1;
        mat[j + 2][k + 2] = ( Real )0;
        mat[j + 2][k + 3] = ( Real )0;
        mat[j + 3][k + 0] = ( Real )0;
        mat[j + 3][k + 1] = ( Real )0;
        mat[j + 3][k + 2] = ( Real ) - 1;
        mat[j + 3][k + 3] = ( Real )0;

        for ( i = 0, j = 0; i < mNumSegments; ++i, j += 4 )
        {
            rhs[j + 0] = mA[i];
            rhs[j + 1] = ( Real )0;
            rhs[j + 2] = ( Real )0;
            rhs[j + 3] = ( Real )0;
        }

        GVector<Real> coeff( size );
        bool solved = LinearSystem<Real>().Solve( mat, rhs, coeff );
        assertion( solved, "Failed to solve linear system\n" );
        WM5_UNUSED( solved );

        for ( i = 0, j = 0; i < mNumSegments; ++i )
        {
            j++;
            mB[i] = coeff[j++];
            mC[i] = coeff[j++];
            mD[i] = coeff[j++];
        }
#endif

#if 0
        // Solving the system using the equations derived in the PDF
        // "Fitting a Natural Spline to Samples of the Form (t,f(t))"
        // is ill-conditioned.  TODO: Find a way to row-reduce the matrix of the
        // PDF in a numerically stable manner yet retaining the O(n) asymptotic
        // behavior.

        // Compute the inverses M[i]^{-1}.
        const int numSegmentsM1 = mNumSegments - 1;
        Matrix4<Real>* invM = new1<Matrix4<Real> >( numSegmentsM1 );

        Real delta;
        int i;
        for ( i = 0; i < numSegmentsM1; i++ )
        {
            delta = mTimes[i + 1] - mTimes[i];
            Real invDelta1 = ( ( Real )1 ) / delta;
            Real invDelta2 = invDelta1 / delta;
            Real invDelta3 = invDelta2 / delta;

            Matrix4<Real>& invMi = invM[i];
            invMi[0][0] = ( Real )1;
            invMi[0][1] = ( Real )0;
            invMi[0][2] = ( Real )0;
            invMi[0][3] = ( Real )0;
            invMi[1][0] = ( ( Real )( -3 ) ) * invDelta1;
            invMi[1][1] = ( ( Real )3 ) * invDelta1;
            invMi[1][2] = ( Real )( -2 );
            invMi[1][3] = delta;
            invMi[2][0] = ( ( Real )3 ) * invDelta2;
            invMi[2][1] = ( ( Real )( -3 ) ) * invDelta2;
            invMi[2][2] = ( ( Real )3 ) * invDelta1;
            invMi[2][3] = ( Real )( -2 );
            invMi[3][0] = -invDelta3;
            invMi[3][1] = invDelta3;
            invMi[3][2] = -invDelta2;
            invMi[3][3] = invDelta1;
        }

        // Matrix M[n-1].
        delta = mTimes[i + 1] - mTimes[i];
        Real delta2 = delta * delta;
        Real delta3 = delta2 * delta;
        Matrix4<Real> lastM
        (
            ( Real )1, ( Real )0, ( Real )0, ( Real )0,
            ( Real )1, delta, delta2, delta3,
            ( Real )0, ( Real )1, ( ( Real )2 )*delta, ( ( Real )3 )*delta2,
            ( Real )0, ( Real )0, ( Real )1, ( ( Real )3 )*delta
        );

        // Matrix L.
        Matrix4<Real> LMat
        (
            ( Real )0, ( Real )0, ( Real )0, ( Real )0,
            ( Real )1, ( Real )0, ( Real )0, ( Real )0,
            ( Real )0, ( Real )1, ( Real )0, ( Real )0,
            ( Real )0, ( Real )0, ( Real )1, ( Real )0
        );

        // Vector U.
        Vector<4, Real> U( ( Real )1, ( Real )0, ( Real )0, ( Real )0 );

        // Initialize P = L and Q = f[n-2]*U.
        Matrix4<Real> P = LMat;

        const int numSegmentsM2 = mNumSegments - 2;
        Vector<4, Real> Q = mA[numSegmentsM2] * U;

        // Compute P and Q.
        for ( i = numSegmentsM2; i >= 0; --i )
        {
            // Matrix L*M[i]^{-1}.
            Matrix4<Real> LMInv = LMat * invM[i];

            // Update P.
            P = LMInv * P;

            // Update Q.
            if ( i > 0 )
            {
                Q = mA[i - 1] * U + LMInv * Q;
            }
            else
            {
                Q = mA[numSegmentsM1] * U + LMInv * Q;
            }
        }

        // Final update of P.
        P = lastM - P;

        // Compute P^{-1}.
        Matrix4<Real> invP = P.Inverse();

        // Compute K[n-1].
        Vector<4, Real> coeff = invP * Q;
        mB[numSegmentsM1] = coeff[1];
        mC[numSegmentsM1] = coeff[2];
        mD[numSegmentsM1] = coeff[3];

        // Back substitution for the other K[i].
        for ( i = numSegmentsM2; i >= 0; i-- )
        {
            coeff = invM[i] * ( mA[i] * U + LMat * coeff );
            mB[i] = coeff[1];
            mC[i] = coeff[2];
            mD[i] = coeff[3];
        }

        delete1( invM );
#endif
    }
Beispiel #18
0
Real* PolyFit3 (int numSamples, const Real* xSamples, const Real* ySamples,
    const Real* wSamples, int xDegree, int yDegree)
{
    int xBound = xDegree + 1;
    int yBound = yDegree + 1;
    int quantity = xBound*yBound;
    Real* coeff = new1<Real>(quantity);

    int i0, j0, i1, j1, s;

    // Powers of x, y.
    Real** xPower = new2<Real>(2*xDegree+1, numSamples);
    Real** yPower = new2<Real>(2*yDegree+1, numSamples);
    for (s = 0; s < numSamples; ++s)
    {
        xPower[s][0] = (Real)1;
        for (i0 = 1; i0 <= 2*xDegree; ++i0)
        {
            xPower[s][i0] = xSamples[s]*xPower[s][i0-1];
        }

        yPower[s][0] = (Real)1;
        for (j0 = 1; j0 <= 2*yDegree; ++j0)
        {
            yPower[s][j0] = ySamples[s]*yPower[s][j0-1];
        }
    }

    // Vandermonde matrix and right-hand side of linear system.
    GMatrix<Real> A(quantity, quantity);
    Real* B = new1<Real>(quantity);

    for (j0 = 0; j0 <= yDegree; ++j0)
    {
        for (i0 = 0; i0 <= xDegree; ++i0)
        {
            int index0 = i0 + xBound*j0;
            Real sum = (Real)0;
            for (s = 0; s < numSamples; ++s)
            {
                sum += wSamples[s]*xPower[s][i0]*yPower[s][j0];
            }

            B[index0] = sum;

            for (j1 = 0; j1 <= yDegree; ++j1)
            {
                for (i1 = 0; i1 <= xDegree; ++i1)
                {
                    int index1 = i1 + xBound*j1;
                    sum = (Real)0;
                    for (s = 0; s < numSamples; ++s)
                    {
                        sum += xPower[s][i0 + i1]*yPower[s][j0 + j1];
                    }

                    A(index0,index1) = sum;
                }
            }
        }
    }

    // Solve for the polynomial coefficients.
    bool hasSolution = LinearSystem<Real>().Solve(A, B, coeff);
    assertion(hasSolution, "Failed to solve linear system\n");
    WM5_UNUSED(hasSolution);

    delete1(B);
    delete2(xPower);
    delete2(yPower);

    return coeff;
}
Beispiel #19
0
double LCPPolyDist<Dimension,FVector,DVector>::ProcessLoop (
    bool halfspaceConstructor, int& statusCode, FVector closest[2])
{
    int i;
    double* Q = new1<double>(mNumEquations);
    double** M = new2<double>(mNumEquations, mNumEquations);

    statusCode = 0;

    bool processing = true;
    if (!BuildMatrices(M, Q))
    {
        WM5_LCPPOLYDIST_FUNCTION(CloseLog());
        closest[0] = FVector::ZERO;
        closest[1] = FVector::ZERO;
        processing = false;
    }

    WM5_LCPPOLYDIST_FUNCTION(PrintMatrices(M, Q));

    int tryNumber = 0;
    double distance = -Mathd::MAX_REAL;
    while (processing)
    {
        double* zResult = new1<double>(mNumEquations);
        double* wResult = new1<double>(mNumEquations);
        int lcpStatusCode;

        LCPSolver solver(mNumEquations, M, Q, zResult, wResult, lcpStatusCode);
        WM5_UNUSED(solver);

        switch (lcpStatusCode)
        {
        case SC_FOUND_TRIVIAL_SOLUTION:
        {
            statusCode = SC_FOUND_TRIVIAL_SOLUTION;
            break;
        }
        case SC_FOUND_SOLUTION:
        {
            DVector lcpClosest[2];
            for (i = 0; i < mDimension; ++i)
            {
                lcpClosest[0][i] = (float)zResult[i];
                lcpClosest[1][i] = (float)zResult[i + mDimension];
            }

            DVector diff = lcpClosest[0] - lcpClosest[1];
            distance = diff.Length();

            statusCode = VerifySolution(lcpClosest);

            if (!halfspaceConstructor)
            {
                WM5_LCPPOLYDIST_FUNCTION(VerifyWithTestPoints(lcpClosest,
                    statusCode));
            }

            for (i = 0; i < mDimension; ++i)
            {
                closest[0][i] = (float)lcpClosest[0][i];
                closest[1][i] = (float)lcpClosest[1][i];
            }
            processing = false;
            break;
        }
        case SC_CANNOT_REMOVE_COMPLEMENTARY:
        {
            WM5_LCPPOLYDIST_FUNCTION(LogRetries(tryNumber));
            if (tryNumber == 3)
            {
                statusCode = SC_CANNOT_REMOVE_COMPLEMENTARY;
                processing = false;
                break;
            }
            MoveHalfspaces(mNumFaces1, mA1, mB1);
            WM5_LCPPOLYDIST_FUNCTION(LogHalfspaces(mNumFaces1, mA1, mB1));
            MoveHalfspaces(mNumFaces2, mA2, mB2);
            WM5_LCPPOLYDIST_FUNCTION(LogHalfspaces(mNumFaces2, mA2, mB2));
            BuildMatrices(M, Q);
            ++tryNumber;
            break;
        }
        case SC_EXCEEDED_MAX_RETRIES:
        {
            WM5_LCPPOLYDIST_FUNCTION(LCPSolverLoopLimit());
            statusCode = SC_EXCEEDED_MAX_RETRIES;
            processing = false;
            break;
        }
        }
        delete1(wResult);
        delete1(zResult);
    }

    delete2(M);
    delete1(Q);

    return distance;
}
void ContEllipse2MinCR<Real>::MaxProduct (std::vector<Vector2<Real> >& A,
    Real D[2])
{
    // Keep track of which constraint lines have already been used in the
    // search.
    int numConstraints = (int)A.size();
    bool* used = new1<bool>(numConstraints);
    memset(used, 0, numConstraints*sizeof(bool));

    // Find the constraint line whose y-intercept (0,ymin) is closest to the
    // origin.  This line contributes to the convex hull of the constraints
    // and the search for the maximum starts here.  Also find the constraint
    // line whose x-intercept (xmin,0) is closest to the origin.  This line
    // contributes to the convex hull of the constraints and the search for
    // the maximum terminates before or at this line.
    int i, iYMin = -1;
    int iXMin = -1;
    Real axMax = (Real)0, ayMax = (Real)0;  // A[i] >= (0,0) by design
    for (i = 0; i < numConstraints; ++i)
    {
        // The minimum x-intercept is 1/A[iXMin].X() for A[iXMin].X() the
        // maximum of the A[i].X().
        if (A[i].X() > axMax)
        {
            axMax = A[i].X();
            iXMin = i;
        }

        // The minimum y-intercept is 1/A[iYMin].Y() for A[iYMin].Y() the
        // maximum of the A[i].Y().
        if (A[i].Y() > ayMax)
        {
            ayMax = A[i].Y();
            iYMin = i;
        }
    }
    assertion(iXMin != -1 && iYMin != -1, "Unexpected condition\n");
    WM5_UNUSED(iXMin);

    used[iYMin] = true;

    // The convex hull is searched in a clockwise manner starting with the
    // constraint line constructed above.  The next vertex of the hull occurs
    // as the closest point to the first vertex on the current constraint
    // line.  The following loop finds each consecutive vertex.
    Real x0 = (Real)0, xMax = ((Real)1)/axMax;
    int j;
    for (j = 0; j < numConstraints; ++j)
    {
        // Find the line whose intersection with the current line is closest
        // to the last hull vertex.  The last vertex is at (x0,y0) on the
        // current line.
        Real x1 = xMax;
        int line = -1;
        for (i = 0; i < numConstraints; ++i)
        {
            if (!used[i])
            {
                // This line not yet visited, process it.  Given current
                // constraint line a0*x+b0*y =1 and candidate line
                // a1*x+b1*y = 1, find the point of intersection.  The
                // determinant of the system is d = a0*b1-a1*b0.  We only
                // care about lines that have more negative slope than the
                // previous one, that is, -a1/b1 < -a0/b0, in which case we
                // process only lines for which d < 0.
                Real det = A[iYMin].DotPerp(A[i]);
                if (det < (Real)0)  // TO DO.  Need epsilon test here?
                {
                    // Compute the x-value for the point of intersection,
                    // (x1,y1).  There may be floating point error issues in
                    // the comparision 'D[0] <= fX1'.  Consider modifying to
                    // 'D[0] <= fX1+epsilon'.
                    D[0] = (A[i].Y() - A[iYMin].Y())/det;
                    if (x0 < D[0] && D[0] <= x1)
                    {
                        line = i;
                        x1 = D[0];
                    }
                }
            }
        }

        // Next vertex is at (x1,y1) whose x-value was computed above.  First
        // check for the maximum of x*y on the current line for x in [x0,x1].
        // On this interval the function is f(x) = x*(1-a0*x)/b0.  The
        // derivative is f'(x) = (1-2*a0*x)/b0 and f'(r) = 0 when
        // r = 1/(2*a0).  The three candidates for the maximum are f(x0),
        // f(r), and f(x1).  Comparisons are made between r and the end points
        // x0 and x1.  Since a0 = 0 is possible (constraint line is horizontal
        // and f is increasing on line), the division in r is not performed
        // and the comparisons are made between 1/2 = a0*r and a0*x0 or a0*x1.

        // Compare r < x0.
        if ((Real)0.5 < A[iYMin].X()*x0)
        {
            // The maximum is f(x0) since the quadratic f decreases for
            // x > r.
            D[0] = x0;
            D[1] = ((Real)1 - A[iYMin].X()*D[0])/A[iYMin].Y();  // = f(x0)
            break;
        }

        // Compare r < x1.
        if ((Real)0.5 < A[iYMin].X()*x1)
        {
            // The maximum is f(r).  The search ends here because the
            // current line is tangent to the level curve of f(x)=f(r)
            // and x*y can therefore only decrease as we traverse further
            // around the hull in the clockwise direction.
            D[0] = ((Real)0.5)/A[iYMin].X();
            D[1] = ((Real)0.5)/A[iYMin].Y();  // = f(r)
            break;
        }

        // The maximum is f(x1).  The function x*y is potentially larger
        // on the next line, so continue the search.
        assertion(line != -1, "Unexpected condition\n");
        x0 = x1;
        x1 = xMax;
        used[line] = true;
        iYMin = line;
    }

    assertion(j < numConstraints, "Unexpected condition\n");

    delete1(used);
}
Beispiel #21
0
BSplineCurveFit<Real>::BSplineCurveFit (int dimension, int numSamples,
    const Real* sampleData, int degree, int numControls)
    :
    mBasis(numControls, degree)
{
    assertion(dimension >= 1, "Invalid input\n");
    assertion(1 <= degree && degree < numControls, "Invalid input\n");
    assertion(numControls <= numSamples, "Invalid input\n");

    mDimension = dimension;
    mNumSamples = numSamples;
    mSampleData = sampleData;
    mDegree = degree;
    mNumControls = numControls;
    mControlData = new1<Real>(mDimension*numControls);

    // The double-precision basis functions are used to help with the
    // numerical round-off errors.
    BSplineFitBasisd dBasis(mNumControls,mDegree);
    double tMultiplier = 1.0/(double)(mNumSamples - 1);

    // Fit the data points with a B-spline curve using a least-squares error
    // metric.  The problem is of the form A^T*A*Q = A^T*P, where A^T*A is a
    // banded matrix, P contains the sample data, and Q is the unknown vector
    // of control points.

    double t;
    int i0, i1, i2, imin, imax, j;

    // Construct the matrix A^T*A.
    BandedMatrixd* ATAMat = new0 BandedMatrixd(mNumControls,
        mDegree + 1, mDegree + 1);

    for (i0 = 0; i0 < mNumControls; ++i0)
    {
        for (i1 = 0; i1 < i0; ++i1)
        {
            (*ATAMat)(i0, i1) = (*ATAMat)(i1, i0);
        }

        int i1Max = i0 + mDegree;
        if (i1Max >= mNumControls)
        {
            i1Max = mNumControls - 1;
        }

        for (i1 = i0; i1 <= i1Max; ++i1)
        {
            double value = 0.0;
            for (i2 = 0; i2 < mNumSamples; ++i2)
            {
                t = tMultiplier*(double)i2;
                dBasis.Compute(t, imin, imax);
                if (imin <= i0 && i0 <= imax && imin <= i1 && i1 <= imax)
                {
                    double dB0 = dBasis.GetValue(i0 - imin);
                    double dB1 = dBasis.GetValue(i1 - imin);
                    value += dB0*dB1;
                }
            }
            (*ATAMat)(i0, i1) = value;
        }
    }

    // Construct the matrix A^T.
    double** ATMat = new2<double>(mNumSamples, mNumControls);
    memset(ATMat[0], 0, mNumControls*mNumSamples*sizeof(double));
    for (i0 = 0; i0 < mNumControls; ++i0)
    {
        for (i1 = 0; i1 < mNumSamples; ++i1)
        {
            t = tMultiplier*(double)i1;
            dBasis.Compute(t, imin, imax);
            if (imin <= i0 && i0 <= imax)
            {
                ATMat[i0][i1] = dBasis.GetValue(i0 - imin);
            }
        }
    }

    // Compute X0 = (A^T*A)^{-1}*A^T by solving the linear system
    // A^T*A*X = A^T.
    bool solved = ATAMat->SolveSystem(ATMat,mNumSamples);
    assertion(solved, "Failed to solve linear system\n");
    WM5_UNUSED(solved);

    // The control points for the fitted curve are stored in the vector
    // Q = X0*P, where P is the vector of sample data.
    memset(mControlData, 0, mNumControls*mDimension*sizeof(Real));
    for (i0 = 0; i0 < mNumControls; ++i0)
    {
        Real* Q = mControlData + i0*mDimension;
        for (i1 = 0; i1 < mNumSamples; ++i1)
        {
            const Real* P = mSampleData + i1*mDimension;
            Real xValue = (Real)ATMat[i0][i1];
            for (j = 0; j < mDimension; j++)
            {
                Q[j] += xValue*P[j];
            }
        }
    }

    // Set the first and last output control points to match the first and
    // last input samples.  This supports the application of fitting keyframe
    // data with B-spline curves.  The user expects that the curve passes
    // through the first and last positions in order to support matching two
    // consecutive keyframe sequences.
    Real* cEnd0 = mControlData;
    const Real* sEnd0 = mSampleData;
    Real* cEnd1 = &mControlData[mDimension*(mNumControls-1)];
    const Real* sEnd1 = &mSampleData[mDimension*(mNumSamples-1)];
    for (j = 0; j < mDimension; j++)
    {
        *cEnd0++ = *sEnd0++;
        *cEnd1++ = *sEnd1++;
    }

    delete2(ATMat);
    delete0(ATAMat);
}
Beispiel #22
0
bool ConvexHull3<Real>::Update (int i)
{
    // Locate a triangle visible to the input point (if possible).
    Triangle* visible = 0;
    Triangle* tri;
    typename std::set<Triangle*>::iterator iter = mHull.begin();
    typename std::set<Triangle*>::iterator end = mHull.end();
    for (/**/; iter != end; ++iter)
    {
        tri = *iter;
        if (tri->GetSign(i, mQuery) > 0)
        {
            visible = tri;
            break;
        }
    }

    if (!visible)
    {
        // The point is inside the current hull; nothing to do.
        return true;
    }

    // Locate and remove the visible triangles.
    std::stack<Triangle*> visibleSet;
    std::map<int,TerminatorData> terminator;
    visibleSet.push(visible);
    visible->OnStack = true;
    int j, v0, v1;
    while (!visibleSet.empty())
    {
        tri = visibleSet.top();
        visibleSet.pop();
        tri->OnStack = false;
        for (j = 0; j < 3; ++j)
        {
            Triangle* adj = tri->Adj[j];
            if (adj)
            {
                // Detach triangle and adjacent triangle from each other.
                int nullIndex = tri->DetachFrom(j, adj);

                if (adj->GetSign(i, mQuery) > 0)
                {
                    if (!adj->OnStack)
                    {
                        // Adjacent triangle is visible.
                        visibleSet.push(adj);
                        adj->OnStack = true;
                    }
                }
                else
                {
                    // Adjacent triangle is invisible.
                    v0 = tri->V[j];
                    v1 = tri->V[(j+1)%3];
                    terminator[v0] = TerminatorData(v0, v1, nullIndex, adj);
                }
            }
        }
        mHull.erase(tri);
        delete0(tri);
    }

    // Insert the new edges formed by the input point and the terminator
    // between visible and invisible triangles.
    int size = (int)terminator.size();
    assertion(size >= 3, "Terminator must be at least a triangle\n");
    typename std::map<int,TerminatorData>::iterator edge = terminator.begin();
    v0 = edge->second.V[0];
    v1 = edge->second.V[1];
    tri = new0 Triangle(i, v0, v1);
    mHull.insert(tri);

    // Save information for linking first/last inserted new triangles.
    int saveV0 = edge->second.V[0];
    Triangle* saveTri = tri;

    // Establish adjacency links across terminator edge.
    tri->Adj[1] = edge->second.T;
    edge->second.T->Adj[edge->second.NullIndex] = tri;
    for (j = 1; j < size; ++j)
    {
        edge = terminator.find(v1);
        assertion(edge != terminator.end(), "Unexpected condition\n");
        v0 = v1;
        v1 = edge->second.V[1];
        Triangle* next = new0 Triangle(i, v0, v1);
        mHull.insert(next);

        // Establish adjacency links across terminator edge.
        next->Adj[1] = edge->second.T;
        edge->second.T->Adj[edge->second.NullIndex] = next;

        // Establish adjacency links with previously inserted triangle.
        next->Adj[0] = tri;
        tri->Adj[2] = next;

        tri = next;
    }
    assertion(v1 == saveV0, "Expecting initial vertex\n");
    WM5_UNUSED(saveV0);

    // Establish adjacency links between first/last triangles.
    saveTri->Adj[0] = tri;
    tri->Adj[2] = saveTri;
    return true;
}
Beispiel #23
0
ConformalMap<Real>::ConformalMap (int numPoints,
    const Vector3<Real>* points, int numTriangles, const int* indices,
    int punctureTriangle)
{
    // Construct a vertex-triangle-edge representation of mesh.
    BasicMesh mesh(numPoints, points, numTriangles, indices);
    int numEdges = mesh.GetNumEdges();
    const BasicMesh::Edge* edges = mesh.GetEdges();
    const BasicMesh::Triangle* triangles = mesh.GetTriangles();

    mPlanes = new1<Vector2<Real> >(numPoints);
    mSpheres = new1<Vector3<Real> >(numPoints);

    // Construct sparse matrix A nondiagonal entries.
    typename LinearSystem<Real>::SparseMatrix AMat;
    int i, e, t, v0, v1, v2;
    Real value = (Real)0;
    for (e = 0; e < numEdges; ++e)
    {
        const BasicMesh::Edge& edge = edges[e];
        v0 = edge.V[0];
        v1 = edge.V[1];

        Vector3<Real> E0, E1;

        const BasicMesh::Triangle& T0 = triangles[edge.T[0]];
        for (i = 0; i < 3; ++i)
        {
            v2 = T0.V[i];
            if (v2 != v0 && v2 != v1)
            {
                E0 = points[v0] - points[v2];
                E1 = points[v1] - points[v2];
                value = E0.Dot(E1)/E0.Cross(E1).Length();
            }
        }

        const BasicMesh::Triangle& T1 = triangles[edge.T[1]];
        for (i = 0; i < 3; ++i)
        {
            v2 = T1.V[i];
            if (v2 != v0 && v2 != v1)
            {
                E0 = points[v0] - points[v2];
                E1 = points[v1] - points[v2];
                value += E0.Dot(E1)/E0.Cross(E1).Length();
            }
        }

        value *= -(Real)0.5;
        AMat[std::make_pair(v0, v1)] = value;
    }

    // Aonstruct sparse matrix A diagonal entries.
    Real* tmp = new1<Real>(numPoints);
    memset(tmp, 0, numPoints*sizeof(Real));
    typename LinearSystem<Real>::SparseMatrix::iterator iter = AMat.begin();
    typename LinearSystem<Real>::SparseMatrix::iterator end = AMat.end();
    for (/**/; iter != end; ++iter)
    {
        v0 = iter->first.first;
        v1 = iter->first.second;
        value = iter->second;
        assertion(v0 != v1, "Unexpected condition\n");
        tmp[v0] -= value;
        tmp[v1] -= value;
    }
    for (int v = 0; v < numPoints; ++v)
    {
        AMat[std::make_pair(v, v)] = tmp[v];
    }

    assertion(numPoints + numEdges == (int)AMat.size(),
        "Mismatch in sizes\n");

    // Construct column vector B (happens to be sparse).
    const BasicMesh::Triangle& tri = triangles[punctureTriangle];
    v0 = tri.V[0];
    v1 = tri.V[1];
    v2 = tri.V[2];
    Vector3<Real> V0 = points[v0];
    Vector3<Real> V1 = points[v1];
    Vector3<Real> V2 = points[v2];
    Vector3<Real> E10 = V1 - V0;
    Vector3<Real> E20 = V2 - V0;
    Vector3<Real> E12 = V1 - V2;
    Vector3<Real> cross = E20.Cross(E10);
    Real len10 = E10.Length();
    Real invLen10 = ((Real)1)/len10;
    Real twoArea = cross.Length();
    Real invLenCross = ((Real)1)/twoArea;
    Real invProd = invLen10*invLenCross;
    Real re0 = -invLen10;
    Real im0 = invProd*E12.Dot(E10);
    Real re1 = invLen10;
    Real im1 = invProd*E20.Dot(E10);
    Real re2 = (Real)0;
    Real im2 = -len10*invLenCross;

    // Solve sparse system for real parts.
    memset(tmp, 0, numPoints*sizeof(Real));
    tmp[v0] = re0;
    tmp[v1] = re1;
    tmp[v2] = re2;
    Real* result = new1<Real>(numPoints);
    bool solved = LinearSystem<Real>().SolveSymmetricCG(numPoints, AMat, tmp,
        result);
    assertion(solved, "Failed to solve linear system\n");
    WM5_UNUSED(solved);
    for (i = 0; i < numPoints; ++i)
    {
        mPlanes[i].X() = result[i];
    }

    // Solve sparse system for imaginary parts.
    memset(tmp, 0, numPoints*sizeof(Real));
    tmp[v0] = -im0;
    tmp[v1] = -im1;
    tmp[v2] = -im2;
    solved = LinearSystem<Real>().SolveSymmetricCG(numPoints, AMat, tmp,
        result);
    assertion(solved, "Failed to solve linear system\n");
    for (i = 0; i < numPoints; ++i)
    {
        mPlanes[i].Y() = result[i];
    }
    delete1(tmp);
    delete1(result);

    // Scale to [-1,1]^2 for numerical conditioning in later steps.
    Real fmin = mPlanes[0].X(), fmax = fmin;
    for (i = 0; i < numPoints; i++)
    {
        if (mPlanes[i].X() < fmin)
        {
            fmin = mPlanes[i].X();
        }
        else if (mPlanes[i].X() > fmax)
        {
            fmax = mPlanes[i].X();
        }
        if (mPlanes[i].Y() < fmin)
        {
            fmin = mPlanes[i].Y();
        }
        else if (mPlanes[i].Y() > fmax)
        {
            fmax = mPlanes[i].Y();
        }
    }
    Real halfRange = ((Real)0.5)*(fmax - fmin);
    Real invHalfRange = ((Real)1)/halfRange;
    for (i = 0; i < numPoints; ++i)
    {
        mPlanes[i].X() = -(Real)1 + invHalfRange*(mPlanes[i].X() - fmin);
        mPlanes[i].Y() = -(Real)1 + invHalfRange*(mPlanes[i].Y() - fmin);
    }

    // Map plane points to sphere using inverse stereographic projection.
    // The main issue is selecting a translation in (x,y) and a radius of
    // the projection sphere.  Both factors strongly influence the final
    // result.

    // Use the average as the south pole.  The points tend to be clustered
    // approximately in the middle of the conformally mapped punctured
    // triangle, so the average is a good choice to place the pole.
    Vector2<Real> origin((Real)0 ,(Real)0 );
    for (i = 0; i < numPoints; ++i)
    {
        origin += mPlanes[i];
    }
    origin /= (Real)numPoints;
    for (i = 0; i < numPoints; ++i)
    {
        mPlanes[i] -= origin;
    }

    mPlaneMin = mPlanes[0];
    mPlaneMax = mPlanes[0];
    for (i = 1; i < numPoints; ++i)
    {
        if (mPlanes[i].X() < mPlaneMin.X())
        {
            mPlaneMin.X() = mPlanes[i].X();
        }
        else if (mPlanes[i].X() > mPlaneMax.X())
        {
            mPlaneMax.X() = mPlanes[i].X();
        }

        if (mPlanes[i].Y() < mPlaneMin.Y())
        {
            mPlaneMin.Y() = mPlanes[i].Y();
        }
        else if (mPlanes[i].Y() > mPlaneMax.Y())
        {
            mPlaneMax.Y() = mPlanes[i].Y();
        }
    }

    // Select the radius of the sphere so that the projected punctured
    // triangle has an area whose fraction of total spherical area is the
    // same fraction as the area of the punctured triangle to the total area
    // of the original triangle mesh.
    Real twoTotalArea = (Real)0;
    for (t = 0; t < numTriangles; ++t)
    {
        const BasicMesh::Triangle& T0 = triangles[t];
        const Vector3<Real>& V0 = points[T0.V[0]];
        const Vector3<Real>& V1 = points[T0.V[1]];
        const Vector3<Real>& V2 = points[T0.V[2]];
        Vector3<Real> E0 = V1 - V0, E1 = V2 - V0;
        twoTotalArea += E0.Cross(E1).Length();
    }
    mRadius = ComputeRadius(mPlanes[v0], mPlanes[v1], mPlanes[v2],
        twoArea/twoTotalArea);
    Real radiusSqr = mRadius*mRadius;

    // Inverse stereographic projection to obtain sphere coordinates.  The
    // sphere is centered at the origin and has radius 1.
    for (i = 0; i < numPoints; i++)
    {
        Real rSqr = mPlanes[i].SquaredLength();
        Real mult = ((Real)1)/(rSqr + radiusSqr);
        Real x = ((Real)2)*mult*radiusSqr*mPlanes[i].X();
        Real y = ((Real)2)*mult*radiusSqr*mPlanes[i].Y();
        Real z = mult*mRadius*(rSqr - radiusSqr);
        mSpheres[i] = Vector3<Real>(x,y,z)/mRadius;
    }
}
BSplineReduction<Real,TVector>::BSplineReduction (int numCtrlPoints,
        const TVector* ctrlPoints, int degree, Real fraction, int& outNumCtrlPoints,
        TVector*& outCtrlPoints)
{
	// Check for valid input.  If invalid, return a "null" curve.
	assertion(numCtrlPoints >= 2, "Invalid input\n");
	assertion(ctrlPoints != 0, "Invalid input\n");
	assertion(1 <= degree && degree < numCtrlPoints, "Invalid input\n");
	if (numCtrlPoints < 2 || !ctrlPoints || degree < 1
	        ||  degree >= numCtrlPoints)
	{
		outNumCtrlPoints = 0;
		outCtrlPoints = 0;
		return;
	}

	// Clamp the number of control points to [degree+1,quantity-1].
	outNumCtrlPoints = (int)(fraction*numCtrlPoints);
	if (outNumCtrlPoints > numCtrlPoints)
	{
		outNumCtrlPoints = numCtrlPoints;
		outCtrlPoints = new1<TVector>(outNumCtrlPoints);
		memcpy(outCtrlPoints, ctrlPoints, numCtrlPoints*sizeof(TVector));
		return;
	}
	if (outNumCtrlPoints < degree + 1)
	{
		outNumCtrlPoints = degree + 1;
	}

	// Allocate output control points and set all to the zero vector.
	outCtrlPoints = new1<TVector>(outNumCtrlPoints);

	// Set up basis function parameters.  Function 0 corresponds to the
	// output curve.  Function 1 corresponds to the input curve.
	mDegree = degree;
	mQuantity[0] = outNumCtrlPoints;
	mQuantity[1] = numCtrlPoints;

	for (int j = 0; j <= 1; ++j)
	{
		mNumKnots[j] = mQuantity[j] + mDegree + 1;
		mKnot[j] = new1<Real>(mNumKnots[j]);

		int i;
		for (i = 0; i <= mDegree; ++i)
		{
			mKnot[j][i] = (Real)0;
		}

		Real factor = ((Real)1)/(Real)(mQuantity[j] - mDegree);
		for (/**/; i < mQuantity[j]; ++i)
		{
			mKnot[j][i] = (i-mDegree)*factor;
		}

		for (/**/; i < mNumKnots[j]; i++)
		{
			mKnot[j][i] = (Real)1;
		}
	}

	// Construct matrix A (depends only on the output basis function).
	Real value, tmin, tmax;
	int i0, i1;

	mBasis[0] = 0;
	mBasis[1] = 0;

	BandedMatrix<Real> A(mQuantity[0], mDegree, mDegree);
	for (i0 = 0; i0 < mQuantity[0]; ++i0)
	{
		mIndex[0] = i0;
		tmax = MaxSupport(0, i0);

		for (i1 = i0; i1 <= i0 + mDegree && i1 < mQuantity[0]; ++i1)
		{
			mIndex[1] = i1;
			tmin = MinSupport(0, i1);

			value = Integrate1<Real>::RombergIntegral(8, tmin, tmax,
			        Integrand, this);
			A(i0, i1) = value;
			A(i1, i0) = value;
		}
	}

	// Construct A^{-1}.
	GMatrix<Real> invA(mQuantity[0], mQuantity[0]);
	bool solved = LinearSystem<Real>().Invert(A, invA);
	assertion(solved, "Failed to solve linear system\n");
	WM5_UNUSED(solved);

	// Construct B (depends on both input and output basis functions).
	mBasis[1] = 1;
	GMatrix<Real> B(mQuantity[0], mQuantity[1]);
	for (i0 = 0; i0 < mQuantity[0]; ++i0)
	{
		mIndex[0] = i0;
		Real tmin0 = MinSupport(0, i0);
		Real tmax0 = MaxSupport(0, i0);

		for (i1 = 0; i1 < mQuantity[1]; ++i1)
		{
			mIndex[1] = i1;
			Real tmin1 = MinSupport(1, i1);
			Real tmax1 = MaxSupport(1, i1);

			Intersector1<Real> intr(tmin0, tmax0, tmin1, tmax1);
			intr.Find();
			int quantity = intr.GetNumIntersections();

			if (quantity == 2)
			{
				value = Integrate1<Real>::RombergIntegral(8,
				        intr.GetIntersection(0), intr.GetIntersection(1),
				        Integrand, this);
				B[i0][i1] = value;
			}
			else
			{
				B[i0][i1] = (Real)0;
			}
		}
	}

	// Construct A^{-1}*B.
	GMatrix<Real> prod = invA*B;

	// Construct the control points for the least-squares curve.
	memset(outCtrlPoints,0,outNumCtrlPoints*sizeof(TVector));
	for (i0 = 0; i0 < mQuantity[0]; ++i0)
	{
		for (i1 = 0; i1 < mQuantity[1]; ++i1)
		{
			outCtrlPoints[i0] += ctrlPoints[i1]*prod[i0][i1];
		}
	}
}