Thanks to Joe Moore, Chris Perry and Mark Ogilvie for their responses.
I settled on the approach sugested by Mark.
For those interested I have included the function implemented in my program
which is as follows: (Note I have an error trapping routine in the main
program in case no liniear objects are found within the upper tolerance
range)
Function calc(ByVal X as float,ByVal Y as Float,ByVal UpTol as float,ByVal
LowTol as float, ByVal RoadTab as String) as object
'This Function takes a coordinate set and a table name and returns a
point object
'that is closest (or very near to) the closest point on the nearest
polyline.
'Parameters passed are:
'X x (east) coordinate of point
'Y y (north) coordinate of point
'UpTol Maximum distance to search from X,Y to find polyline
object
'LowTol Minimum tolerance to use to find nearest object
before accepting the first object
' this is required in-case there are two or more
objects exactly the same distance
' which could occur if X,Y corresponds to the
intersection of teo lines
'RoadTab The name of the polyline table to 'snap' the point
X,Y point too.
Dim SearchArea,fndObj,LinObj as object
Dim SearchRadius,SearchUp,SearchDown as Float
dim fndline,fndnode,curline,curnode as integer
Dim d2node,CurDist,xObj,yObj as float
Dim NotFound as logical
NotFound = False
SearchUp = UpTol
SearchDown = 0
SearchRadius = SearchUp-2*(LowTol)
Do
SearchArea = converttoregion(CreateCircle(X,Y,SearchRadius))
Select * from RoadTab where object intersects SearchArea
into fnd noselect
do case tableinfo(fnd,tab_info_nrows)
case 0 'increase search radius
if SearchRadius=SearchUp then
NotFound = True
exit do
end if
SearchDown = SearchRadius
SearchRadius = (SearchUp+SearchDown)/2
Case 1 'one object found so keep going until within
tolerance exist
while loop
if abs(SearchRadius-SearchUp) <
LowTol then
Exit Do
else
searchUp = SearchRadius
SearchRadius =
(SearchUp+SearchDown)/2
end if
case else 'multiple selection so decrease search
radius
if abs(SearchRadius-SearchUp) < LowTol then
'if all are within tolerance then
exit and use first object
exit do
end if
searchUp = SearchRadius
SearchRadius = (SearchUp+SearchDown)/2
end case
Loop
If Not NotFound then
Fetch first from fnd
LinObj = Converttopline(Fnd.obj)
FndObj = IntersectNodes ( SearchArea,LinObj,INCL_CROSSINGS)
xObj = ObjectNodeX(FndObj,1,1)
yObj = ObjectNodeY(FndObj,1,1)
Create point into variable fndobj (xObj,yObj)
Calc = FndObj
End if
End Function
************************* Original question and reponses follow
***********************************
My original question was:
I have a problem that I have been trying to get my head around and I hope
that someone out there has done similar thing.
I have a series of point features (bus stops) that I would like to snap to
the nearest linear object (road centrelines) in another table.
I can identify the closest road but want to be able to determine where on
the polyline is the closest point to the bus stop so that I can shift the
bus stop object to lie exactly on the road centreline (not just snap to the
nearest node).
I hope this makes sense!
Any ideas??
----------------------------------------------------------------------------
---------------------
In reponse:
Joe Moore Wrote:
Hi Martin,
Funny you should ask, I actually wrote this in MapBasic. Unfortunatly, the
code is archived and it is difficult for me to get at. If you need the
actual code let know and I will get it. Here's the gist of how to do it...
Given points x1,y1,x2,y2 which make your closest street
x3,y3 which is the off-street point
deltaY = y2-y1
deltaX = X2-X1
xAnswer = deltaX * deltaY (y3 - y1) + (deltaX * deltaX) * x3 + (deltaY *
deltaY) * x1
xAnswer = xAnswer / (deltaY * deltaY) + (deltaX * deltaX)
yAnswer = ((deltaY / deltaX) * xAnswer) + y1 - ((deltaY / deltaX) * x1)
Simple, yes! The concept is that you know the slope of the closest line.
You know the place that the point is closest to the line is at a line
perpendicular to the line. Just find the perpendicular line that goes
through your bus stop.
WARNINGS!!!!
You need to do special cases if deltaX or deltaY are zero (horizontal or
vertical lines) these cases are easy though, since you know that every
point on a horizontal line has the same X.
Watch out for cases where it is impossible to draw a perpendicular line
through the closest street and the point.
There will be rounding errors, but they should be minimal.
Here's the funny part... I wrote this to put school bus stops on a center
line :-)
Good luck, and I'll be happy to get that code for you if you need it.
Joe Moore
----------------------------------------------------------------------------
---------------------
Chris Perry Wrote:
Martin,
I'm sure there is a more sophisticated answer, but if you use the
all2pts to
convert the polylines to nodes, then use SQL to select the points
within a
buffer of the original bus stop. The list of points selected will be
in
order closest - farthest.
Hope this helps
Chris Perry
Manager Mapping Systems
Parks Victoria
Melbourne Australia
Ph: 613 9816 6800
Fax: 613 9816 7222
[EMAIL PROTECTED]
----------------------------------------------------------------------------
---------------------
Mark Ogilvie wrote:
I have done something very like this. Although I don't have the
MapBasic
code here right now (and you would probably have to heavily adapt it
for
your particular situation anyway), here's the logic I used. By the
way, I
wrote this programme for another upper North Island District
Council. I work
for Compudigm (a NZ GIS consulting company based in Wellington), and
we did
it under contract to the council. I guess if you wanted to you may
be able
to arrange with either the council or maybe Compudigm to get the
code.
1: Draw/construct a small (1m?) circle around the bus stop. If the
circle
doesn't intersect the road at more than one point draw a bigger
circle. Keep
drawing bigger circles (up to a maximum, say 50m?) until you find a
circle
that intersects the road at two or more points.
2: Take the two intersection points and construct a line between
them. This
line is either parallel or very nearly parallel to the road.
3: Construct the perpendicular bisector to this line. This line will
cut the
road at a point *very* nearly the closest point to the bus stop. To
retrieve
that point you will probably need to turn the perp_bisector into a
really
long line (e.g. 50km) and close it off in a large triangle-shaped
region, so
you can use IntersectNodes to determine the intersection point.
4: You now have a point on the road, either the nearest point or
very close
to the nearest point to the bus stop. If you want to shift this
point to the
nearest node, that's reasonably straight forward, but I can't
remember
exactly how I did it now.
As usual, a good part of the work (half?) was in building the
semi-intelligent user interface, tuned to the client's work process,
around
the core engine which did all the work.
Cheers
Mark Ogilvie
Thanks again to all that helped.
===================================
Martin Roundill
GIS Manager
Waitakere City Council
Private Bag 93109
Henderson
Waitakere City
New Zealand
Ph +64 9 836 8000 ext 8344
Fax +64 9 836 8001
email [EMAIL PROTECTED]
===================================
----------------------------------------------------------------------
To unsubscribe from this list, send e-mail to [EMAIL PROTECTED] and put
"unsubscribe MAPINFO-L" in the message body, or contact [EMAIL PROTECTED]