MapInfo Pro Developers User Group

Using the Circle DrawMode in MapBasic

  • 1.  Using the Circle DrawMode in MapBasic

    Posted 05-21-2019 04:59
    When you create tools in your MapBasic application, you can assign different draw modes to these. These can be used to draw a point, a single line, a polyline, a polygon/region, a rectangles, an ellipse or a circle. The draw modes are all defined in the Icons.def file:
    • define DM_CUSTOM_CIRCLE   30
    • define DM_CUSTOM_ELLIPSE  31
    • define DM_CUSTOM_RECT     32
    • define DM_CUSTOM_LINE     33
    • define DM_CUSTOM_POINT    34
    • define DM_CUSTOM_POLYGON  35
    • define DM_CUSTOM_POLYLINE 36

    In the handler assigned to your toolbutton, you can extract the coordinates or the object drawn by the user. Most of the draw modes gives you back the coordinates where the user clicked and potentially where the user released the mouse button again. The draw modes for polylines and polygons are different, they return the actual object drawn by the user.

    You can use the CommandInfo function to extract the values after the tool was used. Typically, you will use the CMD_INFO_X and CMD_INFO_Y attributes to extract the coordinates. For draw modes that return two coordinates, use CMD_INFO_X2 and CMD_INFO_Y2 to get the coordinate of the feature drawn. For polylines and polygons, use CMD_INFO_CUSTOM_OBJ to extract the feature that was drawn. These attributes are all defined in MapBasic.def:

    • Define CMD_INFO_X          1
    • Define CMD_INFO_Y          2
    • Define CMD_INFO_X2         5
    • Define CMD_INFO_Y2         6
    • Define CMD_INFO_CUSTOM_OBJ 1

    We add a toolbutton to an existing SplitButton control and set the drawmode to DM_CUSTOM_CIRCLE in this case. In the source code below, I'm using the RIBBONLib to create the TolButton:

    sTabName             = "TabMap"
    sGroupName            = "MapSelection"
    sSplitButtonName      = "MapFindSplitButton"
    sSplitButtonGroupName = "MapFindSplitButtonGroup"

    nCtrlIdx = RBNSplitButtonGroupAddControl("cmdFindUsingPoint", "Find Using Point", "", ControlType_ToolButton, sTabName, sGroupName, sSplitButtonName, sSplitButtonGroupName)
    If nCtrlIdx > 0 Then
        Call RBNControlSetToolTipIdx(nCtrlIdx, PRGIGetApplicationName(), "Find records around a point using a custom Spectrum Web Service", "")
       Call RBNControlSetCustomMBXHandlerIdx(nCtrlIdx, "MENUSearchUsingPoint")

       '**Specify the drawmode of the tool
       Call RBNControlSetDrawModeIdx(nCtrlIdx, DM_CUSTOM_CIRCLE)

       Call RBNControlSetMICursorIdx(nCtrlIdx, MI_CURSOR_FINGER_LEFT, "")
    End If

    Now when the user uses the tool, the handler MENUSearchUsingPoint will get called after the tool was used. In the handler/subprocedure, we extract the coordinates of the drawn feature. In the map window, the user sees a dotted circle being drawn as he moves the cursor to make the circle larger.

    To extract the coordinates in the subprocedure, you will use CommandInfo using the coordinate attributes, X, Y, X2, and Y2:

    Set CoordSys Earth Projection 1, 104
    fXMin = CommandInfo(CMD_INFO_X)
    fYMin = CommandInfo(CMD_INFO_Y)
    fXMax = CommandInfo(CMD_INFO_X2)
    fYMax = CommandInfo(CMD_INFO_Y2)

    It's important to notice, that the coordinates you extract are the center and a point on the circle. It's the minimum and maximum coordinates of the minimum bounding rectangle of the circle:

    Also notice that the red circle and the white rectangle in the map, are drawn for illustration purpose. If you want them drawn, you will have to drawn them yourself, That is not part of the drawmode.

    To calculate the center of the circle, you need to find the middle between the two coordinates given:

    fXCenter = (fXMin + fXMax) / 2
    fYCenter = (fYMin + fYMax) / 2

    And finally, to calculate the redius of the circle, you need to calculate the distance from the center to a point on the circle. We will use this point (MaxX, centerY) which is the point at the middle of the right side.

    I will use the Distance function to calculate the length of the radius. If you are using projected coordinate systems, I would recommend that you use the CartesianDistance function.

    fDistance = Distance(fXCenter, fYCenter, fXMax, fYCenter, "m")

    Now I have the values I need to be able to calculate the circle drawn by the user. I can do this using the Buffer()/CartesianBuffer() function or using the CreateCircle() function. In this case I'm passing the details to a service and let this deal with the calculations.

    Have you used any of the draw modes in your custom MapBasic tool?

    Peter Horsbøll Møller
    Pitney Bowes