我们与地图交互的过程时刻在进行着:一个拉框放大操作,或者对地图内容的查询等。这些交互过程中的输入输出,通常都是反映在独立于地图数据一个“层”上。比如拉框放大,我们能看见鼠标所画的一个矩形;又比如对兴趣点的查询,结果通常是将符合条件的兴趣点的形状高亮显示在那个独立的“层”中,通过它既可以反映用户的输入,又可以展现地图的输出。这个“层”就是GraphicsLayer。
        其实ADF开发中也有GraphicsLayer的概念,同样在其他两个客户端API(JavaScript/Flex)中也能找到GraphicsLayer的身影,它们都是一样一样的。
        本节我们主要看如何在GraphicsLayer中展现内容。当然第一个工作就是添加ESRI.ArcGIS.dll的引用,引入esri的xml命名空间;接下来在Map中添加一个GraphicsLayer图层:

  1. <esri:Map x:Name=”Map1″>
  2. <esri:Map.Layers>
  3. <!– 其他图层 –>
  4. <esri:GraphicsLayer ID=”GLayer” />
  5. </esri:Map.Layers>
  6. </esri:Map>

复制代码

要使GraphicsLayer中的内容处于最顶端(不被其他图层内容覆盖),就要将它放在Map标签里的最下头,像上面那样。从命名我们不难看出,GraphicLayer里面放的就是Graphic的集合了。Graphic(ESRI.ArcGIS.Graphic)是GraphicsLayer中的基本元素,它包括了Geometry(在ESRI.ArcGIS.Geometry命名空间中),Symbol(在ESRI.ArcGIS.Symbol命名空间中),Attributes等属性。所有显示在地图中的矢量元素都有一个Geometry,里面包含了若干地理坐标,用于显示地图上地物的形状,它是Point,Polyline,Polygon等的总称,在这里代表了Graphic的形状。Symbol代表了Graphic的外观,它是一系列符号的总称,我们通常跟SimpleMarkerSymbol,SimpleLineSymbol和SimpleFillSymbol等打交道,它们分别对应了上面3种不同的Geometry(Point,Polyline,Polygon)。
        要让一个Graphic显示出来,总共分3步:
1、定义Graphic:
在xaml中

  1. <esri:Graphic>
  2. </esri:Graphic>

复制代码

在code-behind中
Graphic g= new Graphic()
2、设置Graphic的Geometry和Symbol属性:
在xaml中

  1. <esri:Graphic>
  2. <esri:Graphic.Symbol>
  3. <esriSymbols:SimpleMarkerSymbol Color=”Blue” Size=”12″ Style=”Square” />
  4. </esri:Graphic.Symbol>
  5. <esriGeometry:MapPoint X=”108″ Y=”30″ />
  6. </esri:Graphic>

复制代码

在code-behind中

  1. Graphic g = new Graphic()
  2. {
  3. Geometry = new MapPoint(108, 30),
  4. Symbol = new SimpleMarkerSymbol()
  5. {
  6. Color = new SolidColorBrush(Colors.Blue),
  7. Size = 12,
  8. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  9. }
  10. };

复制代码

3、把定义好的Graphic添加到GraphicsLayer里:
在xaml中

  1. <esri:GraphicsLayer ID=”GLayer”>
  2. <esri:GraphicsLayer.Graphics>
  3. <esri:Graphic>
  4. <esri:Graphic.Symbol>
  5. <esriSymbols:SimpleMarkerSymbol Color=”Blue” Size=”12″ Style=”Square” />
  6. </esri:Graphic.Symbol>
  7. <esriGeometry:MapPoint X=”108″ Y=”30″ />
  8. </esri:Graphic>
  9. </esri:GraphicsLayer.Graphics>
  10. </esri:GraphicsLayer>

复制代码

在code-behind中

  1. Graphic g = new Graphic()
  2. {
  3. Geometry = new MapPoint(108, 30),
  4. Symbol = new SimpleMarkerSymbol()
  5. {
  6. Color = new SolidColorBrush(Colors.Blue),
  7. Size = 12,
  8. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  9. }
  10. };
  11. GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
  12. glayer.Graphics.Add(g);

