PDA

View Full Version : Delphi class



terrastudios
10-30-2005, 04:29 AM
All,

I have compiled together a class for using MapPoint (currently 2004) with Delphi. The class creates MapPoint as an ole object, and will display it on any twincontrol (e.g. a panel). I have compiled some of the routines from code found on this forum - credit to the original authors. If anyone feels like extending/improving this class, then please feel free - all I ask is that you can share your results with the rest of the members on this forum so that others can benefit from it too.

Many thanks in advance and I hope its of use to someone.

Regards

Matt Brocklehurst,
TerraStudios Limited.
----------



unit mappoint;

{

TTSMapPoint Class

Author: Matt Brocklehurst

Ties various mappoint (ole) delphi routines together, uses code found at www.MP2KMag.com
Credit to the various authors of some of the routines I use.


}

interface

uses Controls, extCtrls, Classes, Variants, OleCtnrs, OleServer, MapPoint_TLB;

type
TTSMapPoint = class
constructor Create(AOwner: TComponent;ParentControl:TWinControl);
destructor Destroy;
private
OleContainer1: TOleContainer;
locNorthPole:Location;
locSantaCruz:Location; //Center of western hemisphere
Pi, dblHalfEarth, dblQuarterEarth:double;
function Arccos(x:double):double;
function GetStreetName2(Longitude,Latitude:double; out StreetName: string):boolean;
public
FMap: _Map; // the active map
function GetLat(locx:Location):double;
function GetLon(locx:Location):double;
function GetStreetName(xlongitude,xlatitude:double):string;
procedure GetLatLonPostcode(Postcode:string; out Longitude,Latitude: double);
end;

implementation

constructor TTSMapPoint.Create(AOwner: TComponent;ParentControl:TWinControl);
var
vGuid: TGuid;
begin;
OleContainer1:=TOleContainer.create(aowner);
OleContainer1.Width:=ParentControl.Width;
OleContainer1.Height:=ParentControl.height;
OleContainer1.Parent:=ParentControl;
OleContainer1.CreateObject('MapPoint.Map.EU.11',Fa lse);
OleContainer1.DoVerb(1);
OleContainer1.OleObjectInterface.GetUserClassID(vG uid);
FMap:= IDispatch(OleContainer1.OleObject) as map;
locNorthPole:=fmap.GetLocation(90,0,0);
locSantaCruz:=fmap.GetLocation(0,-90,0);
dblHalfEarth:=fmap.Distance(locNorthPole, fmap.GetLocation(-90, 0,0));
dblQuarterEarth:=dblHalfEarth/2;
Pi:=3.14159265358979;
end;

destructor TTSMapPoint.Destroy;
begin;
FMap:=nil;
OleContainer1.DestroyObject;
// OleContainer1.Destroy;
end;


function TTSMapPoint.Arccos(x:double):double;
var
ret:double;
begin
if x=1 then
ret:=0
else
ret:=ArcTan(-x/Sqrt(-x*x+1))+2*ArcTan(1);
result:=ret;
end;

function TTSMapPoint.GetLat(locx:Location):double;
var
ret:double;
begin
ret:=90 - 180 * fmap.Distance(locNorthPole, locX) / dblHalfEarth;
result:=ret;
end;

function TTSMapPoint.GetLon(locx:Location):double;
var
ret, l , d , lat:double;
begin
lat:=GetLat(locx);
d:= fmap.Distance(fmap.GetLocation(lat, 0, 0), locX);
l:= (Lat / 180) * Pi;
ret:= 180 * Arccos((Cos((d * 2 * Pi) / (2 * dblHalfEarth)) - Sin(l) * Sin(l)) / (Cos(l) * Cos(l))) / Pi;
If fmap.Distance&#40;locSantaCruz, locX&#41; < dblQuarterEarth Then ret&#58;= -ret;
result&#58;=ret;
end;

