WPF中手写地图控件(1)——基于瓦片地图的控件

基于瓦片地图的控件

本控件使用dotnet编写,基于WPF的数据绑定自动生成,可以用于展示瓦片地图。为了提高地图加载速度,我们使用了内存缓存和本地文件缓存技术,并采用从中心扩散异步等加载方式。这些技术的结合,使得地图的加载更加流畅。

你可以在Nuget上搜索xyxandwxx.MapControl直接引用该控件

多个瓦片组成地图控件

<UserControl x:Class="MapControl.Gis.GisLayout"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MapControl.Gis"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Name="MainControl" Background="#00000000"><UserControl.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Styles/GisMapGridStyle.xaml"></ResourceDictionary></ResourceDictionary.MergedDictionaries></ResourceDictionary></UserControl.Resources><Canvas Background="#00000000" Name="MapControlGrid" IsManipulationEnabled="True" ManipulationStarting="Grid_ManipulationStarting" ManipulationDelta="Grid_ManipulationDeltaAsync" ManipulationCompleted="Grid_ManipulationCompleted"><Grid Canvas.Left="{Binding OffsetX,ElementName=MainControl}" Canvas.Top="{Binding OffsetY,ElementName=MainControl}"MouseMove="MMove" MouseDown="MDown" MouseUp="MUp" MouseLeave="MLeave" MouseWheel="MWheel" ><ItemsControl ItemsSource="{Binding BaseMap.TitleBlocks,ElementName=MainControl}"ScrollViewer.CanContentScroll="False" Name="MapLayout"Style="{StaticResource MapCanvasImageList}"></ItemsControl><ItemsControl ItemsSource="{Binding Areas,ElementName=MainControl}"ScrollViewer.CanContentScroll="False"Style="{StaticResource MaskListStyle}"></ItemsControl></Grid></Canvas></UserControl>

单个瓦片数据结构

瓦片的数据结构,其中X、Y、Level是瓦片本身的属性,用于获取到瓦片图的路径Url,后面的高度Height、宽度Width就是显示为图像控件的大小,偏移量LayerOffsetPixelX与LayerOffsetPixelY就是基于地图左上角的瓦片,在右边第几个LayerOffsetPixelX就是几倍的
Width,在下面第几个LayerOffsetPixelY就是几倍的Height。

public class TitleBlock : INotifyPropertyChanged
{/// <summary>/// X/// </summary>public int TitleX { get; set; }/// <summary>/// Y/// </summary>public int TitleY { get; set; }/// <summary>/// 所在的地图等级/// </summary>public int Level { get; set; }/// <summary>/// 地址/// </summary>public Uri Url { get; set; }/// <summary>/// 宽度/// </summary>public double Width { get; set; } = 256;/// <summary>/// 高度/// </summary>public double Height { get; set; } = 256;/// <summary>/// 绘制的时候的偏移量/// </summary>public double LayerOffsetPixelX { get; set; }/// <summary>/// 绘制的时候的偏移量/// </summary>public double LayerOffsetPixelY { get; set; }public event PropertyChangedEventHandler? PropertyChanged;
}

瓦片的样式

<Style TargetType="ItemsControl" x:Key="MapCanvasImageList"><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate><Canvas IsItemsHost="True" Width="{Binding BaseMap.PixelWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}"Height="{Binding BaseMap.PixelHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}"></Canvas></ItemsPanelTemplate></Setter.Value></Setter><Setter Property="ItemContainerStyle"><Setter.Value><Style TargetType="ContentPresenter"><Setter Property="Canvas.Left" Value="{Binding LayerOffsetPixelX}"></Setter><Setter Property="Canvas.Top" Value="{Binding LayerOffsetPixelY}"></Setter></Style></Setter.Value></Setter><Setter Property="ItemTemplate"><Setter.Value><DataTemplate><local:LoadingImage Width="{Binding Width}" Height="{Binding Height}" Source="{Binding Url,IsAsync=True}"></local:LoadingImage></DataTemplate></Setter.Value></Setter>
</Style>

地图布局的数据结构

