Point in Polygon with MapBasic

333 views
Skip to first unread message

O'Keeffe, Matthew

unread,
Jun 5, 2008, 11:02:32 AM6/5/08
to mapi...@googlegroups.com
Hello list,

I'm very new to the MapBasic programming side of things but am trying to get better aquainted with it by building a couple of menu's and toolbars.

What I am trying to do at the moment is build a button which, when clicked, will allow the user to do a boundary select of all the points within a polygon which will immediately launch a dialog box displaying the types of point (church, house, garage etc from the points table column "POI_DESCRIPTION") grouped in a multilistbox.

The user would then be able to select a radio button requesting either a count of the type of points selected from the list box, or a table listing each point with its address, coordinate etc.

Is this possible?

I've got as far as calling the boundary select tool and then browsing a full list by pressing a separate push button but I would like to be able to select points, launch dialog with one click.

here's the simplifed code I have so far:

Include "icons.def"
Include "Mapbasic.def"
Include "menu.def"

declare sub main
declare sub emplan_menu
declare sub poi_button
declare sub POI_dialog

'******************************************

sub main

call emplan_menu

end sub

'******************************************

sub emplan_menu

Create menu "Emergency Planning" as
"Display Toolbar" calling Emplan_toolbar

Alter menu bar add "Emergency Planning"

End sub

'*****************************************

sub emplan_toolbar

create buttonpad "Emergency Planning" as

Togglebutton
HelpMsg "Points of Interest Query \n Run"
Icon 1
Calling M_TOOLS_SEARCH_BOUNDARY

Pushbutton 'I dont really want this button, would rather
Icon 2 'everything could be done using the above button
Calling POI_Dialog

End Sub

'******************************************

sub POI_Dialog

Dim strDisplay(2) as string

strDisplay(1) = "Display Details"
strDisplay(2) = "Count"

Select POI_Catagory from Selection group by POI_Catagory order by POI_Catagory into Selection

browse * from selection

Dialog
Title "Points of Interest"

Control Multilistbox

Control Groupbox
Title "Display:"

Control Radiogroup
Title from variable strDisplay

Control Okbutton

Control Cancelbutton

end sub

*******************************************


I'm pretty sure that I need to be converting the selection into an array variable in order to insert it into the multilistbox but I cant get that working. I've browsed the table to make sure that the code is working.

At the moment my first pushbutton is doing nothing more than selecting the normal boundary select button.

My main aim is to eliminate the need for an 'execute' pushbutton by executing POI_Dialog as soon as the user clicks in the desired polygon.

Any help would be much appreciated.

Matt O'Keeffe

Did you know?
In any one month, Social Care is likely to have 1,669 clients receiving domiciliary care, 618 clients in permanent residential care and 231 clients in permanent nursing care.

*****************************************************
This email is for the intended recipient(s) only.

If you have received this email due to an error in addressing, transmission or for any other reason, please reply to it and let the author know. If you are not the intended recipient, you must not use, disclose, distribute, copy or print it.

This email may be monitored, read, recorded and/or kept by Portsmouth City Council. Email monitoring and blocking software may be used.
*****************************************************

Tor Libram

unread,
Jun 6, 2008, 3:55:39 AM6/6/08
to MapInfo-L
Matt,

On the 'button to trigger dialog' part: See the help file on
SearchPoint() and SearchInfo() for more details and code for a sample
toolbar. You will still need a toolbutton (rather than a push- or a
toggle-), but the process would go something like this:

-*user presses toolbutton.
-*user clicks somewhere inside a polygon on the map
-SearchPoint returns information on the map objects found at the point
clicked. (Presumably just the polygon)
-SearchInfo uses the results from SearchPoint to determine table name
and rowid of the objects found.
-Using the results from SearchInfo, populate an object variable by
selecting the appropriate polygon using rowid.
-Select points within the object variable polygon.
-Call the dialog sub
-Populate a string array from the selection of points. (See below)
-Dialog command

I apologise for not putting the above in actual code, but it's been a
while since I used SearchInfo and I can't remember the syntax off the
top of my head.
As far as populating the array variable goes, try this:

*
Dim sCateg(1) as String
Dim i as integer

Select [statement to produce list of items] into POI_Sel

ReDim sCateg(TableInfo(POI_Sel, tab_info_nrows)) ' Resizes the
array to match however many items there are in the list.

For i = 1 to TableInfo(POI_Sel, tab_info_nrows)
Fetch rec i from POI_Sel
sCateg(i) = POI_Sel.POI_Catagory
Next


Hope this helps

Dave

Matthew....@portsmouthcc.gov.uk

unread,
Jun 6, 2008, 7:18:33 AM6/6/08
to MapInfo-L
Thanks Dave

