Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a list of ID2D1Geometry objects and I'm trying to use CompareWithGeometry to detect collisions in Direct2D; unfortunately, I'm not getting the results I need. I suspect I am improperly using the inputGeometryTransform parameter.

If I pass in D2D1::Matrix3x2F::Identity() or nullptr for this parameter, I almost always get D2D1_GEOMETRY_RELATION_CONTAINS (3) or D2D1_GEOMETRY_RELATION_IS_CONTAINED (2) results back for the returned D2D1_GEOMETRY_RELATION. On the other hand, if I try and pass in the product of the scale and translation matrices that I used to generate the primary geometry, then I never get collisions.

Can someone help me understand what I need to pass in for the inputGeometryTransform parameter?

The source code that I believe to be relevant appears below:

// This is Shawn Eary's broken code and it is licensed 2012 under the
// Microsoft Public License (Ms-PL) which is compatible with the 
// Open Source Initiative
//
// Shawn Eary is not affiliated with Microsoft.  
// He just likes the Ms-PL
void SpaceObject::updateDynamics(
    Microsoft::WRL::ComPtr<ID2D1DeviceContext> const i_d2dContext, 
    D2D1::Matrix3x2F const & tranformMatrix)
{
    D2D1_SIZE_F renderTargetSize = i_d2dContext->GetSize();
    float const worldWidth = renderTargetSize.width / 2.0f; 
    float const halfWorldWidth = worldWidth / 2.0f; 
    float const worldHeight = renderTargetSize.height / 2.0f; 
    float const halfWorldHieght = worldHeight / 2.0f; 

    // Update the position in ideal coordinates
    double idealX = m_p.x + m_v.x;
    double idealY = m_p.y + m_v.y; 

    // Account for wrap around  
    m_p.x = getWrappedResult(idealX, worldWidth); 
    m_p.y = getWrappedResult(idealY, worldHeight); 
    m_p.theta += m_v.theta; 

    m_v.x += m_a.x;
    m_v.y += m_a.y; 
    m_v.theta += m_a.theta; 

    // Compute results of elastic collisions
    for (list<SpaceObject *>::iterator it = m_myObjectWorldP->begin(); it != m_myObjectWorldP->end(); it++) {
        SpaceObject * const SOP = (*it);    

        // This eventually needs to be fixed, but for now assume all 
        // spaceObjects are GeometrySpaceObjects 
        GeometrySpaceObject * thisGSOP = dynamic_cast<GeometrySpaceObject*>(this); 
        GeometrySpaceObject * currentGSOP = dynamic_cast<GeometrySpaceObject*>(SOP); 

        // Don't compare this SpaceObject with itself
        if (thisGSOP != currentGSOP) {      
            ID2D1PathGeometry * const thisGP = thisGSOP->gGeoP(); 
            ID2D1PathGeometry * const curGP = currentGSOP->gGeoP();
            D2D1_GEOMETRY_RELATION theRelation; 
            thisGP->CompareWithGeometry(
                (ID2D1Geometry *)curGP, 
                tranformMatrix, 
                &theRelation
            );
            if (theRelation != D2D1_GEOMETRY_RELATION_DISJOINT) {
                // A Collision has occured.
                // 
                // Use conservation of momentum to update 
                // velocities after collission here
                int placeHolder = 0; 
            }           
        }
    }   

    this->updateAcceleration();     
}

Note: At the time I asked this question, the documentation I found on the MSDN site was a bit unclear regarding the inputGeometryTransform Parameter. The documentation I viewed was visible at this URL: http://msdn.microsoft.com/en-us/library/windows/desktop/dd316638(v=vs.85).aspx

share|improve this question
    
The inputGeometryTransform parameter of CompareWithGeometry is apparently the "world" transformation used to scale and position objects. This doesn't work so well for me because each of my spaceObjects use different transformations. As an example spaceObject1 might have a translation of -100, -100 with a rotation of 45 degrees while spaceObject2 might have a translation of 100, 100 with no rotation. For CompareWithGeometry to be useful for me, I really need it to allow for two transformations. One for the host geometry and one for the target geometry. –  Shawn Eary May 28 '12 at 3:23

1 Answer 1

As said in the comment, the inputGeometryTransform Parameter is used to scale, rotate or translate the target geometry before it is compared with the host geometry. Without that translation, geometries will be processed relative to where their figure began in their associated Geometry Sinks; unfortunately, only being able to scale the target geometry was a bit awkward for me so I found an interesting function called CreateTransformedGeometry. Using a few MSDN examples, I was able to create this function that was useful to me:

