实现折线测距功能

来源:互联网 发布:html5 js 扫描条形码 编辑:程序博客网 时间:2024/05/17 03:45

 

本文转载自hi.baidu.com/redpanda/blog/category/Mapx

实现折线测距功能

     如果只是单独的两点测距的功能,只需要调用MapX的Distance函数就可以了。但是如果要实现折线测距的功能就不是这么简单的了。
    折线测距:有两个距离:当前距离和总距离。总距离是从起点到鼠标目前的位置之间的距离。当前距离是鼠标目前的位置到鼠标上一次点击的位置之间的距离,效果图如下:

图 1 折线测距图

 

       为了实现这样的功能,我使用了橡皮糖工具(OnPolyToolUsed)和鼠标移动事件(OnMouseMove)。但是我还是觉得这种实现方法有些麻烦,曾经考虑过用其他方法。以下是我的实现步骤,编码的环境是Delphi 2006+MapX.


大致的思路是:
      在PolyToolUsed函数中,使用全局变量Ruler_flag记录当前的状态,是miPolyToolBegin(开始状态) ,miPolyToolInProgress(使用中的状态,已经点击了第二次),还是miPolyToolEnd(工具结束,即双击)。
     在MouseMove中判断Ruler_flag的值,如果是miPolyToolBegin,miPolyToolInProgress,就给当前距离currDis和总距离totalDis赋值,如果是miPolyToolEnd,就把当前距离置为0,总距离保持不变,并把当前程序的焦点集中在测距显示框上。


思路很简单,下面是具体实现的代码。
1、 初始化TMap对象
这里只列出和测距功能有关的初始化语句。
。。。。。。。
m_map.OnPolyToolUsed := PolyToolUsed;
m_map.OnMouseMove := MyMouseMove;
。。。。。。
2、 创建自定义的测距工具
可以创建一个专门的测距工具。相关代码如下:
。。。
const     miMyRulerTool = 502;
。。。
//在初始化TMap对象的地方,创建测距工具:
m_map.CreateCustomTool(miMyRulerTool,miToolTypePoly,miCrossCursor);
…...

3、 实现相关函数 
(1) 定义全局变量
Var 
//测距功能中的两点坐标
originalPt:MapXLib_TLB.Point;
currentPt:MapXLib_TLB.Point;

Ruler_flag: Integer;   //记录测距过程中状态变化
R_curr_dis :double; //当前距离
R_total_dis:double; //总距离
R_temp_dis:double; //为了计算总距离中的中间值
isMouseDown :boolean; //标记鼠标是否点下
(2) 实现PolyToolUsed函数
procedure TFrame_MapView.PolyToolUsed(ASender: TObject; ToolNum: Smallint; Flags: Integer;
                                      const Points: IDispatch; bShift: WordBool; bCtrl: WordBool;
                                       var EnableDefault: WordBool);
begin
if ToolNum = miMyRulerTool then
begin
//使用全局变量记录在橡皮糖工具中的状态,以便传给mouseMove函数判断
    Ruler_flag := Flags;
    case Flags of
      miPolyToolBegin , miPolyToolInProgress:
        begin
          isMouseDown := true;
          R_temp_dis := R_total_dis;
        end;
    end;
end;
end;

(3) 实现MyMouseMove函数

procedure TFrame_MapView.DoMouseMove(Sender: TObject; Shift: TShiftState; X: Integer; Y: Integer);
var
mapX,mapY:double;
screenX,screenY:Single;
//自定义显示测距结果的Form,界面效果如上图所示
formInfo :TForm_showInfo;
begin
screenX := X/1.0;
screenY := Y/1.0;
m_Map.ConvertCoord(screenX,screenY,mapX,mapY,miScreenToMap);
formInfo := TForm_showInfo.Create(nil);
//测距功能实现
if m_map.CurrentTool = miMyRulerTool then
begin
     case Ruler_flag of
      miPolyToolBegin,miPolyToolInProgress:
        begin
          showDis(mapX,mapY);
        end;
      miPolyToolEnd:
        begin
          R_curr_dis := 0.0;
          R_total_dis := 0.0;
          if formInfo.Showing then
            formInfo.SetFocus;
        end;
     end;
end
formInfo.Free;
end;

相关函数showDis的代码为:


    ///@desc: 根据当前鼠标位置显示测距面板
    
///@para: _mapX,mapY:鼠标坐标
    
///@return:
    
///@authorcsdancyz@163.com
    ///@time : 2010-01-01
Procedure showDis(_mapX:double;_mapY:Double);
var
tmpPoint,pt1:TPoint;
begin
tmpPoint.X := Self.Left;
tmpPoint.Y := self.Height;
//将子坐标转换为屏幕坐标
pt1:=ClientToScreen(tmpPoint);
//鼠标点下
if isMouseDown then
begin
    originalPt.Set_(_mapX,_mapY);
    R_curr_dis := 0.0;
    isMouseDown := not isMouseDown;
end
else
//鼠标移动
begin
    currentPt.Set_(_mapX,_mapY);
    R_curr_dis := p2pDistance(m_map,originalPt,currentPt);
end;
    R_total_dis := R_temp_dis+R_curr_dis;
    formInfo.currDis := R_curr_dis;
    formInfo.totalDis := R_total_dis;
    //让测距框显示在左下角
formInfo.Left := pt1.X;
    formInfo.Top := pt1.Y-formInfo.Height;
    formInfo.Show;
end;

    ///@desc: 计算两点之间的距离
    
///@para: mMap:TMap对象
    ///       fromPt: 测距的起点
    ///       toPt: 测距的终点
    
///@return:返回两点之间的距离
    
///@authorcsdancyz@163.com
    ///@time : 2010-01-01
function p2pDistance(mMap:TMap;fromPt: MapXLib_TLB.Point; toPt: apXLib_TLB.Point):Double;
begin
assert((frompt <> nil) or (toPt <> nil));
result := mMap.Distance(fromPt.X,fromPt.Y,toPt.X,toPt.Y);
end;

关于TForm_showInfo的说明:
有两个属性:
currDis: Double类型;读写属性,可直接赋值。表示当前距离。
totalDis:Double类型;读写属性,可直接复制。 表示总距离。

关于这个Form的实现就比较简单了,就不再啰嗦了。呵呵。

我还是觉得这种实现方法不够简洁,主要是中间变量太多了,并且是全局的,如果有时间和精力要把改进一下。 我之前看过一个实例 就是在mapX之上又封装了一层,添加了很多自定义的工具。

        也许细心的人会发现,对于MapInfo中的一些功能,比如折线测距,区域测面积,显示属性信息(i)等,只要是另外弹出对话框的(图层控制的除外)工具,MapX都没有提供。这些工具的功能只有让程序员自己来实现,但是我相信有这样需求的程序员不至一个两个,需求量还是挺大的,那么我们完全可以把这些工具的实现做成一个通用的部分,只要给一个接口。就像miPanTool工具一样,只要把TMap.currentTool=miMyRulerTool就可以调用折线测距功能了。这是个想法也是我下一步想做的事情。嘿嘿。