5

I have some C# code that decodes map paths encoded using Google's polyline algorithm and am trying to convert it to VB.NET.

Here's the C# code, which works fully:

Collection<Double> decodePolyline(string polyline)
    {
        if (polyline == null || polyline == "") return null;

        char[] polylinechars = polyline.ToCharArray();
        int index = 0;
        Collection<Double> points = new Collection<Double>();
        int currentLat = 0;
        int currentLng = 0;
        int next5bits;
        int sum;
        int shifter;

        while (index < polylinechars.Length)
        {
            // calculate next latitude
            sum = 0;
            shifter = 0;
            do
            {
                next5bits = (int)polylinechars[index++] - 63;
                sum |= (next5bits & 31) << shifter;
                shifter += 5;
            } while (next5bits >= 32 && index < polylinechars.Length);

            if (index >= polylinechars.Length)
                break;

            currentLat += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);

            //calculate next longitude
            sum = 0;
            shifter = 0;
            do
            {
                next5bits = (int)polylinechars[index++] - 63;
                sum |= (next5bits & 31) << shifter;
                shifter += 5;
            } while (next5bits >= 32 && index < polylinechars.Length);

            if (index >= polylinechars.Length && next5bits >= 32)
                break;

            currentLng += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);

            points.Add(Convert.ToDouble(currentLat) / 100000.0);
            points.Add(Convert.ToDouble(currentLng) / 100000.0);
        }

        return points;
    }

Here's the VB.NET code- works for the longitudes but not latitudes.

Public Function decodePolyline(ByVal polyline As String) As Collection(Of Double)
    If polyline Is Nothing OrElse polyline = "" Then Return Nothing

    Dim polylinechars As Char() = polyline.ToCharArray()
    Dim points As New Collection(Of Double)
    Dim currentLat As Integer = 0
    Dim currentLng As Integer = 0
    Dim next5bits As Integer
    Dim sum As Integer
    Dim shifter As Integer

    For index As Integer = 0 To polylinechars.Length - 1
        'calculate next latitude
        sum = 0
        shifter = 0
        Do
            index += 1
            next5bits = AscW(polylinechars(index)) - 63
            sum = sum Or (next5bits And 31) << shifter
            shifter += 5
        Loop While next5bits >= 32 AndAlso index < polylinechars.Length

        If index >= polylinechars.Length Then
            Exit For
        End If

        currentLat += If((sum And 1) = 1, Not (sum >> 1), (sum >> 1))

        'calculate next longitude
        sum = 0
        shifter = 0
        Do
            index += 1
            next5bits = AscW(polylinechars(index)) - 63
            sum = sum Or (next5bits And 31) << shifter
            shifter += 5
        Loop While next5bits >= 32 AndAlso index < polylinechars.Length

        If index >= polylinechars.Length AndAlso next5bits >= 32 Then
            Exit For
        End If

        currentLng += If((sum And 1) = 1, Not (sum >> 1), (sum >> 1))

        points.Add(Convert.ToDouble(currentLat) / 100000.0)
        points.Add(Convert.ToDouble(currentLng) / 100000.0)
    Next

    Return points
End Function

What's missing?