复制代码

看一下效果:


        图中还有其他的图形,无非是改变了Graphic的Geometry和Symbol属性。图上的那只灰熊是一段动画文件,利用Silverlight的特性,能够定义出表现力丰富的各种符号。
        尽管能够完全在xaml中来完成工作,但还是建议将可视化元素的定义放在xaml中,将实现的逻辑部分放在code-behind中。看一下添加图中那些Graphic的代码:

  1. <Grid.Resources>
  2. <esriSymbols:SimpleMarkerSymbol x:Name=”RedMarkerSymbol” Color=”Red” Size=”12″ Style=”Circle” />
  3. <!– 可惜目前Silverlight只支持Jpeg和PNG格式的图像,所以PictureMarkerSymbol无法显示GIF格式的图像,否则会报ImagingError的错误 –>
  4. <esriSymbolsictureMarkerSymbol x:Name=”PinPictureMarkerSymbol” Source=”imgs/pin.png” OffsetX=”10″ OffsetY=”10″ />
  5. <esriSymbols:SimpleLineSymbol x:Name=”RedLineSymbol” Color=”Red” Width=”4″ Style=”Solid” />
  6. <esriSymbols:CartographicLineSymbol x:Name=”CartoLineSymbol” Color=”Red” Width=”10″ DashCap=”Triangle” LineJoin=”Round” DashArray=”6,2″ />
  7. <esriSymbols:SimpleFillSymbol x:Name=”RedFillSymbol” Fill=”#66FF0000″ BorderBrush=”Red” BorderThickness=”2″ />
  8. </Grid.Resources>
  9. <MediaElement x:Name=”BearVideo” />