/// <summary>
/// 基础的地图布局类
/// </summary>
public abstract class BaseMapLayout : INotifyPropertyChanged
{/// <summary>/// 当前地图的显示层级/// </summary>public virtual int Level { get; set; }/// <summary>/// 瓦片地图宽度/// </summary>public virtual double MapTitleWidth { get; set; } = 256;/// <summary>/// 最大和最小的显示等级/// </summary>public abstract int MinLevel { get; set; }public abstract int MaxLevel { get; set; }/// <summary>/// 当前的行数/// </summary>public int Rows { get; protected set; }/// <summary>/// 当前的列数/// </summary>public int Cols { get; protected set; }/// <summary>/// 总的像素宽度/// </summary>public double PixelWidth { get; set; }/// <summary>/// 总的像素高度/// </summary>public double PixelHeight { get; set; }/// <summary>/// 修改的次数/// </summary>public int ModifyCount { get; set; } = 0;/// <summary>/// 当前的偏移box/// </summary>public TitleBlock OffsetTitleBox { get; set; }/// <summary>/// 缓存管理/// </summary>internal CacheManager CacheManager { get; set; }/// <summary>/// 当前的block集合/// </summary>public virtual IList<TitleBlock> TitleBlocks { get; protected set; }/// <summary>/// 当前层一共有多少个区块/// </summary>public virtual int TotalBlock{get{var t = (int)Math.Pow(Math.Pow(2, Level), 2);if (t == 0) return 1;return t;}}
}

1.其中Level、MinLevel、MaxLevel是表示地图等级,一般是前端通过鼠标滚轮事件MouseWheel、触摸屏双指操作更改ManipulationDelta
2.其中行数、列数,一般是前端通过按住鼠标移动、触摸屏滑动事件更改,其中触摸事件可以参考创建你的第一个触控应用程序。

自定义地图用户控件

这里主要是一些依赖属性

