ArcGIS Engine二次开发常用接口及其使用方法(一)
文章目录
- 1.IFeatureLayer接口
- (1)修改矢量图层的名字
- (2)控制矢量图层可见的比例尺范围
- (3)控制矢量图层是否显示
- 2.IFeatureClass接口
- (1)查找某字段的索引值
- (2)获得某个要素中的某个属性值
- (3)添加字段
- (4)删除字段
- 3.ICommand接口
- (1)添加矢量数据
- (2)全景视图
- 4.ITool接口
- 地图放大(缩小)
- 4.接口与控件的适配
- 5.用new初始化接口的两种情况
- 6.读取接口的属性
- 7.不用new的接口实例化
- 8.IMap接口
- 9.鹰眼
- (1)复制axMapControl1的地图到axMapControl2中
- (2)设置矩形框
- (3)设置地图漫游
方法:输入接口返回void——>一般不会直接输入接口,会进去找该接口有没有可用的
属性。返回到方法的格式:mm.方法名称(qq)
判断方法是读取的还是写入的,最好依据方法的名称和说明进行判断。
写入型方法:
1.如果接口里面有适用且可写的属性,直接调用属性并返回到方法。
2.如果接口里面没有适用且可写的属性,但是实现该接口的类又可以去实现另外一个接
口,而恰巧另外那个接口就有适用且可写的属性,那么在调用那个新的接口时就需要
new
读取型方法:
一.带返回值的方法:分两类:
(1)要读取的是接口类型时,继续
(2)要读取的不是接口类型时,又细分两类:
1):返回的不是接口类型,直接就调用例如int index =friend.Findfield("place")
2):返回的是接口类型,先直接调用例如IFeature aa = friend.GetFeature(0),然后继续调用返回回来的接口IFeature里面的属性去完成某个需求。
二.不带返回值的方法:分两类:
(1)如果该方法要读取的接口名称为"IX",则回到刚才去找有没有叫X且可读属性,
如果有,则该属性就可以返回接口IX
(2)
属性:判断属性是写入的还是读取的,根据要实现的功能来判断而不是根据帮助文件
一.写入类的属性,就直接调用;
二.读取类的属性,又分:
(1)读取接口的属性:
1.如果接口刚刚被初始化例如ITool ident = new + Class (),则属性在左,接口在右,并且不用加上接口前缀例如axMapControl1.CurrentTool = ident
2.如果要读取的接口没有被初始化,那么则属性在右,接口在左,并且要加上接口前缀例如IFields qq = friend.Fields;
(2)读取除接口之外比如字符串、数字等的属性:通常还需要输入如数字等,格式为:"读取类型 aa = qq.属性(输入类型)"
格式要求:可读属性、读取类方法中读取的不是接口类型的方法在右侧,其他均在左侧
1.IFeatureLayer接口
IFeatureLayer接口作用于矢量图层的布局视图和内容列表,作用是对属性表进行增删改查等操作。
IFeatureLayer mylyr = axMapControl1.get_Layer(0) as IFeatureLayer;
现在添加3个ArcGIS控件
(1)修改矢量图层的名字
属性:Name属性
属性作用:写入矢量图层的名字
注意事项:该属性作用于内容列表
IFeatureLayer mylyr = axMapControl1.get_Layer(0) as IFeatureLayer;mylyr.Name = "土地利用类型";axTOCControl1.Update();//因为Name属性是修改名字,所以是作用于内容列表,即控件axTOCControl1
运行前的图层名字
运行后,图层名字发生改变
(2)控制矢量图层可见的比例尺范围
属性:MaximumScale MinimumScale属性
属性作用:写入矢量图层可见的最大or最小比例尺
注意事项:比例尺的表达式是“1:x”,在这里输入比例尺时只需要输入x即可
IFeatureLayer mylyr = axMapControl1.get_Layer(0) as IFeatureLayer;
mylyr.MaximumScale = 20000;//最大比例尺:1:20000
mylyr.MinimumScale = 300000;//最小比例尺:1:300000
axMapControl1.Refresh();
//MaximumScale MinimumScale属性是是作用于图层显示区域,即控件axMapControl1
(3)控制矢量图层是否显示
属性:Visible属性
属性作用:写入矢量图层的显示状态,是显示还是不显示
注意事项:要写入bool类型
IFeatureLayer mylyr = axMapControl1.get_Layer(0) as IFeatureLayer;mylyr.Visible = false; //Visible的返回值是bool类型//如果为false,则其作用是让图层不显示;如果为true,则其作用是让图层显示出来。axMapControl1.Refresh();
运行前,图层处于显示的状态
运行后,图层不显示,并且在内容列表中也取消了勾选
我们也可以直接在内容列表中通过勾选来控制矢量图层的显示状态。
2.IFeatureClass接口
IFeatureClass接口作用于矢量数据的属性表
IFeatureLayer mylyr = axMapControl1.get_Layer(0) as IFeatureLayer;
IFeatureClass friend = mylyr.FeatureClass;
(1)查找某字段的索引值
读取型方法返回的不是接口类型,直接就调用例如int index =friend.Findfield("place")
方法:FindField方法
方法类型:读取型的方法,读取字段名称,返回索引值
使用思路:直接调用
int index = friend.FindField("PARCEL_ID");
MessageBox.Show(index.ToString());
(2)获得某个要素中的某个属性值
返回的是接口类型,先直接调用例如IFeature aa = friend.GetFeature(0),然后继续调用返回回来的接口IFeature里面的属性去完成某个需求。
方法:Getfeature方法
方法类型:读取类的方法,并且读取的是FID,返回的是接口IFeature
使用思路:先调用Getfeature方法获得要素,然后调用返回来的接口IFeature里面的属性Value。
读取除接口之外比如字符串、数字等的属性:通常还需要输入如数字等,格式为:"读取类型 aa = qq.属性(输入类型)"
属性:Value属性
属性作用:读取某一要素在某一字段下的属性值
注意事项:需要输入字段的索引值才能读取
IFeature aa = friend.GetFeature(0);//先获得要素
int index = friend.FindField("PARCEL_ID");//再获得某个属性值的位置
string nm = Convert.ToString(aa.get_Value(index));//最后通过位置获得属性值
MessageBox.Show(nm);
(3)添加字段
如果接口里面没有适用且可写的属性,但是实现该接口的类又可以去实现另外一个接口,而恰巧另外那个接口就有适用且可写的属性,那么在调用那个新的接口时就需要new
方法:AddField方法
方法类型:写入型的方法,写入IField但是IField里面没有可用的属性
使用思路:接口IFieldEdit里面有可用的属性,而恰好接口IFieldEdit与接口IField可以被同一个类所实现,所以我们可以使用接口IFieldEdit
IFieldEdit mm = new FieldClass();//IFieldEdit里面就有可用的属性
mm.Name_2 = "place";//字段名称
mm.Type_2 = esriFieldType.esriFieldTypeString;//字段文本类型
mm.Length_2 = 10;//字段长度
friend.AddField(mm as IField);
//mm原本是IFieldEdit里的属性,由于IFieldEdit与IField由同一个类所实现,故可以直接跳转
(4)删除字段
如果该方法要读取的接口名称为"IX",则回到刚才去找有没有叫X且可读属性,如果有,则该属性就可以返回接口IX
方法:DeleteField方法
方法类型:读取型的方法,读取IField且不带返回值
使用思路:回到IFeatureClass接口去找有没有叫Field或者Fields且可读的属性,如果有,则该属性就可以返回接口IField
IFields qq = friend.Fields;//读接口的属性
IField aa = qq.get_Field(3);
friend.DeleteField(aa);
3.ICommand接口
如果在.NET帮助中某个接口里面实现该接口的类比接口里面的方法属性多得多,那么多半会使用类
ICommand接口作用于ToolbarControl控件,作用是添加命令
如果要作用于axMapControl1控件的话,还需要调用下面两个方法:
//ICommand *** = new Class();
***.OnCreate(axMapControl1.Object);
***.OnClick();
(1)添加矢量数据
类:ControlsAddDataCommandClass类
类的作用:添加数量数据
实现的接口:ICommand接口
ICommand adddata = new ControlsAddDataCommandClass();
//使用类,直接初始化类就可以了
/*添加数据是command,要使用ICommand接口,如果要作用于
axMapControl1控件的话,还需要调用下面两个方法*/
adddata.OnCreate(axMapControl1.Object);
adddata.OnClick();
(2)全景视图
类:ControlsMapFullExtentCommandClass类
类的作用:全景视图
实现的接口:ICommand接口
ICommand adddata = new ControlsMapFullExtentCommandClass();
adddata.OnCreate(axMapControl1.Object);
adddata.OnClick();
4.ITool接口
ITool接口里面的类,ICommand几乎全都有。(1)如果这两个接口都有的类,要做用于axMapControl1控件,则还必须要调用IMapControl2中的CurrentTool属性,因此还需要跳转到ITool接口;(2)如果这个类只在ICommand里面有,要做用于axMapControl1控件,则只需直接调用类就可以了
if (axMapControl1.CurrentTool == null)
{ESRI.ArcGIS.SystemUI.ICommand ***;ESRI.ArcGIS.SystemUI.ITool **** = new Class();axMapControl1.CurrentTool = **** ;//核心代码:调用Class*** = **** as ESRI.ArcGIS.SystemUI.ICommand;***.OnCreate(axMapControl1.Object);***.OnClick();
}
else
{axMapControl1.CurrentTool = null;
}
地图放大(缩小)
读取接口的属性:
1.如果接口刚刚被初始化例如ITool ident = new + Class (),则属性在左,接口在右,并且不用加上接口前缀例如axMapControl1.CurrentTool = ident
2.如果要读取的接口没有被初始化,那么则属性在右,接口在左,并且要加上接口前缀例如IFields qq = friend.Fields;
属性:CurrentTool属性
属性作用:读取要作用在axMapControl1控件的接口ITool
注意事项:1.CurrentTool可以通过if语句打开或者关闭工具
2.CurrentTool可以直接用axMapControl1调用
类:ControlsMapZoomInToolClass类
类的作用:地图放大
实现的接口:ICommand、ITool接口
/*放大缩小是command,所以要调用ICommand接口,
如果要作用到axMapControl1控件中,还必须要调用
IMapControl2中的CurrentTool属性,因此还需要跳转到ITool接口*/
if (axMapControl1.CurrentTool == null)
{ESRI.ArcGIS.SystemUI.ICommand identify;//如果有if语句开控制打开或者关闭,则定义的新接口必须要跟上引用前缀ESRI.ArcGIS.SystemUI.ITool ident = new ControlsMapZoomInToolClass();//要读取的接口刚被初始化axMapControl1.CurrentTool = ident ;//属性在左,接口在右identify = ident as ESRI.ArcGIS.SystemUI.ICommand;/*ICommand接口作用于axMapControl1控件还需要调用下面两个方法*/identify.OnCreate(axMapControl1.Object);identify.OnClick();
}
else
{axMapControl1.CurrentTool = null;
}
加载地图后,点击地图放大的Button
即可进行放大
放大过后再次点击地图放大的Button,放大功能就关闭了就不能再放大了
如果我们把if语句删除
ICommand identify;/*去掉if语句就不需要加上引用前缀*/
ITool ident = new ControlsMapZoomInToolClass();
axMapControl1.CurrentTool = ident ;/*IMapControl2与
axMapControl1本质是一样的,所以可以直接调用*/
identify = ident as ICommand;/*ICommand接口作用于axMapControl1控件还需要调用下面两个方法*/
identify.OnCreate(axMapControl1.Object);
identify.OnClick();
点击地图放大
放大过后,再次点击地图放大按钮
发现无法关闭放大的功能
4.接口与控件的适配
1.最早的IFeatureLayer接口本身就作用在axMapControl1控件中,所以添加button就不用再调用ICommand或者ITool
2.ICommand接口是作用在ToolbarControl控件的,如果要作用于axMapControl1控件的话,需要调用下面两个方法
adddata.OnCreate(axMapControl1.Object);
adddata.OnClick();
3.放大缩小是command,所以要调用ICommand接口,如果要作用于axMapControl1控件中,还必须要调用IMapControl2中的CurrentTool属性,因此还需要跳转到ITool接口
4.ITool接口里面的类,ICommand几乎全都有。
(1)如果这两个接口都有的类,要做用于axMapControl1控件,则还必须要调用IMapControl2中的CurrentTool属性,因此还需要跳转到ITool接口;
(2)如果这个类只在ICommand里面有,要做用于axMapControl1控件,则只需直接调用类就可以了
5.用new初始化接口的两种情况
初始化一个接口时,使用new + Class + ();有以下几种情况:
(1)调用在Class作用下该接口的方法或属性
注意事项:调用方法或属性要有赋值
基础类代码:
IRgbColor rgbcol = new RgbColor();
rgbcol.RGB = 255;
rgbcol.Transparency = 255;ILineSymbol poutline = new SimpleLineSymbol();
poutline.Width = 1;
poutline.Color = rgbcol;//.Color属性读取接口
进阶类代码:让接口在另一个属性中运行
/*IEnvelope pEnv;
pEnv = e.newEnvelope as IEnvelope;*/
IElement pElement;
pElement = new RectangleElement();
pElement.Geometry = pEnv;//把接口pEnv赋给了它
//在RectangleElement作用下调用接口IElement的属性.Geometry
(2)该接口与另一接口都被这个Class实现,初始化这个接口目的是为了最终跳转到另一个被Class实现的接口
IFieldEdit mm = new FieldClass();/*IFieldEdit与
IField都被FieldClass实现*/
mm.Name_2 = "place";
mm.Type_2 = esriFieldType.esriFieldTypeString;
mm.Length_2 = 10;
friend.AddField(mm as IField);
(3)直接调用该Class的功能
注意事项:调用功能后的接口要赋给另一个接口的属性
ICommand identify;
ITool ident = new ControlsMapZoomInToolClass();
//直接调用ControlsMapZoomInToolClass的功能,即“放大”
axMapControl1.CurrentTool = ident ;//调用功能后的接口要赋给属性
identify = ident as ICommand;
6.读取接口的属性
7.不用new的接口实例化
1.把接口作用到控件中
注意事项:控件要运用属性,这里用到.Map属性:加载地图
IGraphicsContainer graphicsContainer;
graphicsContainer = axMapControl2.Map/*属性*/ as IGraphicsContainer;
//作用到axMapControl2中
2.让属性在另一个接口里运行
注意事项:运用到接口跳转。这里.Map属性在IActiveView中并没有,但是却要在该接口中运行
/*IGraphicsContainer graphicsContainer;*/
IActiveView activewer;
/*graphicsContainer = axMapControl2.Map as IGraphicsContainer;*/
//.Map属性在IGraphicsContainer中运行
activewer = graphicsContainer as IActiveView;//接口跳转
//.Map属性从在IGraphicsContainer中运行,跳转到在IActiveView中运行
IFillShapeElement pfillshapeelement;
pfillshapeelement = pElement as IFillShapeElement;
pfillshapeelement.Symbol = fillsym ;
8.IMap接口
IMap接口的作用是对地图图层进行增删改查,IMap接口里面就有很多实现增删改查的方法与属性。调用IMap接口可直接通过控件axMapControl来调用,如下所示:
1.先实例化再调用属性
IMap pmap = axMapControl1.Map;
for(int i = 0;i < pmap.LayerCount; ...)//调用IMap中的LayerCount属性
...
上面也可以直接写成for(int i = 0; i < axMapControl1.Map.LayerCount;...)
2.直接.Map实例化后就调用属性
axMapControl2.Map.AddLayer(...);//调用IMap中的AddLayer属性
axMapControlX.Map == IMap的实例化
9.鹰眼
(1)复制axMapControl1的地图到axMapControl2中
事件:OnMapReplaced
事件作用:当地图发生了改变,就运行里面的代码
IMap pmap = axMapControl1.Map;//定义一个IMap,并用Map这个属性来实例化
int i;
for (i = 0; i < pmap.LayerCount; i++)//遍历pmap中所有的图层
{IObjectCopy objectcopy = new ObjectCopy();//复制对象,定义一个IObjectCopy并用ObjectCopyClass对其实例化object toCopyLayer = axMapControl1.get_Layer(pmap.LayerCount - 1 - i);//先获取图层,使用get_Layerobject copiedLayer = objectcopy.Copy(toCopyLayer);//获取图层过后再复制图层,使用Copy//复制axMapControl1的图层axMapControl2.Map.AddLayer(copiedLayer as ILayer);//object强制转换成ILayer,因为复制的图层本身就是ILayer性质的(因为获取图层使用到了get_Layer)//添加到axMapControl2中,方法AddLayer
}
axMapControl2.Extent = axMapControl1.FullExtent;//保证axMapControl2里地图的范围始终是axMapControl1全景视图的范围
总结:1.如果要对地图进行增删改查,使用.Map属性,可通过axMapControl控件直接调用(因为.Map属性是IMapControl2中的属性)
2.使用鹰眼必不可少的代码:axMapControl2.Extent = axMapControl1.FullExtent;
(.Extent/.FullExtent都是IMapControl2的属性)
(2)设置矩形框
事件:OnExtentUpdated
事件作用:当视图范围发生改变,执行下面的代码
IEnvelope pEnv;//矩形框的类型是IEnvelope
pEnv = e.newEnvelope as IEnvelope;//实例化,newEnvelope是实时更新
IGraphicsContainer graphicsContainer;//IGraphicsContainer是一个容器,被Map这个类实现
IActiveView activewer;//IActiveView是实时更新,被Map这个类实现,与IGraphicsContainer可跳转
graphicsContainer = axMapControl2.Map as IGraphicsContainer;//实例化IGraphicsContainer,把容器放进axMapControl2中
activewer = graphicsContainer as IActiveView;//将容器接口跳转到IActiveView,同时对其进行了实例化
graphicsContainer.DeleteAllElements();//矩形框是一个element元素,先删除更新前容器里所有的element元素
IElement pElement;//新建一个element要素
pElement = new RectangleElement();//对element要素实例化
pElement.Geometry = pEnv;//实例化后,就把矩形框IEnvelope pEnv赋给这个element要素IRgbColor rgbcol = new RgbColor();//新建一个颜色rgbcol并实例化
rgbcol.RGB = 255;//颜色为红色
rgbcol.Transparency = 255;//透明度为不透明
ILineSymbol poutline = new SimpleLineSymbol();//新建外框线poutline并实例化
poutline.Width = 1;//外框线的粗细
poutline.Color = rgbcol;//外框线的颜色为刚才设置的颜色,即红色和不透明
IRgbColor pcolor = new RgbColor();//再次新建一个颜色pcolor并实例化
pcolor.RGB = 255;//颜色为红色
pcolor.Transparency = 0;//透明度为透明
IFillSymbol fillsym = new SimpleFillSymbol();//新建面fillsym并实例化
fillsym.Color = pcolor;//面的颜色为pcolor的颜色,即红色透明
fillsym.Outline = poutline;//面也是有外框线的,这里面的外框线和之前新建的外框线poutline颜色一样IFillShapeElement pfillshapeelement;//IFillShapeElement和IElement同时被RectangleElement这个类实现,故可以接口跳转
pfillshapeelement = pElement as IFillShapeElement;//将含有矩形框pEnv的element要素pElement跳转到该接口,同时实例化
pfillshapeelement.Symbol = fillsym ;//把设置好的面fillsym赋给含有矩形框的要素pElementpElement = pfillshapeelement as IElement;//跳转回来
graphicsContainer.AddElement(pElement, 0);//容器中添加pElement
activewer.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
(3)设置地图漫游
事件:Click
if (axMapControl1.CurrentTool == null)
{ESRI.ArcGIS.SystemUI.ICommand identify;ESRI.ArcGIS.SystemUI.ITool ident = new ControlsMapPanToolClass();//地图漫游ClassaxMapControl1.CurrentTool = ident;identify = ident as ESRI.ArcGIS.SystemUI.ICommand;identify.OnCreate(axMapControl1.Object);identify.OnClick();
}
else
{axMapControl1.CurrentTool = null;
}
ArcGIS Engine二次开发常用接口及其使用方法(一)相关推荐
- 【ArcGIS Engine二次开发】入门基础(2):ArcGIS开发方式(VBA、DLL、Add-in、Engine)对比
文章目录 2.1 使用VBA进行桌面软件开发 2.1.1 VBA开发方式 2.1.1 VBA代码的安全性 2.2 使用DLL进行桌面软件开发 2.2.1 DLL开发方式 2.2.2 DLL功能的应用部 ...
- 【ArcGIS Engine二次开发】入门基础(1):ArcGIS Engine简介及开发环境搭建
文章目录 ArcGIS Engine概述 ArcGIS Engine与ArcObjects的关系 ArcGIS Engine下载及安装 ArcGIS Engine概述 ArcGIS Engine简介 ...
- 利用Arcgis Engine 二次开发的使用和总结
Arcgis Engine 初体验 先放一张第一版系统的图,由于公司机密不能提供源码,但是各个小功能提供源码,为需要的同仁提供些许帮助. 接下来进入正题,将逐一展示利用Arcgis Engine开发的 ...
- 【转载】利用ArcGIS Engine 二次开发的使用和总结
文章目录 ArcGIS Engine 初体验 一.较完全编辑功能GIS程序 二.字段搜索要素和空间搜索要素GIS程序 三.图层重叠搜索GIS程序 四.要素合并.裁剪及检测要素重叠GIS程序 五.自定义 ...
- arcgis engine二次开发python-使用C#配合ArcGIS Engine进行地理信息系统开发
简单的地图读取.展示终于到暑假了...开始认真整理整理相关学习的心得体会咯~ 先把很久之前挖的关于C# 二次开发的坑给填上好了~ 这次先计划用一个月把C# ArcEngine 10.0相关开发的学习心 ...
- ArcGIS Engine二次开发
目录 1 安装环境配置 2 参考资料 3 面向对象基础 3.1 接口 3.2 类 3.3 对象 3.4 面向对象的三大特性 4 对象模型图和ArcGIS Engine开发帮助 4.1 对象模型图(OM ...
- 基于C#的ArcGIS Engine二次开发的一个简单测试程序
上一篇文章介绍了环境的搭建,现在我们来做出第一个小测试程序. (1)先建一个C#窗体应用程序,我将程序名称改为了ArcGIS_test2. (2)点击"工具"->" ...
- Arcgis Engine二次开发(一)AE开发总览
参加工作两年多,打算将两年来的AE(Arcgis Engine,本系列后面统一简称AE)开发经验分享出来.打算把AE的开发做成一个系列,原因主要有两个:一个是AE开发网上资源比较少,让从事开发的码农接 ...
- Arcgis Engine 二次开发之属性查询
一.类库接口描述 1.IQueryFilter接口 过滤数据通过属性值或者属性之间的关系,一般为其赋WhereClause和SubFields属性. 2.IFeatureClass接口 (1)Sear ...
- C#+ArcGIS Engine二次开发之鹰眼功能实现的代码
开发系统的时候,一定也会考虑鹰眼的实现,鹰眼对整个研究区域有一个整体的轮廓.所以,鹰眼对一个系统来说还是很有必要的.但是找过网上很多代码,大同小异,可最后出现的成果并不是我想要的,终于,get到了心仪 ...
最新文章
- 通过a标签在页面上显示视频网站中的视频
- MACE(2)-----模型编译
- int (*a)[10] 和 int *a[10] 的区别
- 云炬随笔20171202
- 分享一款颜色神器ColorSchemer Studio
- laravel $request 多维数组取值_大白话 Laravel 中间件
- 技术动态 | 知识图谱上的实体链接
- 2021接力题典1800【数学一】-汤家凤【题目册】
- 国内知名的java商城系统排名
- 快递鸟即时查询接口的连接和使用
- 一个 JDBC 实现对 mysql 进行分页查询的 实例
- 蓝叠模拟器查看Android版本,BlueStacks蓝叠版本信息在哪看蓝叠模拟器版本信息查看方法...
- Causal Reasoning from Meta-reinforcement Learning(自用笔记)
- 钢琴的乐理知识以及musicXml属性介绍
- 网络嗅探之一 --- 原理篇
- I/O 的五分钟法则(Five-Minute Rule)
- 周期信号的傅里叶级数展开
- GDKOI-2023 游记
- Pytorch:torch.ge()、torch.gt()、torch.le()、torch.lt()
- 一年级课程表(3月21日-3月25日)
热门文章
- python发送put请求
- Winform:自定义滚动条——可自定义皮肤
- mysql ibatis count_[mysql] mysql-myibatis-整理
- Windows 制作免安装的JAVA环境
- MATLAB实现巴特沃斯数字滤波器
- 多线程抢票_多线程抢票系统浅析
- 2022建筑架子工(建筑特殊工种)操作证考试题库及在线模拟考试
- 每一个成年男人在算法中都是好色之徒
- 用文字总结出计算机组装步骤,项目教学法在《计算机组装与维护》中的运用与反思(杜燕)...
- 揭秘“菲住布渴”中运用的黑科技:除了check in、坐电梯、开门...全部刷脸之外,还有什么?