2
Vote

New Zealand Map Grid reprojection errors due to inline modification of array in Zpoly1()

description

I was having a problem re-projecting polygons into New Zealand Map Grid. The end-points of polygons should be identical. However, when I passed the polygon coordinates into the Projections library, the end coordinates would always be different.
 
I discovered that the reprojection was going wrong in the OnForward method of the NewZealandMapGrid class.
 
There is a global array called _bf which is declared as readonly. However, when the array of coordinates was getting passed into the Proj.Zpoly1 static method, the array was getting modified, causing subsequent transformations to be incorrect.
 
It looks to me like the problem is that the _bf nested array is declared using object literal syntax, whcih makes it an array of reference types. This is bypassing the readonly declaration of the array, and consequently assignments to copies of the values
which take place inside the Proj.Zpoly1 are actually altering the array inside this method.
 
I made a shallow local copy of the _bf values, and this fixed the problem.

file attachments

comments

Rohan72 wrote Feb 23, 2012 at 1:09 AM

Just to clarify - the problem is due to the fact that arrays are passed by reference in C# (even if they are arrays of value types), not due to the way the nested array is declared.

wrote Feb 23, 2012 at 5:59 PM

Resolved with changeset 65349.

Potscrub wrote Apr 23, 2012 at 7:09 AM

Hi Rohan72 - I have been trying to convert a simple four point polygon from NZMG to WGS84 using featureset.reproject today and have had nothing but trouble. Am I missing something, is there an added step with NZMG. I works fine from any other projection I tried.....

Potscrub wrote Apr 23, 2012 at 11:51 PM

My test code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim coords As New CoordinateList
    coords.Add(New Coordinate(2730000, 6080000))
    coords.Add(New Coordinate(2730000, 6080100))

    ' coords.Add(New Coordinate(175.00001, -40.00001))
    ' coords.Add(New Coordinate(175.00001, -40.01))

    Dim alinestring As New LineString(coords)
    Dim shapepolygon As Polygon
    shapepolygon = alinestring.Buffer(10)

    Dim fs As New FeatureSet(FeatureType.Polygon)
    fs.AddFeature(shapepolygon)
    fs.Projection = KnownCoordinateSystems.Projected.NationalGridsNewZealand.NewZealandMapGrid
    fs.Reproject(KnownCoordinateSystems.Geographic.Australia.NewZealandGeodeticDatum1949)
    fs.SaveAs("c:\temp\WGS84.shp", True)

End Sub
first error occurred was "Index was outside the bounds of the array" here:
for (int j = NTPHI - 1; j > 0; j++)
                {
                    lp[phi] = _tphi[j] + p[R] * lp[phi];
                }
Where j is > 8, so I added a break for j >=8. This got it passed the first issue but then it hangs on another loop which I am having trouble finding my way through (I really have little idea when it comes to c#). Any help geratly appreciated.

Rohan72 wrote Apr 26, 2012 at 7:27 AM

Hi Potscrub,

There was a fix submitted by mudnug for the issue I reported. Oddly, it seems not to be in the current source code. I don't know what happened to it. In any case, I don't think it would have fixed the problem. It created a new version of the _bf array using Array.Copy. However, this method copies by reference for reference types, so I think it would have just reproduced the problem.

Have a look at the source attachment. It just creates a local copy of the array in each loop iteration. It seems to fix the OnForward method. Unfortunately, applying the same code change to the OnInverse method (which is probably what you want) isn't working - the results are coming back as NaN. This is why I never submitted it.

The crash you are getting seems to be due to an error in the loop beginning

for (int j = NTPHI - 1; j > 0; j++)

I think this should be j-- (or some other condition?). Otherwise the counter goes over the bounds of the array. All the same, making this fix doesn't produce valid results.

Unfortunately, I can't offer more than that.

mudnug wrote Apr 26, 2012 at 6:22 PM

You can view the fix at http://dotspatial.codeplex.com/SourceControl/changeset/changes/65349.
Please let us know if the fix solves the problem, and whether there is another issue we need to address, here.

Potscrub wrote Apr 26, 2012 at 8:47 PM

Thanks for the response guys, the modification below [from Rohan72] didnt make it into NewZealandMapGrid.cs. The fix does not address the problem in OnForward or OnInverse, I will follow Rohan72's suggestion and post back.
//HACK: Create a shallow, value-based version of the array.
//Because arrays are passed by refernce, the _bf array is getting permanently modified
//inside the Proj.Zpoly1() method. Consequently, the results returned by this method differ each time around.
            double[][] bf = new double[_bf.Length][];

            for (int k = 0; k < _bf.Length; k++)
            {
                bf[k] = new double[2];
                bf[k][0] = _bf[k][0];
                bf[k][1] = _bf[k][1];
            }
However the following was added to Proj.cs
        // make a copy of the array that we are going to modify and return.
        int size = c[n].Length;
        double[] a = new double[size];
        Array.Copy(c[n], a, size);

Potscrub wrote Apr 26, 2012 at 9:12 PM

I have applied the changes that Rohan72 suggested and it now works on the OnFoward method, nice work!! Rohan72 is also correct that the OnInverse still doesn't produce valid results although replacing j++ with j-- means it doesn't crash now.....

Mudnug, the OnInverse method of NZMG does not produce valid results, can we open this issue back up? I will have another stumble around this evening and report back if I can narrow it down.

mudnug wrote Apr 27, 2012 at 5:06 PM

** Closed by mudnug 23/02/2012 10:59

mudnug wrote Apr 27, 2012 at 5:06 PM

per Potscrub request

mudnug wrote Apr 27, 2012 at 5:06 PM

I've reopened it. did you not have that option (perhaps they only give it to "Developers")?

Potscrub wrote Apr 29, 2012 at 9:36 PM

Nope, couldn't find the option to open it up again. Had a play in the weekend but couldn't figure it out, hopefully someone with better skills can follow a co-ordinate through and see where it is going wrong...