EDIT: Resolved the issue (corrected code in my answer below, which I can't select as an answer for 2 more days).

amb9800
  • 365
  • 2
  • 5
  • 14
  • (deleted my answer, as I don't think it was helping and my VB has degenerated to read-only, so I can't fix it by glance alone) – Marc Gravell Feb 27 '11 at 09:56
  • In what way it does not work? Does it compile? Shows wrong results, different from the C# version? – tiago2014 Feb 27 '11 at 10:01
  • Gives incorrect output for the latitudes. – amb9800 Feb 27 '11 at 10:02
  • 2
    Maybe it's just me, but I think it is a Bad Thing to change the value of the loop index inside a for loop. – tiago2014 Feb 27 '11 at 10:11
  • Yeah- changed it back to a `while` (though the `for` did work)-- the issue was in incrementing the loop index- `index++` in C# returns the original value, while the converted code was giving the incremented value (corrected code in my answer below). – amb9800 Feb 27 '11 at 10:20

3 Answers3

2

The best way to do it if you don't know the target language, compile your source code in debug mode, and then decompile it using Reflector. That way you keep the var names, and your sure the generated code is valid.

Be aware that VB.Net has "delicate" logical operators that could break your code logic : OR vs OrElse...

Lotfi
  • 1,205
  • 8
  • 18
  • 3
    The logical operators aren't "delicate". `OrElse` adds short-circuiting. `Or` is a bitwise operator, and does logical comparisons *without* short-circuiting. It's not fair to call something "delicate" just because it requires the programmer to understand how it works. – Cody Gray - on strike Feb 27 '11 at 09:02
  • Well, they are. if you don't know the target language and you want something functional, you don't have to read a huge book to do the job. – Lotfi Feb 27 '11 at 09:06
  • 1
    I'm really curious which programming language you can write functional code in without knowing how its operators work. Can you name one for me? *Guaranteed* that a good comprehensive book on VB is not as 'huge' as one on C++. – Cody Gray - on strike Feb 27 '11 at 09:13
  • @Cody Gray: If I have to add a 5 min fix to an existing code in a new language, doesn't meen I have to read a book for it, just a quick google search will do. OK VB.net syntax isn't that hard, but my point is if you don't know the difference between Or and OrElse, you would probably introduce bugs and/or performance issues. BTW, I come from a VB6 background, and I went into such problems just because I thought that the syntax is the same. – Lotfi Feb 27 '11 at 09:26
  • 2
    So really, your answer should have said that "VB.NET's syntax is different from VB6, despite superficial similarities. Be careful you don't inadvertently introduce bugs into your code." But then that would have been irrelevant, because the question is about converting from C# to VB.NET. Beyond that, `Or` works the same way in VB.NET that it did in VB6. You don't actually have to change your code to use `OrElse`; that's why it was added as a *separate* operator. The performance issues are minimal, and if you're introducing bugs because of short circuit evaluation, I blame your coding style. – Cody Gray - on strike Feb 27 '11 at 09:30
2

Ah so the issue was that the C# ++ operator increments the variable but returns the original value, whereas my VB.NET conversion above was incrementing index and then using the incremented value. That somehow still worked for longitudes but messed up the latitude decoding.

Here's the corrected VB.NET code:

Public Function decodePolyline(ByVal polyline As String) As Collection(Of Double)
    If polyline Is Nothing OrElse polyline = "" Then Return Nothing

    Dim polylinechars As Char() = polyline.ToCharArray()
    Dim points As New Collection(Of Double)
    Dim currentLat As Integer = 0
    Dim currentLng As Integer = 0
    Dim next5bits As Integer
    Dim sum As Integer
    Dim shifter As Integer
    Dim index As Integer = 0

    While index < polylinechars.Length
        ' calculate next latitude
        sum = 0
        shifter = 0
        Do
            index += 1
            next5bits = AscW(polylinechars(index - 1)) - 63
            sum = sum Or (next5bits And 31) << shifter
            shifter += 5
        Loop While next5bits >= 32 AndAlso index < polylinechars.Length

        If index >= polylinechars.Length Then
            Exit While
        End If

        currentLat += If((sum And 1) = 1, Not (sum >> 1), (sum >> 1))

        'calculate next longitude
        sum = 0
        shifter = 0
        Do
            index += 1
            next5bits = AscW(polylinechars(index - 1)) - 63
            sum = sum Or (next5bits And 31) << shifter
            shifter += 5
        Loop While next5bits >= 32 AndAlso index < polylinechars.Length

        If index >= polylinechars.Length AndAlso next5bits >= 32 Then
            Exit While
        End If

        currentLng += If((sum And 1) = 1, Not (sum >> 1), (sum >> 1))

        points.Add(Convert.ToDouble(currentLat) / 100000.0)
        points.Add(Convert.ToDouble(currentLng) / 100000.0)
    End While

    Return points
End Function
amb9800
  • 365
  • 2
  • 5
  • 14
0

There's an online converter by Telerik: Convert VB to C# or C# to VB.

tiago2014
  • 3,392
  • 1
  • 21
  • 28
  • Yeah that's where I started- cleaned up the VB.NET output to get what I posted above. – amb9800 Feb 27 '11 at 09:54
  • @amb9800 Your VB.NET code and the one generated by Telerik do not seen the same. You changed the `while loop` to a `for loop`, etc. Why? – tiago2014 Feb 27 '11 at 10:02