I'm not sure that you can use the searchpoint/info tool to do a
boundary select against a polygon to pick up all the points that fall
within it?

I have tried to use the array variable code towards the bottom of your
message but Mapinfo tells me that I:

"cannot use an array or user-defined type in an expression"

The error occurs when i try to populate POI_Sel with an expression.

Here's the (very messy) code that I have so far.

Many thanks for your help.




Include "icons.def"
Include "Mapbasic.def"
Include "menu.def"

declare sub main
declare sub emplan_toolbar
declare sub emplan_menu
declare sub POI_dialog

'**********************************************************************

sub main

call emplan_menu

end sub

'**********************************************************************

sub emplan_menu

Create menu "Emergency Planning" as
"Display Toolbar" calling Emplan_toolbar

Alter menu bar add "Emergency Planning"

End Sub

'*********************************************************************

sub emplan_toolbar

dim strPOI() as string

create buttonpad "Emergency Planning" as

Togglebutton
HelpMsg "Points of Interest Query \n Run"
Icon 1
Calling M_TOOLS_SEARCH_BOUNDARY
' insert into strPOI

Pushbutton
Icon 2
Calling POI_Dialog

End Sub

'*********************************************************************

sub POI_Dialog


Dim strPOI_sel() as string
Dim sCateg(1) as String
Dim i as integer
Dim strDisplay(2) as string


strDisplay(1) = "Display Details"
strDisplay(2) = "Count"

Select POI_Catagory from Selection group by POI_Catagory order by
POI_Catagory into strPOI_sel

'***(This is where the error occurs)***

ReDim sCateg(TableInfo(POI_sel, tab_info_nrows))
For i = 1 to TableInfo(POI_sel, tab_info_nrows)
Fetch rec i from POI_sel
sCateg(i) = POI_sel.POI_Catagory
Next

'browse * from selection

Dialog
Title "Points of Interest"

Control Multilistbox
Title from variable strPOI_sel

Tor Libram

unread,
Jun 9, 2008, 4:22:06 AM6/9/08
to MapInfo-L
Matt,

Try the following:

sub emplan_toolbar

create buttonpad "Emergency Planning" as
Toolbutton
HelpMsg "Points of Interest Query \n Run"
Icon 1
Calling POI_Dialog

End Sub



sub POI_Dialog

Dim fX, fY as Float
Dim i, iWin, iNum, iCount(1) as Integer
Dim oPoly as Object
Dim sCateg(1), strDisplay(2) as string

strDisplay(1) = "Display Details"
strDisplay(2) = "Count"
iWin = FrontWindow()

' If statement used as an error catcher
If WindowInfo(iWin, WIN_INFO_TYPE) <> WIN_MAPPER Then
Note "This tool only works on Map windows."
Exit Sub
End If

' Returns coordinates of the point that the user clicked on the map
window
fX = CommandInfo(CMD_INFO_X)
fY = CommandInfo(CMD_INFO_Y)
' Returns number of objects found at coordinates fX, fY
iNum = SearchPoint(iWin, fX, fY)

' Loop runs through the objects found above until it finds one from
the polygon table, upon which it returns the rowid of the object
found, allowing you to select it.
For i = 1 to iNum
If SearchInfo(i, SEARCH_INFO_TABLE) = "[polygon table]" Then
iRow = SearchInfo(i, SEARCH_INFO_ROW)
End If
Next
Select * from [polygon table] where rowid = iRow Into ObjSel
Fetch first from ObjSel
oPoly = ObjSel.obj

' So. Now you have your polygon object stored as an object variable,
which allows you to do the boundary select as follows:

Select POI_Catagory, count(*)"Quantity" from [point table] where obj
within oPoly into POI_sel group by POI_Catagory order by POI_Catagory

' Note that you can't say "Select POI_Catagory from Selection",
because there is no selection at this point.

' I suspect your error was occurring because you were saying "... into
strPOI_Sel" which you had defined as a string array variable but then
not actually filled with anything. The Into clause of a select
statement is looking for a string to name the query, not a place to
put the answers.
' The following loop goes through the POI_Sel table and assigns each
row to the array sCateg()
ReDim sCateg(TableInfo(POI_sel, tab_info_nrows))
ReDim iCount(TableInfo(POI_sel, tab_info_nrows))
For i = 1 to TableInfo(POI_sel, tab_info_nrows)
Fetch rec i from POI_sel
sCateg(i) = POI_sel.POI_Catagory
iCount(i) = POI_sel.quantity
Next
' Note that I threw iCount in there as well, so that if your user now
wants to know the number of points of the selected type, you have the
numbers ready stored in iCount. ;)

Dialog Title "Points of Interest"
Control Multilistbox Title from variable sCateg
Control Groupbox Title "Display:"
Control Radiogroup Title from variable strDisplay
Control OKButton
Control Cancelbutton
end sub