function TTSMapPoint.GetStreetName2&#40;Longitude,Latitude&#58;doub le; out StreetName&#58; string&#41;&#58;boolean;
var
vFindResult &#58; FindResults;
vStreetAddress &#58; StreetAddress;
vResult &#58; string;
i &#58; integer;
iOle &#58; OleVariant;
Loc&#58; Location;
GoodHit&#58; boolean;
begin
Loc&#58;=FMap.GetLocation&#40;longitude,latitude,1&#41;;
Loc.Goto_;
vFindResult&#58;=FMap.ObjectsFromPoint&#40;FMap.LocationTo X&#40;Loc&#41;,FMap.LocationToY&#40;Loc&#41;&#41; as FindResults;
GoodHit&#58;=false;
for i &#58;= 1 to vFindResult.Count do
begin
iOle &#58;= i;
vStreetAddress &#58;= &#40;vFindResult&#91;iOle&#93; as Location&#41;.StreetAddress;
if Assigned&#40;vStreetAddress&#41; then
begin
StreetName&#58;=&#40;vStreetAddress.Street&#41;;
goodhit&#58;=true;
break;
end
else
begin;
goodhit&#58;=false;
end;
end;
GetStreetName2&#58;=goodhit;
end;

function TTSMapPoint.GetStreetName&#40;xlongitude,xlatitude&#58;dou ble&#41;&#58;string;
var
longitude, latitude&#58; double;
oldlongitude,oldlatitude&#58; double;
streetname&#58; string;
flag&#58; boolean;
i&#58; integer;
begin
// for some reason longitude and latitude are back to front?
// to avoid conversion - we flip em over for the purpose of our routines
longitude&#58;=xlatitude;
latitude&#58;=xlongitude;
streetname&#58;='';
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then exit;
oldlongitude&#58;=longitude;
oldlatitude&#58;=latitude;
for i&#58;=1 to 10 do
begin;
longitude&#58;=longitude+0.001;
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then
begin;
getstreetname&#58;=streetname;
exit;
end;
end;
latitude&#58;=oldlatitude;
longitude&#58;=oldlongitude;
for i&#58;=1 to 10 do
begin;
longitude&#58;=longitude-0.001;
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then
begin;
getstreetname&#58;=streetname;
exit;
end;
end;
latitude&#58;=oldlatitude;
longitude&#58;=oldlongitude;
for i&#58;=1 to 10 do
begin;
latitude&#58;=latitude-0.001;
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then
begin;
getstreetname&#58;=streetname;
exit;
end;
end;
latitude&#58;=oldlatitude;
longitude&#58;=oldlongitude;
for i&#58;=1 to 10 do
begin;
latitude&#58;=latitude+0.001;
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then
begin;
getstreetname&#58;=streetname;
exit;
end;
end;

getstreetname&#58;='';
end;

procedure TTSMapPoint.GetLatLonPostcode&#40;Postcode&#58;string; out Longitude,Latitude&#58; double&#41;;
var
vFindResult &#58; FindResults;
vStreetAddress &#58; StreetAddress;
loc&#58; location;
iOle&#58; olevariant;
i&#58; integer;
begin;
vFindResult&#58;=FMap.FindAddressResults&#40;'','','','',p ostcode,0&#41;;
for i &#58;= 1 to vFindResult.Count do
begin
iOle &#58;= i;
loc&#58;=&#40;vFindResult&#91;iOle&#93; as Location&#41;;
if&#40;assigned&#40;loc&#41;&#41; then
begin;
latitude&#58;=getlat&#40;loc&#41;;
longitude&#58;=getlon&#40;loc&#41;;
exit;
end;
end;
end;

end.

Wilfried
11-02-2005, 11:21 AM
Hi,

I tryed your class in Delphi 7. Works as a glance, however some strange things:

If I make a panel bottom aligned, and a second panel client alignd (for MP), then my bottom alligned pannel dissapears... also resizing does not resize the map.

If I only 1 panel bottom aligned and visual the map on the form then I can make my panel visible by making the form larger at runtime, but again the map anchors does not follow the form.

OK I did only quick test. but your comments are welcome of course.

Wilfried
11-02-2005, 11:26 AM
Hi,

this is of course solution for the resize. Still other panel dissapears. Will look at it later.


OleContainer1.Align &#58;= alClient;

Wilfried
11-02-2005, 11:34 AM
Hi,

I could not stop :)

Setting the panel to Aligne=alNone, and his Anchors to top+left+bottom+right then MP will resize perfect (see also my previous mail) and the other panel stay visible :)

Wilfried
11-02-2005, 11:37 AM
Hi,

this is interesting:

