MapInfo Pro

Welcome to the MapInfo Pro community!  Please feel free to start a discussion in the discussion tab or join in a conversation.

Here are some useful links where you can find more information:

Product Announcements  Product Documentation  Ideas Portal

Discussions

Members

Resources

Events

 View Only

MapInfo Monday: Assign Service Areas to Districts using Drivetime Polygons IV

  • 1.  MapInfo Monday: Assign Service Areas to Districts using Drivetime Polygons IV

    Employee
    Posted 5 hours ago

    Last week, we also looked at Service Area Assignment. You may recall we ended up with a pretty long script that was run from the SQL window in MapInfo Pro. If you can't remember how long that script was, please go back and have a look.

    I was basically repeating the same query with different parameters several times.

    I said this could be done more simply with an actual MapBasic add-in, so here we go.

    Assign Service Areas Add-in

    When you build a MapBasic add-in instead of a MapBasic script, you get some benefits, for example, to be able to use custom functions. It does, however, get a bit more complicated: it needs to be compiled, so you can't see or alter the code without recompiling.

    In most cases, the benefits do outplay the shortcomings.

    For example, in the script, I had to run the query several times. This is done by writing the query the same number of times. In my add-in, I can create a function that wraps my query and then call it several times with different parameters.

    I decided to build a function that could assign areas to service engineers based on the drivetime zones. The logic is the same as in the script; I just added a bit to it to count the number of areas assigned.

    Here is my function:

    '**************************************************************************
    Function AssignAreaDT(    ByVal nDTValue As Integer
                            , ByVal fOverlapPct As Float
                            ) As Integer    'Returns number of areas were assigned
    
    Dim nRows As Integer
    
    AssignAreaDT = 0
    
        Print Time(24) & " " + nDTValue + " min. Drivetime: " + Format$((fOverlapPct * 100), "#,###.") + "% Overlap" 
        Select sa.postsect, sa.NameNew, sa.DistanceNew
            , sa.PropOverlapNew, dt.NAME, dt.value
            , ProportionOverlap(sa.Obj, dt.Obj) As "PropOverlap"
            From msTabServiceAreas As "sa", msServiceEngineerDTs As "dt"
            Where sa.Obj intersects dt.Obj
            And dt.value = nDTValue
            And sa.DistanceNew = 0
            And ProportionOverlap(sa.Obj, dt.Obj) >= fOverlapPct
            Order by sa.postsect, PropOverlap Asc
            Into _to_update NoSelect Hide
    
        nRows   = TableInfo(_to_update, TAB_INFO_NROWS)
    
        If nRows > 0 Then
            Update _to_update
                Set NameNew = Name,
                DistanceNew = value,
                PropOverlapNew = PropOverlap
    
            Select postsect
                From _to_update
                Group By postsect
                Into _count_records NoSelect Hide
            nRows   = TableInfo(_count_records, TAB_INFO_NROWS)        
            Close Table _count_records
        End If 
           
        Close Table _to_update
        AssignAreaDT  = nRows
    
    End Function

    The initial query is the same as in the script. Instead of just updating the result, I start by validating the number of records to update. If there are no records, there is no reason to run the update statement.

    If I'm updating the result, I also calculate the number of records being updated. I perform an additional query to find this number, as some service areas may overlap multiple drive time zones and therefore can appear multiple times in the initial query.

    Because I now have this as a function, I can call it in my Main procedure and just change the parameters: the drivetime value in minutes and the overlap percentage.

    Here you can see how I use this function several times in my Main procedure:

        '**15 minutes    
        nValue = 15
        fOverlapPct = 0.5
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
        
        '**30 minutes    
        nValue = 30
        fOverlapPct = 0.5
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
    
        '**45 minutes    
        nValue = 45
        fOverlapPct = 0.5
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
    
        '**60 minutes    
        nValue = 60
        fOverlapPct = 0.5
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
    
        fOverlapPct = 0.25
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
        
        fOverlapPct = 0.05
        nRows           = AssignAreaDT(nValue, fOverlapPct)
        nRowsAssigned   = nRowsAssigned + nRows
        Print Time(24) & "     Assigned " & nRows & " records. Now assigned totally " & nRowsAssigned & " out of " & nAllRows & " records"
    

    The function returns the number of records being assigned each time. I use this count to report out to the user the number of areas being assigned out of the total number of service areas.

    You can see the output in the Message window under the Explorer window in the image below.

    image
    The benefits of moving this to a compiled MapBasic add-in are:
    • Simplification of code
    • Reuse of code via functions and procedures
    • Support of If statements

    Additional benefits that I haven't yet taken advantage of in my small sample add-in:

    • Error Handling
    • Dynamic table and column names
    • Looping over the existing drivetimes instead of hard-coding the drivetime intervals
    • Handling Enclaved Service Areas

    You can see below that we still experience some enclaved service areas. The highlighted polygons are all surrounded by service areas served by a different service engineer. In an upcoming article, I will try to find a solution to assign these to the surrounding service engineer.

    image
    How do you prefer to create your automations? Using MapBasic scripts in MapInfo Pro, using Python scripts in MapInfo Pro, or using a MapBasic or Python add-in that you load and run from MapInfo Pro?
    Happy #MapInfoMonday! 


    ------------------------------
    Peter Horsbøll Møller
    Principal Presales Consultant | Distinguished Engineer
    Precisely | Trust in Data
    ------------------------------