MapInfo Pro

 View Only

MapBasic Monday: Moving the Centroid for Polygons

  • 1.  MapBasic Monday: Moving the Centroid for Polygons

    Employee
    Posted 25 days ago

    A bit more than 4 years ago, I wrote about moving centroids for polygons resulting in a good discussion at the time.

    Some were puzzled that centroids could be moved at all. Others gave good reasons for moving the centroid for polygons. 

    What we didn't cover, however, was how to do this in an automated way. Some tools were mentioned but none would take a coordinate pair and update the polygon object's centroid to match these.

    This article has come up based on a question I got from our internal data team. They want to move the centroid to a different location based on the gravity center.

    Let's dive into this now. Happy #MapInfoMonday and #MapBasicMonday too!

    Changing the Centroid through MapBasic

    Let me start by saying that you can only change the centroid for polygon objects. For the other object types, the centroid is at a well-defined location.

    You must use the Alter Object statement in MapBasic to change the centroid.

    Alter Object obj
      { Info object_info_code, new_info_value 
      | Geography object_geo_code , new_geo_value 
      | Node 
        { Add [ Position polygon_num, node_num ] ( x, y )
        | Set Position polygon_num, node_num ( x , y )
        | Remove Position polygon_num, node_num 
        } 
      }

    As you can tell from the syntax, this statement allows you to change objects in various ways. You can use the attributes from ObjectInfo() function, attributes from the ObjectGeography() function, and change, delete, and add additional nodes to the object.

    In our case, we will use the Geography clause of the statement to modify the centroid. More specifically, we will be using the ObjectGeography() attribute OBJ_GEO_CENTROID: 

    Alter Object oPolygon Geography OBJ_GEO_CENTROID, oPoint

    The statement above will assign the point object oPoint as the centroid to the polygon object oPolygon.

    But that's only part of the needed statements. Typically, objects are stored in a table. This means that we first need to get the object from the table into a variable, then change the centroid of this object variable, and finally write the object variable back to the record.

    This could look like this including the variable definitions:

    Dim oPolygon As Object
    Dim nRowID As Integer
    Dim fX, fY As Float
    
    Set Coordsys Table Selection
    
    Fetch First From Selection
    oPolygon = Selection.OBJ
    nRowID = Selection.ROWID
    fX = Selection.X
    fY = Selection.Y
    
    Alter Object oPolygon Geography OBJ_GEO_CENTROID, CreatePoint(X, Y)
    
    Update Selection Set OBJ = oPolygon 
       Where ROWID = nRowID

    Note that I specify the coordinate system to use and that I read the new location of the centroid from columns X and Y.

    Creating a Function for Changing the Centroid

    There are good reasons to create a function instead of using the rather complex structure above. One reason is that it becomes easier to use and another is that it improves performance.

    The basic element of the function is still the Alter Object statement. A function also allows us to wrap some error handling around the process.

    In my function below, you can see that I check the input object type and ensure that the new centroid point lies inside the input object.

    The function below takes two parameters: the polygon to modify and the new centroid as a point. 

    Function OBJSetCentroid( ByVal oPolygon As Object
    					, ByVal oPoint As Object
    					) As Object
    
    OnError GoTo ErrorOccured
    
    OBJSetCentroid = oPolygon
    
    	If Not ObjectInfo(oPolygon, OBJ_INFO_TYPE) = OBJ_TYPE_REGION Then
    		'**Only works for Polygon/Region objects
    		Print "New Input Object not of type Polygon/Region!"
    		Exit Function
    	ElseIf Not oPoint Within oPolygon Then
    		Print "New Centroid not within Polygon! X: " & FormatNumber$(Round(CentroidX(oPoint), 0.01)) & " Y: " & FormatNumber$(Round(CentroidY(oPoint), 0.01))
    		Exit Function
    	End If
    
    	Alter Object oPolygon Geography OBJ_GEO_CENTROID, oPoint
    
    	OBJSetCentroid = oPolygon
    
    	Exit Function
    '-------------------------
    ErrorOccured:
    	Print Err() + " " Error$() + " OBJSetCentroid"
    
    End Function

    I can also create a function that takes 3 parameters: The polygon to modify and the coordinate pair of the new centroid.

    As you can see, this function takes advantage of the first function by calling this with the polygon parameter and the CreatePoint function to create a point from the coordinate pair.

    Function OBJSetCentroidXY( ByVal oPolygon As Object
    					, ByVal fX As Float
    					, ByVal fY As Float
    					) As Object
    
    OnError GoTo ErrorOccured
    
    	OBJSetCentroidXY = OBJSetCentroid(oPolygon, CreatePoint(fX, fY))
    
    	Exit Function
    '-------------------------
    ErrorOccured:
    	Print Err() + " " + Error$() + " OBJSetCentroidXY"
    
    End Function

    Having these two functions, you can now easily update the centroid of your polygons using the Update statement:

    Set CoordSys Table Boundaries

    Update Boundaries Set OBJ = OBJSetCentroidXY(OBJ, X, Y)

    I can also call the first function directly if I prefer:

    Set CoordSys Table Boundaries

    Update Boundaries Set OBJ = OBJSetCentroid(OBJ, CreatePoint(X, Y))

    Notice how I in both cases set the projection to use with the Set CoordSys statement.

    MapBasic Common Libraries

    I have added these two functions to the OBJLib module that is part of the Common MapBasic Libraries.

    You can find the OBJLib.mb file and the other MapBasic modules on GitHub.

    I have earlier written about how to use these libraries via MapBasic projects. You can find the article here: MapBasic Monday: Introducing MapBasic Projects.

    You can also copy and paste the functions into your MapBasic module. Remember to remove any references to functions or procedures from other modules, such as the procedures called under error handling.



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