// This is Shawn Eary's code and it is licenced under the
// Microsoft Public License (Ms-PL) which is compatible with the 
// Open Source Initiative
//
// Shawn Eary is not affiliated with Microsoft.  
// He just likes the Ms-PL
// 
// References and Influences Used: 
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd742769(v=vs.85).aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd742730(v=vs.85).aspx
HRESULT TransformGeometry(
    ID2D1Geometry *ipGeometryToTransform,
    ID2D1Geometry **oppTranformedGeometry, 
    D2D1_MATRIX_3X2_F const & transform
    )
{
    HRESULT hr;
    ID2D1Factory *pFactory = NULL;
    ipGeometryToTransform->GetFactory(&pFactory);

    ID2D1TransformedGeometry *pTransformedGeometry = NULL;
    hr = pFactory->CreateTransformedGeometry(
        ipGeometryToTransform,
        transform,
        &pTransformedGeometry
     );

    *oppTranformedGeometry = pTransformedGeometry;
    (*oppTranformedGeometry)->AddRef();
    pTransformedGeometry->Release();

    return hr;
}

Then, using the new TransformGeometry function, my UpdateDynamics code could then could be rewritten for hit-testing like this:

// This is Shawn Eary's code and it is licenced under the
// Microsoft Public License (Ms-PL) which is compatible with the 
// Open Source Initiative
//
// Shawn Eary is not affiliated with Microsoft.  
// He just likes the Ms-PL
void SpaceObject::updateDynamics(
    Microsoft::WRL::ComPtr<ID2D1DeviceContext> const i_d2dContext)
{
    D2D1_SIZE_F renderTargetSize = i_d2dContext->GetSize();
    float const worldWidth = renderTargetSize.width / 2.0f; 
    float const halfWorldWidth = worldWidth / 2.0f; 
    float const worldHeight = renderTargetSize.height / 2.0f; 
    float const halfWorldHieght = worldHeight / 2.0f; 

    // Update the position in ideal coordinates
    double idealX = m_p.x + m_v.x;
    double idealY = m_p.y + m_v.y; 

    // Account for wrap around  
    m_p.x = getWrappedResult(idealX, worldWidth); 
    m_p.y = getWrappedResult(idealY, worldHeight); 
    m_p.theta += m_v.theta; 

    m_v.x += m_a.x;
    m_v.y += m_a.y; 
    m_v.theta += m_a.theta; 

    // Compute results of elastic collisions
    for (list<SpaceObject *>::iterator it = m_myObjectWorldP->begin(); it != m_myObjectWorldP->end(); it++) {
        SpaceObject * const SOP = (*it);

        // This eventually needs to be fixed, but for now assume all 
        // spaceObjects are GeometrySpaceObjects 
        GeometrySpaceObject * thisGSOP = dynamic_cast<GeometrySpaceObject*>(this); 
        GeometrySpaceObject * currentGSOP = dynamic_cast<GeometrySpaceObject*>(SOP); 

        // Don't compare this SpaceObject with itself
        if (thisGSOP != currentGSOP) {
            D2D1_MATRIX_3X2_F thisTransform = thisGSOP->gTransformation();
            D2D1_MATRIX_3X2_F currentTransform = currentGSOP->gTransformation();
            ID2D1PathGeometry * const thisGP = thisGSOP->gGeoP(); 
            ID2D1PathGeometry * const curGP = currentGSOP->gGeoP();

            D2D1_GEOMETRY_RELATION theRelation; 
            ID2D1Geometry * thisTGP; 
            TransformGeometry(thisGP, &thisTGP, thisTransform); 
            ID2D1Geometry * currentTGP; 
            TransformGeometry(curGP, &currentTGP, currentTransform); 
            thisTGP->CompareWithGeometry(
                (ID2D1Geometry *)currentTGP, 
                NULL, 
                &theRelation
            );          
            thisTGP->Release(); 
            currentTGP->Release(); 
            if (theRelation != D2D1_GEOMETRY_RELATION_DISJOINT) {

                // A Collision has occured.
                // 
                // Use conservation of momentum to update 
                // velocities after collission here
                int placeHolder = 0; 
            }           
        }
    }   

    this->updateAcceleration();     
} 
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.