本文我将从如何使用地图API(本文以百度为例,谷歌类似)开始,往后的扩展行的内容详见后续文章。
1.打开链接http://developer.baidu.com/map/jshome.htm
这里有很多DEMO,或者你直接百度搜索“百度地图API”,第一个就是。进入后有很多方向供你选择,由于现在开源的地图API都是JS脚本写的,所以我上面的链接就只针对JAVASCRIPT进行介绍。
即使是编程菜鸟(像我这种),也知道当你在任何一个开发环境下写代码时,都需要加入头文件,例如,你要在C++里使用cout,cin呢就必须要加入include ;与这种思维类似,开发电子地图系统也是一样的。你想啊,百度地图都是开发好的,人家能随随便便就把这东西直接给你吗?搞笑呢么。只可能给你一些接口让你去开发。呢么问题就是如何让这些接口有意义呢?比如你现在想在地图上定点一个位置,百度地图里有一个函数就是提供此功能的,setCenter(Point:String);呢么你无论把这句话加在页面的任何一个地方都不会起作用,因为页面根本就不知道这是个什么东西,这时就要加入API库的链接:
这个链接就好比给setCenter(Point:String)加了一个头文件。其实这很简单,而我这么介绍是因为我几乎就没学过什么HTML,CSS,JS,WEB啊,基本都是靠自己的理解去现学现用的,就拿JS来说我都没有任何基础,直接拿其他语言的语法去些的,遇到什么问题就去搜JS的函数定义啊,什么特殊的事件等等。所以原谅我这么罗嗦的介绍,只为给像我一样的小白说的更清楚。下面解释一下这个链接:
api:该链接为百度地图api库
v=1.4:库的版本为1.4版本,是目前最高的
以前百度API开放的时候是需要注册KEY的,现在就不需要,所以使用起来更简单了。另外提一点,在参考百度的DEMO时要注意这个版本,现在比如V=1.2和V=1.4在有些功能上有些偏差,而且有的函数在某些版本里可能有,在高级版本里已经废弃了。
2.以百度提供的DEMO为例,入门介绍
body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
#l-map{height:100%;width:78%;float:left;border-right:2px solid #bcbcbc;}
#r-result{height:100%;width:20%;float:left;}
百度地图的Hello, Worldvar map = new BMap.Map("allmap"); // 创建Map实例
var point = new BMap.Point(116.404, 39.915); // 创建点坐标
map.centerAndZoom(point,15); // 初始化地图,设置中心点坐标和地图级别。
map.enableScrollWheelZoom(); //启用滚轮放大缩小
---------------------------------------------------------------------------
将上面的页面复制下来,保存为.html文件,然后运行该静态页面将会显示一张任何功能都没有,但却和百度地图一样的页面。
若不能显示或者是出现乱码,则用以下办法解决:
1.当你保存txt文件时采用默认编码格式(ANSI),则在上述代码中将编码格式改为charset="gb2312";若还不能显示,则查看是不你的浏览器的问题,在internet工具,选项里找到“禁用脚本提示”,看是否打钩了。
2.保存txt文件时选择编码格式为utf-8,则上面的代码就能正常显示(推荐此编码,不解释)。
接着上一篇,将上一篇代码的js提取出来:
var map = new BMap.Map("allmap"); // 创建Map实例
var point = new BMap.Point(116.404, 39.915); // 创建点坐标
map.centerAndZoom(point,15); // 初始化地图,设置中心点坐标和地图级别。
map.enableScrollWheelZoom(); //启用滚轮放大缩小
这段js功能很简单,就是初始化地图并且定位。其中涉及了四个库里的函数:
1.Map(参数:HTML中的元素)
所以必须要有一个块
body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
#l-map{height:100%;width:78%;float:left;border-right:2px solid #bcbcbc;}
#r-result{height:100%;width:20%;float:left;}
2.Point(坐标|字符串)
这个函数即可用坐标初始化也可用字符串。
3.centerAndZoom(Point,Number)
这个函数是地图的最基础也是最重要的函数,是将定义好的点加载到地图上进行定位,并且指明地图放大级数。
4.enableScrollWheelZoom();
这个一看名字就知道是开启滚动条,默认参数为true。
以后修改百度的DEMO时只要在
//do something
就行了,当然了,你要是有特殊的需求还需要另外定义元素或者全局变量等等,这个后面我会跟大家分享。上面的四个函数在百度的开源库里都能找到http://developer.baidu.com/map/reference/index.phptitle=Class:E6%80%BB%E7%B1%BB/%E6%A0%B8%E5%BF%83%E7%B1%BB,有详细的介绍,我就不在这一一介绍了。但是必须说一点,也许是出于机密,百度提供的这个类库有些笼统,比如有些类里面方法的属性根本就没有提及,这个类库的参考只能让你有一些轮廓。所以,利用百度API进行二次开发有一个很庞大的工程就是筛选出你需要的功能函数,并且看很多DEMO来找出该函数的各种重载和用法。所以下一篇,我跟大家分享一下我自己总结的常用函数的属性以及方法,会很多喔(绝对实用)。
这一篇我将跟大家分享一下我自己在开发过程中总结出的一些操作地图的方法,属性,及思路,希望可以让大家少走弯路。
1.定位
一般百度的示例DEMO里开始初始化地图时用的都是map.centerAndZoom(坐标,放大级数);其中坐标可以用点代替,也可用字符串代替,而放大级数必须是整数,比如:
var p1=new BMap.Point(108.961605,34.238296);//西安坐标
map.centerAndZoom(p1,15);//或者map.centerAndZoom("西安",15);
但是必须要注意一点,这个点绝对是要用百度的API去实例化,即必须用BMap.Point(经度,纬度)去创造一个点,我在这点上吃了很多苦,有一次直接建立了一个坐标数组就在那读,死活没调通。
如果要重新定位,我建议大家不要在用centerAndZoom了,可以这样:
map.setCenter(“西安");
map.setZoom(15);
2.添加标注(Marker)
添加标注的最基本条件就是添加点坐标,示例如下:
首先必须要加载地图(所有的操作都是在这个的基础上进行的)
var map = new BMap.Map("allmap");
map.centerAndZoom(new BMap.Point(108.961605,34.238296), 14);
var marker1 = new BMap.Marker(new BMap.Point(108.961605,34.238296)); // 创建标注
map.addOverlay(marker1); // 将标注添加到地图中
若要给标注添加信息框,则继续下面的代码:
var infoWindow1 = new BMap.InfoWindow("普通标注");
//给mark添加鼠标单击事件
marker1.addEventListener("click", function(){this.openInfoWindow(infoWindow1);});
百度默认的标注是个红色气球,可以给它换图标:
var pt = new BMap.Point(116.417, 39.909);
var myIcon = new BMap.Icon("./png.gif", new BMap.Size(300,157));//自己要添加的路径
var marker2 = new BMap.Marker(pt,{icon:myIcon}); // 创建标注
map.addOverlay(marker2); // 将标注添加到地图中
最后为信息框加入点击鼠标事件:
var infoWindow2 = new BMap.InfoWindow("
哈哈,你看见我啦!我可不常出现哦!
赶快查看源代码,看看我是如何添加上来的!
");marker2.addEventListener("click", function(){this.openInfoWindow(infoWindow2);});
3.画线
下面是百度的一个小DEMO:
var map = new BMap.Map("allmap");
map.centerAndZoom("重庆",12); // 初始化地图,设置城市和地图级别。
var pointA = new BMap.Point(106.486654,29.490295); // 创建点坐标A--大渡口区
var pointB = new BMap.Point(106.581515,29.615467); // 创建点坐标B--江北区
alert(‘从大渡口区到江北区的距离是:‘+map.getDistance(pointA,pointB)+‘ 米。‘);//获取2点距离
var polyline = new BMap.Polyline([pointA,pointB], {strokeColor:"blue", strokeWeight:6, strokeOpacity:0.5}); //定义折线
map.addOverlay(polyline); //添加折线到地图上
从以上代码中可以得到两个重要的信息:
(1) map.getDistance(点1,点2);这个函数可以很好的帮助我们算两点的距离,不用自己计算,很方便。
(2) Ployline函数可以帮助我们划线,在这里不难看出它需要的第一个参数是一个点数组,所以在实际项目中可以将数据先放在数组里,然后在传数组名给它即可(注意一定要实例化,即BMap.Point());所以可以利用它来画矩形,多边形等等。。
4.地址解析
function BMap_Geo(detail_address,city)
{
var myGeo=new BMap.Geocoder();
myGeo.getPoint(detai_address,
function(point)
{
if(point)
{
map.panTo(point);
map.addOverlay(new BMap.Marker(point));
}
},city)
}
5.鼠标实时获取坐标
function GetlngAndlat(e)
{if(e.point.lng!=null)
{
document.getElementById("mouselng").innerHTML=e.point.lng;
document.getElementById("mouselat").innerHTML=e.point.lat;
}
}
这些全部都是静态页面的脚本,为了更好的实现,我选择用WINFORM与其交互。
这一篇,记录一下我调用的地图API实现的功能。下面介绍的都是一些片段的节选,不能直接复制就运行。在实现之前肯定要加载地图,先放一个webbroser控件,然后如下:
01.private void Form1_Load(object sender, EventArgs e)
02. {
03.
04. string str_url = Application.StartupPath + "\\最终合并版本(昨晚修改).html";
05. Uri url = new Uri(str_url);
06. webBrowser1.Url = url;
07. webBrowser1.ObjectForScripting = this;
08.
09. }
而为了能与JS交互,首先引入using System.Security.Permissions;,然后在namespace下必须加入两行:
01.namespaceWebBroser_Test_V1._002.{03. [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]04.05. [System.Runtime.InteropServices.ComVisibleAttribute(true)]06.07.08. public partial classForm1 : Form09. {10. publicForm1()11. {12. InitializeComponent();13. }14. private void Form1_Load(objectsender, EventArgs e)15. {16.17. string str_url = Application.StartupPath + "\\最终合并版本(昨晚修改).html";18. Uri url = newUri(str_url);19. webBrowser1.Url =url;20. webBrowser1.ObjectForScripting = this;21. //timer1.Enabled = true;
22. }23.}
有了上面的基础,就可以实现以下功能了。
1.鼠标放在屏幕上移动时,实时的显示坐标。
放入一个timer和一个StatusScrip:
01.private void timer1_Tick(objectsender, EventArgs e)02. {03. try
04. {05. string tag_lng = webBrowser1.Document.GetElementById("mouselng").InnerText;06. string tag_lat = webBrowser1.Document.GetElementById("mouselat").InnerText;07. doubledou_lng, dou_lat;08. if (double.TryParse(tag_lng, out dou_lng) && double.TryParse(tag_lat, outdou_lat))09. {10. toolstatus_CurrentLocation.Text ="当前坐标:"+ dou_lng.ToString("F5") + "," + dou_lat.ToString("F5");11. }12. }13. catch(Exception ee)14. { MessageBox.Show(ee.Message); }15.16. }
放入一个button命名及代码如下:
01.private void btnGetLocation_Click(objectsender, EventArgs e)02. {03. if (btnGetLocation.Text == "开启实时坐标")04. {05. timer1.Enabled = true;06. btnGetLocation.Text = "关闭实时坐标";07. }08. else
09. {10. btnGetLocation.Text = "开启实时坐标";11. timer1.Enabled = false;12. }13. }
JS脚本如下:
01.var map =new BMap.Map("allmap");02.var first_locate=new BMap.Point(108.953098,34.2778);03.map.centerAndZoom(first_locate,15);04.map.enableScrollWheelZoom(true);05.map.addEventListener("mousemove",GetlngAndlat);06.function GetlngAndlat(e)07.{if(e.point.lng!=null)08. {09.10. document.getElementById("mouselng").innerHTML=e.point.lng;11. document.getElementById("mouselat").innerHTML=e.point.lat;12. }13.}
2.开启测距工具(百度自己开发的)
拖一个按钮:
01.//开启测距工具按钮
02. private void btnOpenDistance_Click(objectsender, EventArgs e)03. {04. webBrowser1.Document.InvokeScript("openGetDistance");05. }
为了加载这个工具,是需要引入百度的另一个工具库:
JS如下:
01.
02.function openGetDistance()03.{04. var myDis=new BMapLib.DistanceTool(map);//map为上面已经初始化好的地图实例
05. myDis.open();06.}
//上面这个DistanceTool_min.js在百度的DEMO里有,我只是把它考到我的DEBUG下了,具体路径自己解决。
3.右击鼠标给地图上放marker,每一个marker的icon换成小汽车,并且显示坐标编号和坐标值,然后每放置一次,将数据存入数据库。
//放标注
01.private void btnPutMarker_Click(objectsender, EventArgs e)02. {03. if (radioButton1.Checked || radioButton2.Checked || radioButton3.Checked ||radioButton4.Checked)04. webBrowser1.Document.InvokeScript("PUTANDSEND");05. else
06. {07. MessageBox.Show("至少选择一项!");08. }09. }10. //得到Radiobutton的值
11. public stringsetWhichCar()12. {13. if(radioButton1.Checked)14. return "1";15. if(radioButton2.Checked)16. return "2";17. if(radioButton3.Checked)18. return "3";19. if(radioButton4.Checked)20. return "4";21. return "Erro";22. }23. //将从JS里得到的汽车数据显示到文本框内,并且存入数据库
24. public void PutIntotextBox(object markerIndex,object carNumber,object JSlng,objectJSlat)25. {26. text_index.Text =markerIndex.ToString();27. text_num.Text = (string)carNumber;28. text_lng.Text =JSlng.ToString();29. text_lat.Text =JSlat.ToString();30. string sql = "insert into 汽车轨迹数据 values (‘"+text_num.Text+"‘,‘"+text_index.Text+"‘,‘"+text_lng.Text+"‘,‘"+text_lat.Text+"‘,‘"+DateTime.Now.ToString()+"‘)";31. DBfunction.getcom(sql);32.33. }
JS脚本如下:
01.//---------------放标注,并且将JS的数据传送给WINFORM------------
02.function PUTANDSEND()03.{04. map.addEventListener("rightclick",putAndsend);05.}06.function putAndsend(e)07.{08. //放标注
09. var p1=newBMap.Point(e.point.lng,e.point.lat);10. var marker = new BMap.Marker(p1,{icon:myIcon});//将标注的图标改为小汽车
11. map.addOverlay(marker);12. marker_num++;//标注索引,这个是个全局变量
13. var whichCar=window.external.setWhichCar();14. var label=new BMap.Label(whichCar+"号车-坐标"+marker_num+":"+
15."("+e.point.lng+","+e.point.lat+")",{offset:new BMap.Size(20,-10)});16. marker.setLabel(label);17. //给WINFORM传值
18. window.external.PutIntotextBox(marker_num,whichCar,e.point.lng,e.point.lat);19.20.}//---------------放标注,并且将JS的数据传送给WINFORM------------
function PUTANDSEND()
{
map.addEventListener("rightclick",putAndsend);
}
function putAndsend(e)
{//放标注
var p1=newBMap.Point(e.point.lng,e.point.lat);var marker = new BMap.Marker(p1,{icon:myIcon});//将标注的图标改为小汽车
map.addOverlay(marker);
marker_num++;//标注索引,这个是个全局变量
var whichCar=window.external.setWhichCar();var label=new BMap.Label(whichCar+"号车-坐标"+marker_num+":"+
"("+e.point.lng+","+e.point.lat+")",{offset:new BMap.Size(20,-10)});
marker.setLabel(label);//给WINFORM传值
window.external.PutIntotextBox(marker_num,whichCar,e.point.lng,e.point.lat);
}
4.根据上面已经模拟的汽车历史坐标,可以查询具体车辆的历史轨迹(即从数据库里提取数据,画轨迹)
01.private void btnDrawOrit_Click(objectsender, EventArgs e)02. {03. string ss = "^[0-9]*$"; //正则表达式
04. string cc =text_whichCar.Text.Trim().ToString();05. bool match =Regex.IsMatch(cc, ss);06. if (Convert.ToInt32(text_whichCar.Text) > 4 || !match||text_whichCar.Text.Trim().Equals(String.Empty))07. //webBrowser1.Document.InvokeScript("PUTANDSEND");
08. {09. MessageBox.Show("您输入的不是数字,或者编号不在范围内!");10. }11. else
12. {13. string getdata_sql = "select * from 汽车轨迹数据 where 汽车编号=" +text_whichCar.Text;14. whichCarData(getdata_sql);15. }16. }
//从数据库里的取出经纬度传送给JS
01.public void whichCarData(stringlimit_sql)02. {03. OleDbDataReader DR =DBfunction.getread(limit_sql);04. ArrayList a = newArrayList();05. while(DR.Read())06. {07. a.Add(DR[2]);//经度
08. a.Add(DR[3]);//纬度
09. Rows_Num++;10. }11. if (Rows_Num == 0)12. MessageBox.Show("该车辆,无历史信息!");13. else
14. {15. for (int i = 0; i <= 2 * Rows_Num - 1; i++)16. {17. pointArr[i] =Convert.ToDouble(a[i]);18. }19.20. webBrowser1.Document.InvokeScript("DrawOrit1");21. }22. }23. //辅助方法
24. //获取计数
25. public intgetRowsNumber()26. {27. returnRows_Num;28. }29.//根据索引获取特定坐标
30. public double Getpoints(intindex)31. { return pointArr[index]; }
JS脚本如下:
//------------从后台数据库获得点集合来画轨迹(无参数版本),测试可用
01.function DrawOrit1()02.{03. var Array=[];04.var total_num=window.external.getRowsNumber();05.for(var i=0;i<=2*total_num-1;i++)06.{07. Array.push(window.external.Getpoints(i));08.}09.10.var PointArr=[];11.for(var i=0;i<=Array.length-1;i+=2)12.{//偶数索引存经度,奇数存维度
13. PointArr.push(new BMap.Point(Array[i],Array[i+1]));14.}15.var polyline = new BMap.Polyline(PointArr, {strokeColor:"blue", strokeWeight:6, strokeOpacity:0.5}); //定义折线
16. map.addOverlay(polyline);17.window.external.ClearRows_num();//重置窗体计数器
18.}
5.打开绘图工具,这个工具可以画直线,圆,矩形等等,其中我这里用的主要是画圆的方法,画好圆后,可以得到哪些车辆在这个圆内,并将其标注出来(其实就是一个预警范围)。
//开启画图工具按钮
01.private void btnDrawPicture_Click(objectsender, EventArgs e)02. {03. if(radio_Circle.Checked)04. { webBrowser1.Document.InvokeScript("drawCircle"); }05. else
06. { webBrowser1.Document.InvokeScript("drawRec"); }07. }
//搜索当前车辆位置,返回各个车辆的坐标
01.public double SearchAllCars(intindex)02. {03.04. string sql="select * from 汽车轨迹数据";05. OleDbDataReader dr=DBfunction.getread(sql);06. ArrayList allCars = newArrayList();07. while(dr.Read())08. {09. allCars.Add(dr[2]);10. allCars.Add(dr[3]);11. }12. Danger_Num =allCars.Count;13. double[] sendto_JS = new double[allCars.Count];14. allCars.CopyTo(sendto_JS);15.16. returnsendto_JS[index];17. }18.//全局变量,返回有危险的车辆个数
19. public intGetdangerNum()20. { return Danger_Num; }
JS脚本如下:
01.
02.
03.
04.//回调获得覆盖物的信息(修改后的版本,已测试可用)
05. var complete=function(e)06. {07. overlays.push(e.overlay);08. if (e.drawingMode ==BMAP_DRAWING_CIRCLE)09. {10. //随便赋值,刷新一遍数据库(此方法只为演示,实际中要另考虑算法)
11. var test= window.external.SearchAllCars(0);12.13.14. var circle_radius=e.overlay.getRadius();//半径
15. //圆心
16. var circle_point=newBMap.Point(e.overlay.getCenter().lng,e.overlay.getCenter().lat);17. //从WINFORM里取出数据
18. var dangerCars=[];19. var pointlen=window.external.GetdangerNum();20.21. for(var k=0;k<=pointlen-1;k++)22. {23. dangerCars.push(window.external.SearchAllCars(k));24. }25. var BMappoints=[];//创建百度地图接口规定的数组
26. for(var j=0;j<=dangerCars.length-1;j+=2)27. {28. BMappoints.push(new BMap.Point(dangerCars[j],dangerCars[j+1]));29. }30.31. for(var i=0;i<=BMappoints.length-1;i++)32. {33. if(map.getDistance(circle_point,BMappoints[i])<=circle_radius)34. {35. AddMarker(BMappoints[i]);//调用添加标注版本V3.0
36. }37. }38.39. }40.41. };42.//线条样式
43. var styleOptions ={44. strokeColor:"blue", //边线颜色。
45. fillColor:"blue", //填充颜色。当参数为空时,圆形将没有填充效果。
46. strokeWeight: 3, //边线的宽度,以像素为单位。
47. strokeOpacity: 1, //边线透明度,取值范围0 - 1。
48. fillOpacity: 0.3, //填充的透明度,取值范围0 - 1。
49. strokeStyle: ‘solid‘ //边线的样式,solid或dashed。
50. }51. //实例化鼠标绘制工具
52. var drawingManager = newBMapLib.DrawingManager(map, {53. isOpen: true, //是否开启绘制模式
54. enableDrawingTool: true, //是否显示工具栏
55. drawingToolOptions: {56. anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
57. offset: new BMap.Size(5, 5), //偏离值
58. scale: 0.8, //工具栏缩放比例
59. drawingTypes : [60. BMAP_DRAWING_CIRCLE,61. BMAP_DRAWING_RECTANGLE62. ]63.64. },65. circleOptions: styleOptions, //圆的样式
66. rectangleOptions: styleOptions //矩形的样式
67. });68.69.70.71. //添加鼠标绘制工具监听事件,用于获取绘制结果
72. drawingManager.addEventListener(‘overlaycomplete‘,complete);73.74. //drawingManager.enableCalculate();
75.76.77. //----------------------公用方法,用元素id获取元素的值-------------------
78. function $(id){79. returndocument.getElementById(id);80. }81.82. //------------------画矩形,让WINFORM调用---------------
83. function drawRec(){84.drawingManager.setDrawingMode(BMAP_DRAWING_RECTANGLE);}85. //------------------画圆,让WINFORM调用----------------
86. function drawCircle(){87.drawingManager.setDrawingMode(BMAP_DRAWING_CIRCLE);}88. //------------------清除所有已画图形,让WINFORM调用--------------------
89. function clearAll() {90. for(var i = 0; i < overlays.length; i++){91. map.removeOverlay(overlays[i]);92. }93. overlays.length = 0
94. }
这个功能比较复杂,必须要加入前两行的库连接才可以。因为画圆可以得到圆心和半径,所以我只需要从数据库里取出点,然后一一测量其与圆心的距离,然后和半径比较,只要小于半径则就在圆内标注。起初头让我画矩形,画矩形的DEMO如下:
01.//回调获得覆盖物信息,未使用该版本
02. var overlaycomplete =function(e){03. overlays.push(e.overlay);04. var result = "";05.06. result += e.drawingMode + ":";07.08. if (e.drawingMode ==BMAP_DRAWING_CIRCLE) {09.10. var circle_radius=e.overlay.getRadius();11. var circle_point=newBMap.Point(e.overlay.getCenter().lng,e.overlay.getCenter().lat);12. alert(map.getDistance(circle_point,tests[1]));13. for(var i=0;i<3;i++)14. {15. if(map.getDistance(circle_point,tests[i])<=circle_radius)16. {17. AddMarker(tests[i]);18. }19. }20. alert(result);21. }22. if (e.drawingMode == BMAP_DRAWING_POLYLINE || e.drawingMode == BMAP_DRAWING_POLYGON || e.drawingMode ==BMAP_DRAWING_RECTANGLE) {23. result += ‘所画的点个数:‘ + e.overlay.getPath()[1].lng;24. alert(result);25. }26.27. };
这里是修改的百度DEMO,其中有一行result += ‘ 所画的点个数:‘ + e.overlay.getPath()[1].lng;在百度原有的demo里是这样写的result += ‘ 所画的点个数:‘ + e.overlay.getPath().length;只会返回一个数据,我仔细看了下函数名,getPath(),而且还有length的属性,那么肯定是数组,而且是返回的边或者点的个数,而边一定是由点组成的,根据之前的Ployline函数可以推测,这个函数必定是一个存放多边形点的数组,那么我就试了试e.overlay.getPath()[1].lng,看能不能取到某个点的经度值,果然不出我所料,可以的,当时兴奋了好一阵子,有了这个方法,矩形的四个点就都能记录,那么就可以跟数据库里取出的点直接进行经纬度比较,也可以标注预警范围,不过还是没有用圆方便。
以上内容来自网上整理,感觉很不错 收藏了。