Matthew....@portsmouthcc.gov.uk

unread,
Jun 10, 2008, 12:16:26 PM6/10/08
to MapInfo-L
Thats been a great help Dave. I have managed to get that working.

Rather than having to hard code the polygon table into the code am I
able to use the x and y to create the objsel.obj variable so that I
can use the tool on any polygon that I click on?

I have also got a bit stuck about how to display the count of any
selected catagories from the multilistbox. I understand that I should
be using a ReadControlValue command to see what a user has selected
from the multilistbox. At the moment the ok button from the dialog
calls a couple of subs depending on the radios to just display a
note. obviously this isnt what I want to happen. I want the
catagories selected by the user to be displayed with their count in
the first instance (count radio) and with the details for each point
which matches the catagory selected from the points_of_interest table.

I want to do something like:

select * from points_of_interest where POI_Catagory_Text = *whatever
catagory the user selects from the multilistbox* (intDisplay(?))

any help much appreciated,

thank you




(code below)


Include "icons.def"
Include "Mapbasic.def"
Include "menu.def"

declare sub main
declare sub emplan_menu
declare sub emplan_toolbar
declare sub POI_Dialog
Declare Sub POI_Handler
Declare sub POI_Count

global intDisplay as Integer
global intPOI_Choice() as integer

'******************************************************

sub main

call emplan_menu

end sub

'***********************************************

sub emplan_menu

Create menu "Emergency Planning" as
"Display Toolbar" calling Emplan_toolbar
Alter menu bar add "Emergency Planning"

End Sub


'*****************************************************
sub emplan_toolbar

create buttonpad "Emergency Planning" as
Toolbutton
HelpMsg "Points of Interest Query \n Run"
Icon 3
Calling POI_Dialog

Toolbutton
HelpMsg "LLPG Query \n Run"
Icon 3

End Sub

'*******************************************************
sub POI_Dialog

Dim fX, fY as Float
Dim i, iWin, iNum, iRow, iCount(1) as Integer
Dim oPoly as Object
Dim sCateg(1), strDisplay(2), strPOI_Choice() as string
strDisplay(1) = "Display Details"
strDisplay(2) = "Count"
iWin = FrontWindow()

' If statement used as an error catcher

If WindowInfo(iWin, WIN_INFO_TYPE) <> WIN_MAPPER Then

Note "This tool only works on Map windows."

Exit Sub 'Stops the tool closing if an error is found

End If

'Returns coordinates of the point that the user clicked on the map
'window

fX = CommandInfo(CMD_INFO_X)
fY = CommandInfo(CMD_INFO_Y)


' Returns number of objects found at coordinates fX, fY

iNum = SearchPoint(iWin, fX, fY)

'Loop runs through the objects found above until it finds one from
'the polygon table, upon which it returns the rowid of the object
'found, allowing you to select it.

For i = 1 to iNum
If SearchInfo(i, SEARCH_INFO_TABLE) = "[polygon table]" Then
iRow = SearchInfo(i, SEARCH_INFO_ROW)

End If

Next

Select * from _60degrees_west_2k where rowid = iRow Into ObjSel'
***CAN I AVOID HARD CODING THE POLYGON TABLE HERE?***
Fetch first from ObjSel
oPoly = ObjSel.obj

'So. Now you have your polygon object stored as an object variable,
'which allows you to do the boundary select as follows:

Select POI_Catagory_Text, count(*)"Count"
from Points_of_interest where obj within oPoly
into POI_sel
group by POI_Catagory_Text
order by POI_Catagory_Text

'Note that you can't say "Select POI_Catagory from Selection",
'because there is no selection at this point.
'I suspect your error was occurring because you were saying "... into
'strPOI_Sel" which you had defined as a string array variable but
then
'not actually filled with anything. The Into clause of a select
'statement is looking for a string to name the query, not a place to
'put the answers.

'The following loop goes through the POI_Sel table and assigns each
'row to the array sCateg()

ReDim sCateg(TableInfo(POI_sel, tab_info_nrows))
ReDim iCount(TableInfo(POI_sel, tab_info_nrows))
For i = 1 to TableInfo(POI_sel, tab_info_nrows)
Fetch rec i from POI_sel
sCateg(i) = POI_sel.POI_Catagory_Text
iCount(i) = POI_sel.count
Next

'Note that I threw iCount in there as well, so that if your user now
'wants to know the number of points of the selected type, you have
the
'numbers ready stored in iCount. ;)

Dialog

Title "Points of Interest"
Width 200
Control Multilistbox
Title from variable sCateg
Width 180
Height 100

Control Groupbox Title "Display:"

Control Radiogroup Title from variable strDisplay
into intDisplay

Control OKButton

Control Cancelbutton

if

