Mixed managed C++ method does not always return the same result to the calling C# code

202 Views Asked by At

A C++ method returns the correct value when I use a conditional breakpoint, but an incorrect value without a breakpoint.

C# method which calls C++:

bool SetProperty(Element element, Node referencePoint, List<Materializer> materializers, List<ulong> properties)
{
        // Loop over STLs
        for (int i = 0; i < materializers.Count; i++)
        {               
            Materializer materializer = materializers[i];

            if (materializer.IsPointInside(referencePoint.X, referencePoint.Y, referencePoint.Z, pentalTreeDatasets[i].top))
            {
                element.PropertyId = properties[i];
                return true;
            };
        }
        return false;
    }

C++ methods in the header file:

    int CountIntersects(double x, double y, double z, PentalTreeNode ^root)
    {
        Math3d::M3d rayPoints[2], intersectionPoint;

        rayPoints[0].set(x,y,z);
        rayPoints[1].set(x,y,1.0e6);

        if(!root) 
            return 0;
        else
        {
            int special = CountIntersects(x,y,z,root->special);
            if (x <= root->xMax && x >= root->xMin && y <= root->yMax && y >= root->yMin)
            {       
                if( _stlMesh->IsRayIntersectsPoly(root->index, rayPoints, intersectionPoint))
                {
                    return (1 + special);
                }
                else 
                    return special;
            }
            else
            {
             if (y>root->yMax)
                 {
                    return (CountIntersects(x,y,z,root->top)+special);
              }
              else if(y<root->yMin)
                    {
                        return (CountIntersects(x,y,z,root->bottom)+special);
                    }
                    else if(x<root->xMin)
                            {
                                return (CountIntersects(x,y,z,root->left)+special);
                            }
                            else if(x>root->xMax)
                            {
                                return (CountIntersects(x,y,z,root->right)+special);
                            }
                            else 
                                return special;
            }
        }
    }

    bool IsPointInside(double x, double y, double z, PentalTreeNode ^root)
    {
        int intersectionCount = 0;

        Math3d::M3d rayPoints[2], intersectionPoint;

        rayPoints[0].set(x,y,z);
        rayPoints[1].set(x,y,1.0e6);


        if(_box->IsContainingPoint(x,y,z))
        {           
            intersectionCount=CountIntersects(x,y,z,root);
            return (intersectionCount%2!=0);

        }   
    }

C++ methods in other header files:

    bool IsRayIntersectsPoly(int nPolygonIndex, Math3d::M3d RayPoints[2], CVector3D& IntersectionPoint)
{
    CMeshPolygonBase& Poly = m_PolygonArray[nPolygonIndex];
    CArrayResultI Result;

    int* pPolygonPoints = GetPolygonPoints(Poly, Result);

    Math3d::MPlane TrianglePlane;

    double Atmp[3], A;

    CVector3D* pPoints[3];
    pPoints[0] = &m_PointArray[*pPolygonPoints].m_Position;

    for(int i = 1; i < Result.GetSize() - 1; i++)
    {
        pPoints[1] = &m_PointArray[*(pPolygonPoints+i)].m_Position;
        pPoints[2] = &m_PointArray[*(pPolygonPoints+i+1)].m_Position;

        TrianglePlane.Init(*pPoints[0], *pPoints[1], *pPoints[2]);
        TrianglePlane.IntersectLine(RayPoints[0], RayPoints[1], IntersectionPoint);

        A = GetTriangleArea(*pPoints[0], *pPoints[1], *pPoints[2]);
        for(int j = 0; j < 3; j++)
        {
            Atmp[j] = GetTriangleArea(*pPoints[j], *pPoints[(j+1)%3], IntersectionPoint);
        }

        if( fabs(A - Atmp[0] - Atmp[1] - Atmp[2]) < 1.0e-5 ) return true;
    }

    return false;
};


    double GetTriangleArea(CVector3D& T1, CVector3D& T2, CVector3D& T3)
{
    double a, b, c, s;

    a = (T1 - T2).length();
    b = (T2 - T3).length();
    c = (T3 - T1).length();

    s = 0.5 * (a + b + c);

    return( sqrt(s * (s - a)* (s - b)* (s - c)) );
}