复制代码

  1. private void AddGraphics()
  2. {
  3. GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
  4. Graphic[] graphics = new Graphic[8];
  5. graphics[0] = new Graphic()
  6. {
  7. Geometry = new MapPoint(108, 34),
  8. Symbol = RedMarkerSymbol
  9. };
  10. graphics[1] = new Graphic()
  11. {
  12. Geometry = new MapPoint(108, 30),
  13. Symbol = new SimpleMarkerSymbol()
  14. {
  15. Color = new SolidColorBrush(Colors.Blue),
  16. Size = 12,
  17. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  18. }
  19. };
  20. graphics[2] = new Graphic()
  21. {
  22. Geometry = new MapPoint(108, 25),
  23. Symbol = PinPictureMarkerSymbol
  24. };
  25. graphics[3] = new Graphic()
  26. {
  27. Geometry = new MapPoint(108, 20),
  28. Symbol = new TextSymbol()
  29. {
  30. FontFamily = new FontFamily(”微软雅黑, 宋体”),
  31. FontSize = 14,
  32. Foreground = new SolidColorBrush(Colors.Black),
  33. Text = “这是text symbol”
  34. }
  35. };
  36. graphics[4] = new Graphic();
  37. graphics[4].Symbol = RedLineSymbol;
  38. ESRI.ArcGIS.Geometry.PointCollection pc = new ESRI.ArcGIS.Geometry.PointCollection()
  39. {
  40. new MapPoint(95,10),
  41. new MapPoint(110,-15),
  42. new MapPoint(130,10)
  43. };
  44. ESRI.ArcGIS.Geometry.Polyline pl = new ESRI.ArcGIS.Geometry.Polyline();
  45. pl.Paths.Add(pc);
  46. graphics[4].Geometry = pl;
  47. graphics[5] = new Graphic();
  48. graphics[5].Symbol = CartoLineSymbol;
  49. ESRI.ArcGIS.Geometry.PointCollection pc1 = new ESRI.ArcGIS.Geometry.PointCollection()
  50. {
  51. new MapPoint(95,0),
  52. new MapPoint(110,-25),
  53. new MapPoint(130,0)
  54. };
  55. ESRI.ArcGIS.Geometry.Polyline pl1 = new ESRI.ArcGIS.Geometry.Polyline();
  56. pl1.Paths.Add(pc1);
  57. graphics[5].Geometry = pl1;
  58. graphics[6] = new Graphic()
  59. {
  60. Symbol = RedFillSymbol
  61. };
  62. ESRI.ArcGIS.Geometry.PointCollection pc2 = new ESRI.ArcGIS.Geometry.PointCollection()
  63. {
  64. new MapPoint(110,-30),
  65. new MapPoint(130,-30),
  66. new MapPoint(130,-45),
  67. new MapPoint(120,-55),
  68. new MapPoint(110,-45),
  69. new MapPoint(110,-30)
  70. };
  71. ESRI.ArcGIS.Geometry.Polygon pg = new ESRI.ArcGIS.Geometry.Polygon();
  72. pg.Rings.Add(pc2);
  73. graphics[6].Geometry=pg;
  74. graphics[7] = new Graphic();
  75. //MediaElement的Name属性只能在xaml中定义(见帮助),所以决定了MediaElement不能完全在cs代码中定义
  76. BearVideo.Source = new Uri(”http://serverapps.esri.com/media/bear.wmv”, UriKind.RelativeOrAbsolute);
  77. BearVideo.IsHitTestVisible=false;
  78. BearVideo.IsMuted=true;
  79. BearVideo.AutoPlay=true;
  80. BearVideo.Opacity=0;
  81. ESRI.ArcGIS.Geometry.Polygon pg2 = new ESRI.ArcGIS.Geometry.Polygon();
  82. ESRI.ArcGIS.Geometry.PointCollection pc3 = new ESRI.ArcGIS.Geometry.PointCollection()
  83. {
  84. new MapPoint(10,-20),
  85. new MapPoint(32,7),
  86. new MapPoint(62,-35),
  87. new MapPoint(11,-36),
  88. new MapPoint(10,-20)
  89. };
  90. pg2.Rings.Add(pc3);
  91. graphics[7].Geometry=pg2;
  92. graphics[7].Symbol = new SimpleFillSymbol()
  93. {
  94. Fill = new VideoBrush()
  95. {
  96. SourceName = BearVideo.Name,
  97. Opacity = 0.6,
  98. Stretch = Stretch.UniformToFill
  99. }
  100. };
  101. foreach (Graphic g in graphics)
  102. {
  103. glayer.Graphics.Add(g);
  104. g.MouseLeftButtonDown+=new MouseButtonEventHandler(graphic_MouseLeftButtonDown);
  105. }
  106. }
  107. private void graphic_MouseLeftButtonDown(object o,MouseButtonEventArgs e)
  108. {
  109. Graphic g=o as Graphic;
  110. MessageBox.Show(string.Format(”Geometry:{0}/nSymbol:{1}”,g.Geometry.GetType().ToString(),g.Symbol.GetType().ToString()));
  111. }

复制代码

可以看到,完全能够在一个Graphic上定义一些事件,来达到程序的目的。大家可以试着把上面的内容在xaml中改写一遍。看到这里肯定会产生一个疑问:难道每个Geometry的定义都这么困难吗?其实SilverlightAPI已经给我们提供了ESRI.ArcGIS.Draw(继承自xaml中的Canvas)类,它能非常方便的捕捉到用户的鼠标操作,从而获取各种Geometry来供程序使用。
        可以把Draw理解成一块画板,调用Draw的Active()方法,就可以开始在画板上面绘画,程序会自动记录鼠标画出的每个Geometry,调用DeActive()方法,停止绘画。Active()有一个DrawMode参数,它决定了我们即将在这个画板上画出的内容类型:Point,Polyline,Polygon等。在画的过程中我们可以看到地图上可以实时反映出我们绘画的内容,而这些则利用了Draw的预定义Symbol:DefaultMarkerSymbol,DefaultLineSymbol,DefaultPolygonSymbol等。对应关系如下:


        每当完成一个图形的绘制,就会触发Draw.OnDrawComplete事件,利用事件参数就可以获得Geometry,之后可以创建一个Graphic,设置一个Symbol(一般使用Draw的预定义Symbol),把画好的这个Graphic添加到一个GraphicsLayer中。
        点击这里,查看一个比较完整的Graphics的例子。
最后来看一下这个例子的部分代码:

  1. <Grid.Resources>
  2. <esriSymbols:SimpleMarkerSymbol x:Name=”DefaultMarkerSymbol” Color=”Red” Size=”12″ Style=”Circle” />
  3. <esriSymbols:CartographicLineSymbol x:Name=”DefaultLineSymbol” Color=”Red” Width=”4″ />
  4. <esriSymbols:SimpleFillSymbol x:Name=”DefaultFillSymbol” Fill=”#33FF0000″ BorderBrush=”Red” BorderThickness=”2″ />
  5. <esriSymbols:SimpleFillSymbol x:Name=”DefaultPolygonSymbol” Fill=”#33FF0000″ BorderBrush=”Red” BorderThickness=”2″ />
  6. </Grid.Resources>
  7. <esriraw x:Name=”Draw1″
  8. DefaultRectangleSymbol=”{StaticResource DefaultFillSymbol}”
  9. DefaultMarkerSymbol=”{StaticResource DefaultMarkerSymbol}”
  10. DefaultLineSymbol=”{StaticResource DefaultLineSymbol}”
  11. DefaultPolygonSymbol=”{StaticResource DefaultPolygonSymbol}”
  12. Loaded=”Draw1_Loaded”
  13. OnDrawComplete=”Draw1_OnDrawComplete” />
  14. <Canvas VerticalAlignment=”Top” HorizontalAlignment=”Left” Margin=”20,20,0,0″ Width=”430″ Height=”110″>
  15. <Rectangle RadiusX=”10″ RadiusY=”10″ Width=”430″ Height=”110″ Fill=”#98000000″ Stroke=”#FF6495ED” />
  16. <Rectangle Fill=”#FFFFFFFF” Stroke=”DarkGray” RadiusX=”5″ RadiusY=”5″ Canvas.Left=”10″ Canvas.Top=”10″ Width=”410″ Height=”90″ />
  17. <StackPanel Orientation=”Vertical” Canvas.Top=”5″ Canvas.Left=”20″>
  18. <esriWidgets:Toolbar x:Name=”ToolBar1″ MaxItemHeight=”80″ MaxItemWidth=”80″ Width=”380″ Height=”80″
  19. ToolbarIndexChanged=”ToolBar1_ToolbarIndexChanged”
  20. ToolbarItemClicked=”ToolBar1_ToolbarItemClicked”>
  21. <esriWidgets:Toolbar.Items>
  22. <esriWidgets:ToolbarItemCollection>
  23. <esriWidgets:ToolbarItem Text=”添加点”>
  24. <esriWidgets:ToolbarItem.Content>
  25. <Image Source=”imgs/DrawPoint.png” Stretch=”UniformToFill” Margin=”5″ />
  26. </esriWidgets:ToolbarItem.Content>
  27. </esriWidgets:ToolbarItem>
  28. <esriWidgets:ToolbarItem Text=”添加折线”>
  29. <esriWidgets:ToolbarItem.Content>
  30. <Image Source=”imgs/DrawPolyline.png” Stretch=”UniformToFill” Margin=”5″ />
  31. </esriWidgets:ToolbarItem.Content>
  32. </esriWidgets:ToolbarItem>
  33. <esriWidgets:ToolbarItem Text=”添加多边形”>
  34. <esriWidgets:ToolbarItem.Content>
  35. <Image Source=”imgs/DrawPolygon.png” Stretch=”UniformToFill” Margin=”5″ />
  36. </esriWidgets:ToolbarItem.Content>
  37. </esriWidgets:ToolbarItem>
  38. <esriWidgets:ToolbarItem Text=”添加矩形”>
  39. <esriWidgets:ToolbarItem.Content>
  40. <Image Source=”imgs/DrawRectangle.png” Stretch=”UniformToFill” Margin=”5″ />
  41. </esriWidgets:ToolbarItem.Content>
  42. </esriWidgets:ToolbarItem>
  43. <esriWidgets:ToolbarItem Text=”添加曲线”>
  44. <esriWidgets:ToolbarItem.Content>
  45. <Image Source=”imgs/DrawFreehand.png” Stretch=”UniformToFill” Margin=”5″ />
  46. </esriWidgets:ToolbarItem.Content>
  47. </esriWidgets:ToolbarItem>
  48. <esriWidgets:ToolbarItem Text=”停止添加动作”>
  49. <esriWidgets:ToolbarItem.Content>
  50. <Image Source=”imgs/StopDraw.png” Stretch=”UniformToFill” Margin=”5″ />
  51. </esriWidgets:ToolbarItem.Content>
  52. </esriWidgets:ToolbarItem>
  53. <esriWidgets:ToolbarItem Text=”清空绘制的图形”>
  54. <esriWidgets:ToolbarItem.Content>
  55. <Image Source=”imgs/eraser.png” Stretch=”UniformToFill” Margin=”5″ />
  56. </esriWidgets:ToolbarItem.Content>
  57. </esriWidgets:ToolbarItem>
  58. </esriWidgets:ToolbarItemCollection>
  59. </esriWidgets:Toolbar.Items>
  60. </esriWidgets:Toolbar>
  61. <TextBlock x:Name=”StatusTextBlock” Text=”" FontWeight=”Bold” HorizontalAlignment=”Center”/>
  62. </StackPanel>
  63. </Canvas>

复制代码

  1. private void Draw1_Loaded(object sender, RoutedEventArgs e)
  2. {
  3. Draw1.Map = Map1;
  4. }
  5. private void Draw1_OnDrawComplete(object sender, ESRI.ArcGIS.DrawEventArgs args)
  6. {
  7. ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
  8. ESRI.ArcGIS.Graphic graphic = new ESRI.ArcGIS.Graphic()
  9. {
  10. Geometry = args.Geometry,
  11. Symbol = _activeSymbol,
  12. };
  13. graphicsLayer.Graphics.Add(graphic);
  14. }
  15. private void ToolBar1_ToolbarIndexChanged(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
  16. {
  17. StatusTextBlock.Text = e.Item.Text;
  18. }
  19. private void ToolBar1_ToolbarItemClicked(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
  20. {
  21. Draw1.Deactivate();
  22. switch (e.Index)
  23. {
  24. case 0: // Point
  25. Draw1.Activate(ESRI.ArcGIS.DrawMode.Point);
  26. _activeSymbol = strobeSymbol;
  27. break;
  28. case 1: // Polyline
  29. Draw1.Activate(ESRI.ArcGIS.DrawMode.Polyline);
  30. _activeSymbol = DefaultLineSymbol;
  31. break;
  32. case 2: // Polygon
  33. Draw1.Activate(ESRI.ArcGIS.DrawMode.Polygon);
  34. _activeSymbol = DefaultPolygonSymbol;
  35. break;
  36. case 3: // Rectangle
  37. Draw1.Activate(ESRI.ArcGIS.DrawMode.Rectangle);
  38. _activeSymbol = DefaultFillSymbol;
  39. break;
  40. case 4: // Freehand
  41. Draw1.Activate(ESRI.ArcGIS.DrawMode.Freehand);
  42. _activeSymbol = waveLineSymbol;
  43. break;
  44. case 5: // Stop Graphics
  45. break;
  46. case 6: // Clear Graphics
  47. ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
  48. graphicsLayer.ClearGraphics();
  49. break;
  50. }
  51. }

复制代码

大家可以注意一下例子中添加的点符号和曲线符号。只要有足够的想象力,完全可以利用Silverlight定制出非常炫的符号效果来。
        好了,下一节我们来了解如何使用这些画出的图形与地图数据交互。

ArcGIS API for Silverlight开发入门(4):用户与地理信息之间的桥梁–GraphicsLayer相关推荐

  1. ArcGIS API for Silverlight开发入门

    ArcGIS API for Silverlight开发入门 你用上3G手机了吗?你可能会说,我就是喜欢用nokia1100,ABCDEFG跟我 都没关系.但你不能否认3G是一种趋势,最终我们每个人都 ...

  2. ArcGIS API for Silverlight开发入门准备

    原文:ArcGIS API for Silverlight开发入门准备 微软的Silverlight提供了跨浏览器和跨平台开发环境,在Web中可用于创建和展现富互联网应用(RIA,Rich Inter ...

  3. ArcGIS API for Silverlight开发入门(2):一个基础地图实例

    这节在一个地图实例的基础上,来对Silverlight API中的一些基本概念做一个总体了解,顺便熟悉一下Silverlight的开发知识.         点击这里,直接看效果. 下载 (722.0 ...

  4. arcgis api for flex 开发入门(九)webservices 的使用

    arcgis api for flex 开发入门(九)webservices 的使用 flex 本身对webservices有着良好的支持,我们可以调用互联网上的各种 webservices来结合es ...

  5. arcgis api for flex 开发入门(二)map 的创建

    arcgis api for flex 开发入门(二)map 的创建 在flex 中创建一个esri 的map ,你只需要使用<esri:Map>标签就可以轻松完成. 在<esri: ...

  6. arcgis api for flex 开发入门(七)Geometry service 的使用

    arcgis api for flex 开发入门(七)Geometry service 的使用 Geometry service 顾名思义,就是提供针对几何层级的服务,比如说Project,   Si ...

  7. arcgis api for flex 开发入门(五)查询

    在gis中,针对要素的查询是一个最基本的操作,也是最常用的操作之一. 下面我们介绍如何使用arcgis api for flex 来查询我们需要的东西. 要在arcgis api for flex中进 ...

  8. 13 ArcGIS API for JavaScript开发入门文档

    写在前面 这篇文章写在我用ArcGIS API for JavaScript(后面统称为"ArcGIS JS API")开发了两年项目后的某一天夜里.写这篇文章主要是两个目的吧,第 ...

  9. ArcGIS API for Silverlight开发

    http://bbs.esrichina-bj.cn/ESRI/thread-45836-1-2.html Ethan_Shan little sister's birthday https://b ...

  10. ArcGis api配合vue开发入门系列(二)距离以及面积的测量

    正文 首先自定义个工具栏,包括测量距离与测量面积的工具以及地图漫游. 图标的话是用的iconfont.我是把这个工具单独写在一个组件里面,这个组件里面里面会用到一些操作地图的方法,我在map这个组件里 ...

最新文章

  1. python续行符是啥_python续行符
  2. 全自动采集新闻站源码-单站自动采集新闻源码(seo标题伪原创)
  3. Ubuntu16.04下codeblocks16.01安装,适用于不同的架构
  4. 整数倒转问题的算法实现
  5. MongoDB 表结构分析工具介绍 -- Variety
  6. 真·不怪云原生:探寻IT大厂逐渐云化的秘密!
  7. java文件处理:文件流、上传、下载
  8. DGIOT实战教程——虚拟ModbusRTU接入
  9. TTL和RS232之间的详细对比转
  10. 电路原理笔记整理_【盛世清北】2021清华大学827电路原理考研笔记-清华考研辅导班...
  11. 台式计算机如何扫描文件,打印机怎么扫描,教您打印机怎么扫描文件
  12. Java设计模式(六)装饰器模式-与代理模式的区别-项目实战应用
  13. Python SMTP发送邮件
  14. 【爬虫学习笔记day66】7.8. scrapy-redis实战-- IT桔子分布式项目2
  15. 你真的了解分类模型评估指标都有哪些吗?【附Python代码实现】
  16. win10+Linux18.04双系统安装
  17. 全功能mp3,wav音频格式转换器-QVE音频剪辑
  18. python 查看 文件MD5值
  19. 【服务器数据恢复】Raid阵列更换故障硬盘后数据同步失败的数据恢复案例
  20. 狼群效应-霍桑效应-磨合效应

热门文章

  1. 5种常见的3D游戏艺术风格及工具栈
  2. Xcode中使用Git进行代码版本控制
  3. [导读]整合Spring MVC由于用到jstl,所以假如jstl便签用的jar包,启动tomcat时控制台出现了如下的输出:2014-3-25 23:54:49 org.apache.catal
  4. LeetCode102.二叉树的层序遍历(按层输出和统一输出)
  5. 5位运动员参加了10米台跳水比赛
  6. android 防丢器 ibeacon
  7. Android植入微信支付的那些坑
  8. 山科大2018期末OJ 几点几分几秒 (Append Code)
  9. [置顶] ubuntu 12.04 使用纪要 -- 持续更新
  10. 这里有张高能地图 科达正式发布扁平化指挥系统