CommandInfo (CMD_INFO_DLG_OK) and intDisplay = 1 then

call POI_Handler

end if

if

CommandInfo (CMD_INFO_DLG_OK) and intDisplay = 2 then

call POI_Count

end if

end sub

'*******************************************************************

Sub POI_Handler

Note "Lists details of the catagory selected in multilistbox from the
POI table"

End Sub

'******************************************************************

Sub POI_Count

Note "Lists the name and count of any catagory selected in
multilistbox"

end sub

Tor Libram

unread,
Jun 11, 2008, 6:15:33 AM6/11/08
to MapInfo-L
> Rather than having to hard code the polygon table into the code am I
> able to use the x and y to create the objsel.obj variable so that I
> can use the tool on any polygon that I click on?

++ I had assumed you only had the one layer of boundary polygons. If
you have multiple overlapping polygons in the same table (ie the same
map layer) then life gets a bit complex! If you have, say, electoral
wards in one layer, parishes in another layer, counties in a third and
so on then that's fairly straightforward: You would need to add a line
or two in the Searchinfo loop to store the table name of each object
found in a string array; then use the string array as the source for a
popup in a new dialog in order to allow the user to pick which table
they wanted to use for the boundary select.

sub POI_Dialog
Dim fX, fY as Float
Dim i, iWin, iNum, iRow(1), iCount(1), iTabSel as
Integer '*** Note iRow changed to array variable
Dim oPoly as Object
Dim sCateg(1), strDisplay(2), strPOI_Choice(), sTabNam(1) as
string

strDisplay(1) = "Display Details"
strDisplay(2) = "Count"
iWin = FrontWindow()

If WindowInfo(iWin, WIN_INFO_TYPE) <> WIN_MAPPER Then
Note "This tool only works on Map windows."
Exit Sub
End If

fX = CommandInfo(CMD_INFO_X)
fY = CommandInfo(CMD_INFO_Y)

iNum = SearchPoint(iWin, fX, fY)
ReDim sTabNam(iNum)
ReDim iRow(iNum)

For i = 1 to iNum
sTabNam(i) = SearchInfo(i, SEARCH_INFO_TABLE)
iRow(i) = SearchInfo(i, SEARCH_INFO_ROW)
Next

Dialog Title "Select boundary table"
Control PopupMenu Title from variable sTabNam Into iTabSel
Control OKButton

Select * from sTabNam(iTabSel) where rowid = iRow(iTabSel) Into ObjSel
Fetch first from ObjSel
oPoly = ObjSel.obj

'And as before from here on in.

> I have also got a bit stuck about how to display the count of any
> selected catagories from the multilistbox.  I understand that I should
> be using a ReadControlValue command to see what a user has selected
> from the multilistbox.  At the moment the ok button from the dialog
> calls a couple of subs depending on the radios to just display a
> note.  obviously this isnt what I want to happen.  I want the
> catagories selected by the user to be displayed with their count in
> the first instance (count radio) and with the details for each point
> which matches the catagory selected from the points_of_interest table.
>

++ Hmm, need more detail here. Also, if I spend much more time on
this, I may have to write up all the paperwork and turn it into a
proper project with jobcodes and everything!


Dave McElligott
Mott MacDonald Ltd

Driver, Greg 9434

unread,
Jun 11, 2008, 6:36:49 AM6/11/08
to mapi...@googlegroups.com
It might be easier to have the user select a polygon before the tool is run. You can easily pick-up the table name of the polygon that the user has selected using SelectionInfo(SEL_INFO_TABLENAME) and this could be used in any SQL Select statements that you need to run. As you already have the object that the user has selected, you just need to do oPoly = Selection.obj, rather than having to do the SearchPoint() part of the code as well.

Just a thought.

Greg Driver

System Administrator
Applications Support
ICT
Surrey Police
NOT PROTECTIVELY MARKED

*Internet communications are not secure and therefore Surrey Police does not accept legal responsibility for the contents of this message. This email and any attachments may be confidential. They may contain privileged information and are intended for the named addressee (s) only. They must not be distributed without our consent. If you are not the intended recipient, please notify us immediately and delete the message and any attachments from your computer, do not disclose, distribute, or retain this email or any part of it. Unless expressly stated, opinions in this email are those of the individual sender, and not of Surrey Police. We believe but do not warrant that this e-mail and any attachments are virus free. You must therefore take full responsibility for virus checking. Surrey Police reserves the right to monitor all email communications through their networks.*

Matthew....@portsmouthcc.gov.uk

unread,
Jun 13, 2008, 4:56:20 AM6/13/08
to MapInfo-L
Thanks all for your help.

Forward me any costcode and I'll take them to the powers that be, I
wouldn't hold your breath though! ;-)

Matt
Reply all
Reply to author
Forward
0 new messages