When I start the program which calls SetProperty() within the for-loop, the results for some iterator values are wrong. When I set conditional breakpoints for critical iterator values in the for-loop and step over it, then the result is OK for that item. What may be the problem?

This is method in which I post breakpoint. For example, for critical element.Id==2393.

 private void StartButton_Click(object sender, EventArgs e)
    {
        DateTime startTime = DateTime.Now;

        List<Materializer> materializers = new List<Materializer>();
        List<ulong> properties = new List<ulong>();

        // Load STLs
        for (int i = 0; (int)i < (this.dataGridView.RowCount - 1); i++)
        {
            if (dataGridView.Rows[i].Cells[1].Value != null && (string)dataGridView.Rows[i].Cells[1].Value != "")
            {
                Materializer materializer = new Materializer();
                materializer.LoadSTLMesh(dataGridView.Rows[i].Cells[0].Value.ToString());
                materializers.Add(materializer);
                properties.Add((ulong)dataGridView.Rows[i].Cells[1].Tag);                
            }
         }

        CreatePentalTrees(materializers);
        int processedElementCount = 0;
        int changedElementCount = 0;

        // Loop over elements
        foreach (Element element in model.ElementsList.Values)

            if ((element.Topology == 7 || element.Topology == 8) && !lockedProperties.ContainsKey(element.PropertyId)) // 3D elements only
            {


                Node center = this.CenterPoint(element, model.NodesList);

                if (element.Id == 2393)
                {
                    //if breakpoints thats ok, else not ok
                    Console.WriteLine(element.Id);
                    Console.WriteLine(element.PropertyId);
                }

                if (SetProperty(element, center, materializers, properties))   // Check for center point
                {
                    //changedElements.Add(element.Id, true);
                    changedElementCount++;
                }
                else
                {
                    // Check for all nodes if center point does not belong to any STL

                    int[] nodeOrder;

                    switch (element.Topology)
                    {
                        case 7:
                            nodeOrder = wedgeNodeOrder;
                            break;
                        case 8:
                            nodeOrder = brickNodeOrder;
                            break;
                        default:
                            throw new Exception("Unknown topology " + element.Topology.ToString());
                    }

                    for (int i = 0; i < nodeOrder.Length; i++)
                    {
                        Node node = model.NodesList[element.NodeIds[nodeOrder[i]]];

                        if (SetProperty(element, node, materializers, properties))
                        {
                            //changedElements.Add(element.Id, true);
                            changedElementCount++;
                            break;
                        }
                    }
                }

                if (++processedElementCount % 100 == 0)
                {
                    labelTime.Text = "Changed/processed elements: " + changedElementCount.ToString() + "/" + processedElementCount.ToString();
                    labelTime.Refresh();
                    Application.DoEvents();
                }

            }

        DateTime endTime = DateTime.Now;
        labelTime.Text = "Total time: " + (endTime - startTime).TotalSeconds.ToString() + " s";

        MessageBox.Show("Completed.");

        SaveFileDialog saveFileDlg = new SaveFileDialog();
        saveFileDlg.Title = "Save FEMAP neutral file";
        saveFileDlg.Filter = "(*.neu)|*.neu";
        if (saveFileDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            FemapNeutral.ExportNeu(saveFileDlg.FileName, model);
        }

    }
1

There are 1 best solutions below

2
On

You seem to be calling a lot of methods you haven't listed, and/or the wall of code made me get lost. Adding that code won't help: reducing your problem to a simpler one that demonstrates the problem might.

However, the most likely cause of your problem, if you have unmanaged code reading managed data, is that you failed to marshal or pin the data prior to using the managed code.

Unpinned data can be moved around by the garbage collector in unexpected ways.