public partial class GisLayout : UserControl
{#region 扩展属性public static readonly DependencyProperty BaseMapProperty = DependencyProperty.Register("BaseMap", typeof(BaseMapLayout), typeof(GisLayout));public static DependencyProperty AreasProperty = DependencyProperty.Register("Areas", typeof(IEnumerable), typeof(GisLayout));public static DependencyProperty OffsetXProperty = DependencyProperty.Register("OffsetX", typeof(double), typeof(GisLayout));public static DependencyProperty OffsetYProperty = DependencyProperty.Register("OffsetY", typeof(double), typeof(GisLayout));public static DependencyProperty FillProperty = DependencyProperty.Register("Fill", typeof(Brush), typeof(GisLayout));public static DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(GisLayout));public static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint", typeof(Point), typeof(GisLayout), new PropertyMetadata(CenterPointCallback));public static DependencyProperty IsZoomAutoCenterProperty = DependencyProperty.Register("IsZoomAutoCenter", typeof(bool), typeof(GisLayout), new PropertyMetadata(false));public static DependencyProperty TextFontSizeProperty = DependencyProperty.Register("TextFontSize", typeof(double), typeof(GisLayout), new PropertyMetadata(12.0));public static DependencyProperty LevelProperty = DependencyProperty.Register("Level", typeof(int), typeof(GisLayout), new PropertyMetadata(new PropertyChangedCallback(OnLevelChanged)));public static DependencyProperty MaxLevelProperty = DependencyProperty.Register("MaxLevel", typeof(int), typeof(GisLayout));public static readonly DependencyPropertyKey LevelMinusPropertyKey = DependencyProperty.RegisterReadOnly("LevelMinus", typeof(int), typeof(GisLayout), null);public static readonly DependencyProperty LevelMinusProperty = LevelMinusPropertyKey.DependencyProperty;public static DependencyProperty ItemVisibilityProperty = DependencyProperty.Register("ItemVisibility", typeof(Visibility), typeof(GisLayout));private static void CenterPointCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){GisLayout layout = d as GisLayout;Point p = (Point)e.NewValue;layout.SetCenter(p.X, p.Y);}public static DependencyProperty DragMouseButtonProperty = DependencyProperty.Register("DragMouseButton", typeof(MouseButton), typeof(GisLayout), new PropertyMetadata(MouseButton.Right));#endregion/// <summary>/// Item的Visibility状态/// </summary>public Visibility ItemVisibility { get => (Visibility)GetValue(ItemVisibilityProperty); set => SetValue(ItemVisibilityProperty, value); }/// <summary>/// 地图最大Level与当前Level的差值/// </summary>public int LevelMinus { get => (int)GetValue(LevelMinusProperty); private set => SetValue(LevelMinusPropertyKey, value); }/// <summary>/// 地图当前Level/// </summary>public int Level { get => (int)GetValue(LevelProperty); set => SetValue(LevelProperty, value); }/// <summary>/// 地图最大Level/// </summary>public int MaxLevel { get => (int)GetValue(MaxLevelProperty); set => SetValue(MaxLevelProperty, value); }/// <summary>/// 文本字体大小/// </summary>public double TextFontSize { get => (double)GetValue(TextFontSizeProperty); set => SetValue(TextFontSizeProperty, value); }/// <summary>/// 设置缩放自动更新中心点/// </summary>public bool IsZoomAutoCenter { get => (bool)GetValue(IsZoomAutoCenterProperty); set => SetValue(IsZoomAutoCenterProperty, value); }/// <summary>/// 地图操作类/// </summary>public BaseMapLayout BaseMap { get => (BaseMapLayout)GetValue(BaseMapProperty); set => SetValue(BaseMapProperty, value); }/// <summary>/// 经纬度区域数据集/// </summary>public IEnumerable Areas { get => (IEnumerable)GetValue(AreasProperty); set => SetValue(AreasProperty, value); }/// <summary>/// 控件偏移坐标/// </summary>public double OffsetX { get => (double)GetValue(OffsetXProperty); set => SetValue(OffsetXProperty, value); }/// <summary>/// 控件拖拽偏移坐标/// </summary>public double OffsetY { get => (double)GetValue(OffsetYProperty); set => SetValue(OffsetYProperty, value); }/// <summary>/// 经纬度遮罩填充颜色/// </summary>public Brush Fill { get => (Brush)GetValue(FillProperty); set => SetValue(FillProperty, value); }/// <summary>/// 中心经纬度/// </summary>public Point CenterPoint { get => (Point)GetValue(CenterPointProperty); set => SetValue(CenterPointProperty, value); }/// <summary>/// 拖拽鼠标的按键/// </summary>public MouseButton DragMouseButton { get => (MouseButton)GetValue(DragMouseButtonProperty); set => SetValue(DragMouseButtonProperty, value); }/// <summary>/// 子项模板/// </summary>public DataTemplate ItemTemplate { get => (DataTemplate)GetValue(ItemTemplateProperty); set => SetValue(ItemTemplateProperty, value); }/// <summary>/// 构造函数/// </summary>public GisLayout(){InitializeComponent();this.Loaded += GisLayout_Loaded;}private void GisLayout_Loaded(object sender, RoutedEventArgs e){SetCenter(CenterPoint.X, CenterPoint.Y);}public event PropertyChangedEventHandler PropertyChanged;private static void OnLevelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){int maxLevel = (int)d.GetValue(MaxLevelProperty);int level = (int)d.GetValue(LevelProperty);d.SetValue(LevelMinusPropertyKey, maxLevel - level);}protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo){base.OnRenderSizeChanged(sizeInfo);SetCenter(CenterPoint.X, CenterPoint.Y);}/// <summary>/// 经纬度坐标转当前地图的像素坐标/// </summary>/// <param name="mapPoint">经纬度坐标</param>/// <returns>像素坐标</returns>private Point ConvertToPixelPoint(Point mapPoint){if (BaseMap is null) return new Point();PixelTitleBlock block = BaseMap.LongitudeAndAtitudeConvertToPixel(mapPoint.X, mapPoint.Y);var centerX = (block.TitleX - BaseMap.OffsetTitleBox.TitleX) * block.Width + block.OffsetX;var centerY = (block.TitleY - BaseMap.OffsetTitleBox.TitleY) * block.Height + block.OffsetY;return new Point(centerX, centerY);}/// <summary>/// 设置居中 在设置的经纬度/// </summary>/// <param name="lat">维度</param>/// <param name="lng">经度</param>public void SetCenter(double lng, double lat){if (BaseMap is null) return;var center = ConvertToPixelPoint(new Point(lng, lat));var offsetx = RenderSize.Width / 2 - center.X;var offsety = RenderSize.Height / 2 - center.Y;var clip = OffsetClip(new Point(offsetx, offsety));OffsetX = clip.X;OffsetY = clip.Y;}#region 鼠标控制/// <summary>/// 前一个坐标/// </summary>private Point ForntPoint { get; set; }/// <summary>/// 是否移动/// </summary>private bool IsMove { get; set; }/// <summary>/// 是否是多指操作/// </summary>private bool IsManipulationOption = false;#region 移动控制/// <summary>/// 偏移裁剪过滤 防止超出边界/// </summary>/// <param name="target">目标偏移</param>/// <returns>实际偏移</returns>private Point OffsetClip(Point target){var tempX = target.X;var tempY = target.Y;if (tempX > 0){tempX = 0;}else if (tempX <= -BaseMap.PixelWidth + this.RenderSize.Width){tempX = -BaseMap.PixelWidth + this.RenderSize.Width;}if (tempY > 0){tempY = 0;}else if (tempY <= -BaseMap.PixelHeight + this.RenderSize.Height){tempY = -BaseMap.PixelHeight + this.RenderSize.Height;}return new Point(tempX, tempY);}/// <summary>/// 计算2个点的距离/// </summary>/// <param name="p1"></param>/// <param name="p2"></param>/// <returns></returns>private double GetDistance(Point p1, Point p2){return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));}/// <summary>/// 开始移动/// </summary>/// <param name="point"></param>private void StartMove(Point point){IsMove = true;ForntPoint = point;}/// <summary>/// 停止移动/// </summary>private void StopMove(){IsMove = false;}/// <summary>/// 使用新的点更新移动/// </summary>/// <param name="point"></param>private void UpdateMove(Func<Point> getCurrentPoint){if (!IsMove || IsManipulationOption) return;Point now = getCurrentPoint();var x = now.X - ForntPoint.X;var y = now.Y - ForntPoint.Y;var dis = Math.Sqrt(x * x + y * y);if (dis < 3){return;}if (dis > 200){return;}var tempX = OffsetX + x;var tempY = OffsetY + y;var clip = OffsetClip(new Point(tempX, tempY));OffsetX = clip.X;OffsetY = clip.Y;ForntPoint = now;}/// <summary>/// 使用新的点更新移动/// </summary>/// <param name="point"></param>private void UpdateMove(Vector offset){var x = offset.X;var y = offset.Y;var dis = Math.Sqrt(x * x + y * y);if(dis < 2){return;}if (dis > 200){return;}var tempX = OffsetX + x;var tempY = OffsetY + y;var clip = OffsetClip(new Point(tempX, tempY));OffsetX = clip.X;OffsetY = clip.Y;}private bool IsZooming = false;  // 是否正在缩放private DateTime ForntTime = DateTime.Now;  // 上次操作的事件private long SpanMiliseconds = 1000;  // 间隔的毫秒/// <summary>/// 更新缩放/// </summary>/// <param name="isBigger">是变大还是缩小</param>/// <param name="zoomCenterPoint">缩放中心点</param>private async Task UpdateZoom(bool isBigger, Point zoomCenterPoint){if (IsZooming) return;if ((DateTime.Now - ForntTime).TotalMilliseconds < SpanMiliseconds) return;IsZooming = true;var point = zoomCenterPoint;var lngLat = BaseMap.PixelConvertToLongitudeAndAtitude(point.X, point.Y);if (!isBigger){await BaseMap.ResetLayout(lngLat.X, lngLat.Y, BaseMap.Level - 1);}else{await BaseMap.ResetLayout(lngLat.X, lngLat.Y, BaseMap.Level + 1);}SetCenter(lngLat.X, lngLat.Y);IsZooming = false;ForntTime = DateTime.Now;}#endregion#region 鼠标控制的移动private void MMove(object sender, MouseEventArgs e){UpdateMove(() => e.GetPosition(MapControlGrid));}private void MDown(object sender, MouseButtonEventArgs e){if (e.ChangedButton == DragMouseButton){StartMove(e.GetPosition(MapControlGrid));}}private void MUp(object sender, MouseButtonEventArgs e){StopMove();}private void MLeave(object sender, MouseEventArgs e){StopMove();}#endregion#region 鼠标控制的缩放/// <summary>/// 注册了滚轮放大事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private async void MWheel(object sender, MouseWheelEventArgs e){var res = e.Delta;var point = e.GetPosition(sender as FrameworkElement);await UpdateZoom(res > 0, IsZoomAutoCenter ? point : ConvertToPixelPoint(CenterPoint));}#endregion/// <summary>/// 双指操作/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private async void Grid_ManipulationDeltaAsync(object sender, ManipulationDeltaEventArgs e){if (e.Manipulators.Count() < 2){IsManipulationOption = false;UpdateMove(e.DeltaManipulation.Translation);return;}var point1 = e.Manipulators.First().GetPosition(MapLayout);var point2 = e.Manipulators.Last().GetPosition(MapLayout);var point  = new Point((point1.X + point2.X) / 2, (point1.Y + point2.Y) / 2);IsManipulationOption = true;var scale = e.DeltaManipulation.Scale;if (scale.X < 1 && scale.Y < 1){await UpdateZoom(false, IsZoomAutoCenter ? point : ConvertToPixelPoint(CenterPoint));}else if (scale.X > 1 && scale.Y > 1){await UpdateZoom(true, IsZoomAutoCenter ? point : ConvertToPixelPoint(CenterPoint));}IsManipulationOption = false;}/// <summary>/// 多指操作开始/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Grid_ManipulationStarting(object sender, ManipulationStartingEventArgs e){e.ManipulationContainer = sender as FrameworkElement;e.Mode = ManipulationModes.All;}/// <summary>/// 多指操作结束/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Grid_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e){IsManipulationOption = false;}#endregion}

高德瓦片

高德地图的瓦片获取方式,前者lang可以通过zh_cn设置中文,en设置英文,size基本无作用,scl设置标注还是底图,scl=1代表注记,scl=2代表底图(矢量或者影像),style设置影像和路网,style=6为影像图,style=7为矢量路网,style=8为影像路网

public override string GetUri(int row, int column, int level)
{if (MapImage == MapImageType.RoadNetwork)return "http://webrd0" + (column % 4 + 1) + ".is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=" + column + "&y=" + row + "&z=" + level;elsereturn "http://webst0" + (column % 4 + 1) + ".is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x=" + column + "&y=" + row + "&z=" + level;
}

外部调用地图控件

<map:GisLayout BaseMap="{Binding Path=BaseMapLayout}" Fill="#50FF0000" DragMouseButton="Left"Areas="{Binding Path=IotBlockList}" CenterPoint="{Binding CenterPoint}"Level="{Binding BaseMapLayout.Level,Mode=OneWay}" MaxLevel="{Binding BaseMapLayout.MaxLevel,Mode=OneWay}"x:Name="Map" IsZoomAutoCenter="True"><map:GisLayout.Style><Style TargetType="{x:Type map:GisLayout}"><Style.Triggers><Trigger Property="LevelMinus" Value="0"><Setter Property="TextFontSize" Value="20"/></Trigger><Trigger Property="LevelMinus" Value="1"><Setter Property="TextFontSize" Value="15"/></Trigger><Trigger Property="LevelMinus" Value="2"><Setter Property="ItemVisibility" Value="Collapsed"/></Trigger></Style.Triggers></Style></map:GisLayout.Style><map:GisLayout.ItemTemplate><DataTemplate><StackPanel Orientation="Vertical" Visibility="{Binding Path=ItemVisibility, RelativeSource={RelativeSource AncestorType=map:GisLayout}}"><behaviour:Interaction.Triggers><behaviour:EventTrigger EventName="MouseLeftButtonDown"><behaviour:InvokeCommandAction Command="{Binding ClickCommand}"CommandParameter="{Binding Path=.}"/></behaviour:EventTrigger><behaviour:EventTrigger EventName="TouchDown"><behaviour:InvokeCommandAction Command="{Binding ClickCommand}"CommandParameter="{Binding Path=.}"/></behaviour:EventTrigger></behaviour:Interaction.Triggers><Image Source="../Resources/定位.png" Stretch="None" IsHitTestVisible="False"/><TextBlock Text="{Binding Name}" Foreground="Black" FontSize="{Binding Path=TextFontSize, RelativeSource={RelativeSource AncestorType=map:GisLayout}}" HorizontalAlignment="Center" VerticalAlignment="Center" IsHitTestVisible="False"/></StackPanel></DataTemplate></map:GisLayout.ItemTemplate>
</map:GisLayout>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SA8295P 源码分析】系列文章链接汇总 - 持续更新中

【SA8295P 源码分析】00 - 系列文章链接汇总 - 持续更新中 一、分区、下载、GPIO等杂项相关二、开机启动流程代码分析二、OpenWFD 显示屏模块三、Touch Panel 触摸屏模块四、QUPv3 及 QNX Host透传配置五、Camera 摄像头模块&#xff08;当前正在更新中...&#xff09;六、网络…

java八股文面试[数据结构]——List和Set的区别

List和Set是用来存放集合的接口&#xff0c;并且二者都继承自接接口Collection List 中的元素存放是有序的&#xff0c;可以存放重复的元素&#xff0c;检索效率较高&#xff0c;插入删除效率较低。 Set 没有存放顺序不能存放重复元素检索效率较低&#xff0c;插入删除效率较…

学习笔记230818---对于promise失败状态处理的重要性

问题描述&#xff1a; 在项目中经常会出现如上的问题&#xff0c;这是因为&#xff0c;用promise封装的接口或第三方组件方法&#xff0c;如果只对成功的状态做处理&#xff0c;就会造成页面出错&#xff0c;报error。 解决方法 then()的末尾加上.catch(()>{})对失败的状态…

C++类和对象----封装(观看黑马教程整理的笔记)

1、简介 C面向对象的三大特性为&#xff1a;封装、继承、多态 C认为万事万物都皆为对象&#xff0c;对象上有其属性和行为 例如&#xff1a; ​ 人可以作为对象&#xff0c;属性有姓名、年龄、身高、体重…&#xff0c;行为有走、跑、跳、吃饭、唱歌… ​ 车也可以作为对象…

MySQL索引可能失效之or、is null、is not null、不等于(!=,<>)、联合索引

1、如果 A,B 两列都有索引&#xff0c;那么 select * from Table where Aa or Bb; 会走索引吗&#xff1f; 答案&#xff1a;会&#xff0c;因为 A,B都有索引&#xff1b; 2、如果 A,B有索引&#xff0c;但是C没有索引&#xff1b; select * from Table where Aa or Bb …

线程与进程,你真得理解了吗

线程与进程&#xff0c;你真得理解了吗 1 进程与线程的关系和区别2 并行与并发3 线程共享了进程哪些资源 相信大家面试时一定没少被一个问题刁难&#xff0c;那就是进程和线程的区别是什么&#xff1f;这个问题延申开来并不像表面那么简单&#xff0c;今天就来深入一探。 开始…

无涯教程-PHP - 标量函数声明

在PHP 7中&#xff0c;引入了一个新函数&#xff0c;即标量类型声明。标量类型声明有两个选项- Coercive - 强制性是默认模式。Strict - 严格模式必须明确提示。 可以使用上述模式强制执行以下类型的函数参数- intfloatbooleanstringinterfacesarraycallable 强制模…

【Unity】如何制作小地图

我们为什么要制作小地图呢&#xff1f; 原因很简单&#xff1a; 导航和定位&#xff1a;小地图可以显示玩家当前位置以及周围环境的概览。这使得玩家能够更好地导航和定位自己在游戏中的位置&#xff0c;找到目标或避开障碍物。场景了解&#xff1a;通过小地图&#xff0c;玩…

Windows10上VS2022单步调试FFmpeg 4.2源码

之前在 https://blog.csdn.net/fengbingchun/article/details/103735560 介绍过通过VS2017单步调试FFmpeg源码的方法&#xff0c;这里在Windows10上通过VS2022单步调试FFmpeg 4.2的方法&#xff1a;基于GitHub上ShiftMediaProject/FFmpeg项目&#xff0c;下面对编译过程进行说明…

渗透测试面试题汇总(附答题解析+配套资料)

注&#xff1a;所有的资料都整理成了PDF&#xff0c;面试题和答案将会持续更新&#xff0c;因为无论如何也不可能覆盖所有的面试题。 一、思路流程 1、信息收集 a、服务器的相关信息&#xff08;真实ip&#xff0c;系统类型&#xff0c;版本&#xff0c;开放端口&#xff0c;…

vue 实现腾讯地图搜索选点功能(附加搜索联想功能)

注意&#xff1a;开发环境、正式环境需在腾讯地图配置ip地址白名单、域名白名单 封装map组件&#xff1a; <template><iframe width"100%" style"border: none;width: 100%;height: 100%;" :src"map_src"></iframe> </t…

新服务器基本环境下载conda + docker + docker-compose + git

文章目录 Ubuntu 允许root用户登录 centos无所谓condadockerubuntucentos docker-compose官方下载docker-compose国内镜像 gitUbuntuCentos Ubuntu 允许root用户登录 centos无所谓 # 以普通用户登录系统&#xff0c;创建root用户的密码 sudo passwd root# SSH 放行 sudo sed -…

Java免费自学网站墙裂推荐!!!!

最近&#xff0c;常有一些读者问我&#xff1a;“有没有什么推荐的Java学习网站啊&#xff1f;” 因为一直没有时间&#xff0c;所以我之前也是让大家上知乎、搜索引擎搜一下就好了。 但是&#xff0c;我深知不能这样&#xff0c;应该拿出更真诚的态度带来优质的内容。 于是…

uni-app开启gzip配置

指令&#xff1a;npm install webpack4.46.0 --save-dev 指令&#xff1a;npm install compression-webpack-plugin6.1.1 --save-dev vue.config.js const CompressionWebpackPlugin require(compression-webpack-plugin);module.exports {configureWebpack: config > {…

IntelliJ IDEA 编辑器的全局搜索中使用正则表达式

打开 IntelliJ IDEA 编辑器。 使用快捷键 Ctrl Shift F&#xff08;Windows / Linux&#xff09;或 Cmd Shift F&#xff08;Mac&#xff09;打开全局搜索窗口。在搜索框中输入要搜索的内容&#xff0c;例如&#xff1a;“设备【】已经绑定网关”。在搜索框旁边的 “.*” …

轻松搭建远程Node.js服务端,让你的应用在公共网络中畅行无阻!

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…

linux安装 MySQL8 并配置开机自启动

目录 1.下载 mysql 安装包 2.上传并解压 mysql 3.修改 mysql 文件夹名 4.创建mysql 用户和用户组 5.数据目录 &#xff08;1&#xff09;创建目录 &#xff08;2&#xff09;赋予权限 6.初始化mysql &#xff08;1&#xff09;配置参数 &#xff08;2&#xff09;配置环…

ChatGPT应用于高职教育的四大潜在风险

目前&#xff0c;ChatGPT还是一种仍未成熟的技术&#xff0c;当其介入高职教育生态后&#xff0c;高职院校师生在享受ChatGPT带来的便利的同时&#xff0c;也应该明白ChatGPT引发的风险也会随之进入高职教育领域&#xff0c;如存在知识信息、伦理意识与学生主体方面的风险与挑战…

爬虫异常处理:异常捕获与容错机制设计

作为一名专业的爬虫程序员&#xff0c;每天使用爬虫IP面对各种异常情况是我们每天都会遇到的事情。 在爬取数据的过程中&#xff0c;我们经常会遇到网络错误、页面结构变化、被反爬虫机制拦截等问题。在这篇文章中&#xff0c;我将和大家分享一些关于如何处理爬虫异常情况的经…

ChatGpt 从入门到精通

相关资源下载地址: 基于ChatGPT的国际中文语法教学辅助应用的探讨.pdf 生成式人工智能技术对教育领域的影响-关于ChatGPT的专访.pdf 电子-从ChatGPT热议看大模型潜力.pdf 从图灵测试到ChatGPT——人机对话的里程碑及启示.pdf 正文 ChatGPT 是一种强大的自然语言处理模型&…