Drop a MainMenu on the form ! And see what happens, automaticely without any letter of code I have the whole Mappoint menu and working.....

This can be sometime not wanted, but..

Adding menu items will merge with the Mappoint ones...

terrastudios
11-03-2005, 05:02 AM
Hi!

Yep the menu bar is strange - but I guess in some instances it could be quite a useful feature.

Thanks for pointing out the resize problem (& solution) I will make this modification to the class.

I think that the "jump to the nearest street" bit of code I wrote is adequate atm, however I have seen a much much more clever solution (more maths than I can cope with!) on here (I believe by yourself Wilfried) so I might look at implementing this in the next revision.

Is there an easy way of disabling the right click menus/other menus and implementing a custom popup menu (I am guessing by catching an OnMouseDown event, detecting that button == mbRight, and displaying a tpopupmenu). I wish for this menu to display a save as bitmap item, is there an method to save the bitmap? I know there is a kludge which allows you to copy the current map to the tclipboard and then I can save it that way, but I do not feel this is a very good solution for an end product!

Cheers again,

Matt.

Wilfried
11-03-2005, 07:32 AM
Hi,

I did not really test the methods you have provided, I was just anger to try it because I have a lot of Delhi applications using mappoint, ant this class is fine :)

For the jump to nearest street I think I have published some delphi code to use a vector. If you cannot find it then I post it again.

If you are going to expand the class I have following suggestion, because it is no nececary that a user (or even you yourself) do need all methods provided in a program. So I suggest to make a TTSCustomMappoint class where only the nececary things in to start and display mappoint. Then you can derrive components from it with the more advanced methods. For example I have a dozain applications where mappoint is only used to check the nearest street of a vehicle if it is not. Half of them do not even display a map, because position has to be sent to someone, like: "car is 50 meter NE from street name, no at zip city", or "car is in street name, no at zip city".

It's your class of course, but only a suggestion :)

For the saveToClipBoard I have no other / better idea's

terrastudios
11-03-2005, 04:33 PM
Hi Wilfried,

Thats actually a great idea - keep TSMapPoint as a parent class and derive any custom methods etc.. from this as seperate child classes - inheritence is good for something!

I hope that it proves a useful class in some of your applications, I will look up the vector code that you wrote, and add it to a descendant (I will post the descendant on here as well for all to use).

Cheers

Matt.

KeithW
11-30-2005, 02:11 PM
Hi,

I did not really test the methods you have provided, I was just anger to try it because I have a lot of Delhi applications using mappoint, ant this class is fine :)

For the jump to nearest street I think I have published some delphi code to use a vector. If you cannot find it then I post it again.

If you are going to expand the class I have following suggestion, because it is no nececary that a user (or even you yourself) do need all methods provided in a program. So I suggest to make a TTSCustomMappoint class where only the nececary things in to start and display mappoint. Then you can derrive components from it with the more advanced methods. For example I have a dozain applications where mappoint is only used to check the nearest street of a vehicle if it is not. Half of them do not even display a map, because position has to be sent to someone, like: "car is 50 meter NE from street name, no at zip city", or "car is in street name, no at zip city".

It's your class of course, but only a suggestion :)

For the saveToClipBoard I have no other / better idea's

Hi Terrastudio / Wilfred
I to just need to be able to get Street location without the MAP but am unsure on how to inherit Classes etc.
Have you extended your class to enable this yet ( Hoping ).

BTW I think theres a small bug in the GetStreetName function that fails if you are Exactly on the Street.




function TTSMapPoint.GetStreetName&#40;xlongitude,xlatitude&#58;dou ble&#41;&#58;string;
....
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then exit;
oldlongitude&#58;=longitude;
oldlatitude&#58;=latitude;


I Think it should be


function TTSMapPoint.GetStreetName&#40;xlongitude,xlatitude&#58;dou ble&#41;&#58;string;
....
flag&#58;=GetStreetName2&#40;longitude,latitude,StreetName &#41;;
if&#40;flag&#41; then
begin
getstreetname &#58;= streetname;
exit;
end;
oldlongitude&#58;=longitude;
oldlatitude&#58;=latitude;


Thanks for the Class

Wilfried
12-02-2005, 04:01 AM
Hi,

You right. In first example the return value of the function is undefined. Compiler should generate a warning also.