My company currently uses MapInfo Professional to map our client's addresses into territories. I have been asked to figure out a mechanism to do the same thing but real-time via a web service call. Is there any way to store the data from teh Mapnfo TAB files in a database and query it with lat/long in order to determine which "object" the lat/long belongs in? I've seen that there are multiple data formats for geospatial information, so if it isn't possible with the MapInfo TAB files, would it be possible with other formats? Am I coming at this issue in the correct way or is there alternative mechanisms for solving the problem?
[GIS] Query MapInfo TAB Files
geocodingmapinfo
Related Solutions
MapInfo stores the projection information inside the MAP file. If the coordinates are correct, but you have wrong projection stored, it can only be corrected one way: Export the table to MIF format, edit the coordsys inside the MIF and then import the file again. After that MapInfo will take care of reprojecting the data on-the-fly if you want to show it together with datasets with other projections.
I would run they each of the individual segments and for each find the matching node in the complex polyline for the start as well as the end node of the section.
Now you can check if the end node number is larger than the start node number. If so the line direction of the section is the same as the direction of the polyline.
If not, the direction is reverted.
Here's some code that can help you find the node number within a polyline/polygon with only one segment:
'******************************
Function OBJFindNode( ByVal oObj As Object 'The object (polyline or polygon) to search in, only the first segment of the object will be searched
, ByVal oNode As Object 'Node position to look for
, ByVal fTolerance As Float 'Search tolerance, in meters, distance is measured using Cartesian calculation
) As Integer 'Returns the first matching node number, or 0 if no found
Dim nSegm, nNode As Integer
OnError GoTo ErrorOccured
OBJFindNode = 0
If OBJFindSegmentAndNode(oObj, oNode, fTolerance, nSegm, nNode) Then
If nSegm = 1 Then
OBJFindNode = nNode
End If
End If
Exit Function
'-------------------------
ErrorOccured:
Note Err() + " " + Error$() + ": OBJFindNode"
End Function
'************************************
Function OBJFindSegmentAndNode( ByVal oObj As Object 'The object (polyline or polygon) to search in
, ByVal oNode As Object 'Node position to look for
, ByVal fTolerance As Float 'Search tolerance, in meters, distance is measured using Cartesian calculation
, nSegmentFound As Integer 'The Segment number where the node was found
, nNodeFound As Integer 'The matching node number
) As Logical 'Returns TRUE if a matching node was found, otherwise FALSE
Dim nSegm, nNode As Integer,
fNodeX, fNodeY, fX, fY, fDistance As Float
OnError GoTo ErrorOccured
OBJFindSegmentAndNode = FALSE
If NOT ObjectInfo(oObj, OBJ_INFO_TYPE) IN (OBJ_TYPE_PLINE, OBJ_TYPE_REGION) Then
Exit Function
End If
fNodeX = CentroidX(oNode)
fNodeY = CentroidY(oNode)
For nSegm = 1 To ObjectInfo(oObj, OBJ_INFO_NPOLYGONS)
For nNode = 1 To ObjectInfo(oObj, OBJ_INFO_NPOLYGONS + nSegm)
fX = ObjectNodeX(oObj, nSegm, nNode)
fY = ObjectNodeY(oObj, nSegm, nNode)
fDistance = CartesianDistance(fNodeX, fNodeY, fX, fY, "m")
If fDistance <= fTolerance Then
nSegmentFound = nSegm
nNodeFound = nNode
OBJFindSegmentAndNode = TRUE
Exit Function
End If
Next 'nNode
Next 'nSegm
Exit Function
'-------------------------
ErrorOccured:
Note Err() + " " + Error$() + " OBJFindSegmentAndNode"
End Function
'******************************
Function OBJFindNodeBinary( ByVal oObj As Object 'The object (polyline or polygon) to search in, only the first segment of the object will be searched
, ByVal oNode As Object 'Node position to look for
, ByVal fTolerance As Float 'Search tolerance, in meters, distance is measured using Cartesian calculation
, ByVal nOffset As Integer 'Offset of 1st node in polyline based on original
) As Integer 'Returns the first matching node number, or 0 if no found
Dim objLow, objHigh As Object,
nPnts, nNode, nMid As Integer
OnError GoTo ErrorOccured
OBJFindNodeBinary = 0
nPnts = ObjectInfo(oObj, OBJ_INFO_NPNTS)
If nPnts < 100 Then
nNode = OBJFindNode( oObj, oNode, fTolerance)
If nNode > 0 Then
OBJFindNodeBinary = (nNode + nOffset)
End If
Exit Function
End If
'Determine the middle point
nMid = nPnts \ 2 + nPnts Mod 2
'Start with the lower half
objLow = ExtractNodes( oObj, 1, 1, nMid, FALSE)
If oNode Within CartesianBuffer(MBR(objLow), 25, fTolerance, "m") Then
nNode = OBJFindNodeBinary(objLow, oNode, fTolerance, nOffset)
OBJFindNodeBinary = nNode
Else
' Forget this branch
nNode = 0
End If
' If we couldn't find it in the lower, then check the upper half
If nNode = 0 Then
objHigh = ExtractNodes(oObj, 1, nMid + 1, nPnts, FALSE )
If oNode Within CartesianBuffer(MBR(objHigh), 25, fTolerance, "m") Then
nNode = OBJFindNodeBinary( objHigh, oNode, fTolerance, nOffset + nMid)
Else
' Forget this branch
nNode = 0
End If
End If
OBJFindNodeBinary = nNode
Exit Function
'-------------------------
ErrorOccured:
Print Err() + " " + Error$() + " OBJFindNodeBinary: nNode: " + nNode
End Function
The fundemental structure of the Binary search function has been made by Bill Thoen who shared it on MapInfo-L more than a year ago.
This is how to use the code above:
Dim oPolyline, oPoint, oLine As Object,
nOrder, nTolerance, nNode1, nNode2, nRowID As Integer
nTolerance = 0.2 'meters
Set CoordSys Table TABLE_WITH_LINES
Fetch First From TABLE_WITH_POLYLINES
oPolyline = TABLE_WITH_POLYLINES.OBJ
Fetch First From TABLE_WITH_LINES
Do Until EOT(TABLE_WITH_LINES)
oLine = TABLE_WITH_LINES.OBJ
nRowID = TABLE_WITH_LINES.ROWID
oPoint = CreatePoint(ObjectGeography(oLine, OBJ_GEO_LINEBEGX), ObjectGeography(oLine, OBJ_GEO_LINEBEGY))
nNode1 = OBJFindNodeBinary(oPolyline, oPoint, 0.2, 0)
oPoint = CreatePoint(ObjectGeography(oLine, OBJ_GEO_LINEENDX), ObjectGeography(oLine, OBJ_GEO_LINEENDY))
nNode2 = OBJFindNodeBinary(oPolyline, oPoint, 0.2, 0)
nOrder = 0
If nNode1 = 0 or nNode2 = 0 Then
'First of last point could not be matched to a node within the tolerance given
ElseIf nNode1 < nNode2 Then
nOrder = 1
ElseIf nNode1 > nNode2 Then
nOrder = -1
End If
Update TABLE_WITH_LINES
Set Direction = nOrder
Where ROWID = nROWID
Fetch Next From TABLE_WITH_LINES
Loop
Notice that in the sample above I'm expected you to only have one polyline. If that's not the case you need to figure out how to link the current line to the matching polyline. If the line table holds a reference ID for the polyline table, you can use this.
Best Answer
If you have >= Version 10 of Mapinfo, it is able to read and write PostGIS natively.
PostGIS is a very good, open database for spatial data. Probably your best option is to convert your tab files to a PostGIS-compatible format and/or load them in.
You can then not only expose a service to test which territory an address is in over the web (you'll need some programming language glue) but you can also use any number of clients to view the data, including Mapinfo (and Mapserver, Geoserver, etc.). In this way your Mapinfo investment is protected, but you are free to experiment with other technologies that may be cheaper or more capable. Testing which polygon a point belongs to is pretty simple with the operators ST_Contains / ST_Within.
In theory, this is a perfectly feasible project, but the implementer will need to know a fair bit about databases, sql including spatial operators, and programming.