Bentley二次开发教程24-交互式类工具

交互式工具概念简述

本次内容主要涉及到交互式工具的使用,在MicroStation中,超过一半的功能都是以交互式工具的形式而存在的,因此交互式工具在MicroStation二次开发中便显得非常重要。当我们的鼠标或键盘在视图中产生交互操作时,不同的动作会调用不同的回调函数。这种方式是“面向过程”编程思想的产物,在“面向对象”的编程思想下,SDK封装了DgnTool、DgnPrimitiveTool、DgnElementSetTool等类来供各位使用。我们只要从相应的类派生一个我们自己的类,根据交互式工具的不同功能,重写一些基类的成员函数很容易就能实现我们的交互式工具。
在这里插入图片描述
MicroStation SDK案例地址:
C:\Program Files\Bentley\MicroStationCONNECTSDK\examples\Elements\exampletool(默认路径)
这张图中是我们从MicroStationAPI.chm中截取的DgnElementSetTool在整个DgnTool工具类中的层次关系。我们可以看到DgnTool是所有工具类最顶层的基类,它定义了交互式工具使用过程中大部分的鼠标和键盘相关的事件处理函数。而DgnElementSetTool的基类除了DgnPrimitiveTool以外还有IRedrawOperation和ModifyOp这两个基类,从DgnPrimitiveTool继承了视图及鼠标键盘等交互事件的响应功能,从IRedrawOperation继承实现了元素动态重绘的功能,从ModifyOp继承实现了元素修改逻辑的功能,而DgnElementSetTool自身又添加了元素选取(包括点选、划选框选、选择集以及围栅)的功能。
在这里插入图片描述
图中是DgnTool常用事件相关成员虚函数。我们从DgnTool直接或间接派生了我们自己的类,重写了某一事件对应的虚函数时,如果对应事件被触发,系统后台会调用我们重写的虚函数。例如如果我们重写了OnDataButton函数的话,当我们在视图中单击鼠标左键时,重写OnDataButton函数就会被调用。我们的交互式工具就是在这些事件处理函数中根据用户输入的信息,而完成各种复杂的交互功能。
简单的来说,所谓继承就是拥有基类的所有功能,打个比方,就像是ORD中除了拥有MicroStation软件的所有功能,还具有道路专业的一些特色功能。对于交互式工具的使用,首先需要明确自身希望实现的最终目标,如果您只是需要做一些元素单选,或需要配合键盘Ctrl,Shift等做简单交互时,使用Dgntool即可;若您需要具有视图及鼠标键盘等交互事件,那么使用DgnPrimitiveTool即可;若需实现元素的动态绘制,元素修改及框选,划选功能,那么需要使用DgnElementSetTool实现既定目标。因为三个工具依次继承,后者拥有前者的功能,因此也会导致其中机制越来越复杂,因此在这里建议:按照实际需求选择满足功能需求的交互式工具
关于交互式工具中可重写的虚方法为了方便理解大致可归为三类,分别为流程类方法,交互类方法,控制类方法。其中,流程类方法指在工具执行流程导致触发的方法,比如说,当我们将交互式工具加载后,会按照流程触发OnPostInstall( ),在这个方法中我们可以对交互式工具中可能需要使用到的变量进行声明或初始化;交互类方法指的是其方法的触发与流程无关,主要在用户执行执行操作便会自动触发,比如说,在用户点击确认键(默认为左键)时便会触发事件,调用该方法;控制类方法,指的是用于控制流程的方法,比如说,当我们需要进行动态绘制时,首先需要使用BeginDynamics( )开启动态绘制,此时当我们的鼠标在屏幕中移动时才会触发OnDynamicFrame( ),其中可供我们将在动态绘制过程中需要实现的业务功能写入其中。
在这里插入图片描述
关于DgnElementSetTool的交互逻辑非常复杂,如果您第一次接触该工具,其中纷繁复杂的交互逻辑与众多可重写的虚方法会让您有一种无法下手的感觉。在这里需要感谢符老师与郭老师对MicroStation中交互式工具的详细阐述,以下为根据LearnDgnTool-05_DgnElementSetTool详解将文字进行梳理并转换为流程导图的形式,更加直观的展示了DgnElementSetTool的交互逻辑。

DgnElementSetTool流程导图

流程导图
在这里插入图片描述

对于我们的日常开发来说,其实并不需要将其中所有的重写虚方法面面俱到的掌握,其中只需要根据实际的业务需求,分析应用场景,抽象出工具的交互流程后,对个别虚方法进行重写并添加业务功能即可。

交互式工具案例

动态绘制绘制圆Demo

该工具涉及左右键点击,动态绘制等操作。
需求说明:
对圆实现动态绘制并可进行重复操作,并具有取消绘制功能。
要求:
首先点击确定圆心位置,然后随着鼠标拖动以鼠标与圆心之间的距离为半径动态绘制圆,确认圆半径后点击左键生成圆,同时全程需要根据不同状态提供相应的提示说明。
分析:
根据需求说明及要求,该工具主要涉及到的功能及设置有:

  • 在执行命令加载工具后输出“选择圆心”的提示(OnPostInstall)
  • 点击左键后记录圆心坐标,启动动态绘制并输出“选择终点”的提示(OnDataButton)
  • 当需要退出程序时,点击右键退出程序(OnResetButton)
  • 在动态绘制的过程中根据圆心坐标与鼠标停留的坐标点绘制面向视图的椭圆元素并在视图中展示(OnDynamicFrame)
  • 当圆心坐标点输入错误需要撤回时,点击右键,此时对储存圆坐标信息的列表执行清空,并输出“选择圆心”的提示,重新选择圆心坐标(OnResetButton)
  • 在确认圆心点与圆半径无误后点击左键,此时结束动态绘制并根据信息生成圆绘制结果(OnDataButton)
    从以上分析可以看出,我们在该交互式工具中使用的OnDataButton与OnResetButton在不同使用场景下执行了两种不同的功能,因此我们需要使用某种机制来区分同一种方法的不同业务功能,在本案例中采用的方法为根据列表中储存的坐标值个数执行不同的业务功能。
    在这里插入图片描述
    基于以上分析,我们将对应的业务功能写入重写的虚函数中,创建出用于绘制圆的交互式工具。
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.GeometryNET;
using Bentley.MstnPlatformNET;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InteractiveToolsIntroduction.Tools
{
    /*
     * 参考资料:
     * https://communities.bentley.com/communities/other_communities/bdn_other_communities/w/chinabdn-wiki/45167/learndgntool-05_5f00_dgnelementsettool
     */
    class CreateEllipse : DgnElementSetTool
    {
        private DgnModel m_dgnModel;
        private List<DPoint3d> m_pos;

        public CreateEllipse(int toolId, int prompt) : base(toolId, prompt)
        {
            
        }

        public static void InstallNewInstance()//交互式工具的入口函数,用于声明工具并进行加载
        {
            CreateEllipse primitiveTool = new CreateEllipse(0, 0);//创建实例
            primitiveTool.InstallTool();//加载工具       
        }

        protected override void OnPostInstall()//工具激活后执行
        {            
            string tips = "Please select start point:";//设置提示语
            NotificationManager.OutputPrompt(tips);//将提示语输出到提示框中

            m_dgnModel = Session.Instance.GetActiveDgnModel();//获得当前的模型空间
            m_pos = new List<DPoint3d>();//创建用于储存坐标的列表            
        }

        /*
         * 如果我们对通过参数传递进来的元素进行修改,并且返回SUCCESS的话,在_DoOperationForModify
         * 中会用修改后的元素替换掉原来的元素,当然前提是_IsModifyOriginal返回true。否则的话会直接
         * 把修改后的元素重新添加到Dgn文件中。
         */
        public override StatusInt OnElementModify(Element element)
        {            
            return StatusInt.Error;
        }

        protected override bool OnDataButton(DgnButtonEvent ev)//点击确认键(默认为左键)后触发
        {
            if(m_pos.Count()==0)//判断列表中点个数,若列表中没有坐标点
            {
                m_pos.Add(ev.Point);//添加捕捉点

                string tips = "Please select end point:";//设置提示语
                NotificationManager.OutputPrompt(tips);//将提示语输出到提示框中

                BeginDynamics();//启动动态绘制
            }
            else
            {
                EndDynamics();//关闭动态绘制
                m_pos.Add(ev.Point);//添加捕捉点
                EllipseElement element = CreateEllipseElement(m_pos[0], m_pos[1]);//创建椭圆元素
                element.AddToModel();//将椭圆元素写入模型
                m_pos.Clear();//清空列表

                string tips = "Please select start point:";//设置提示语
                NotificationManager.OutputPrompt(tips);//将提示语输出到提示框中
            }
            return true;
        }

        protected override void OnDynamicFrame(DgnButtonEvent ev)//动态绘制时触发
        {
            EllipseElement element = CreateEllipseElement(m_pos[0],ev.Point);//创建椭圆元素
            if (null == element)//若未成功生成椭圆元素
                return;//返回

            RedrawElems redrawElems = new RedrawElems();//使用元素用于动态绘制
            redrawElems.SetDynamicsViewsFromActiveViewSet(Session.GetActiveViewport());//设置视角
            redrawElems.DrawMode = DgnDrawMode.TempDraw;//设置绘制模式
            redrawElems.DrawPurpose = DrawPurpose.Dynamics;//设置绘制目标            
            redrawElems.DoRedraw(element);//使用元素用于动态绘制
        }     

        protected override bool OnResetButton(DgnButtonEvent ev)//点击重置键(默认为右键)触发
        {
            if(m_pos.Count()==0)//判断列表中点个数,若列表中没有坐标点则退出
            {
                ExitTool();//退出工具
            }
            else
            {
                EndDynamics();//停止动态捕捉
                m_pos.Clear();//清空列表中的数据

                string tips = "Please select start point:";//设置提示语
                NotificationManager.OutputPrompt(tips);//将提示语输出到提示框中
            }
            return true;//返回
        }

        protected override void OnRestartTool()//重启工具时触发
        {
            InstallNewInstance();//重新启动交互式工具
        }

        private EllipseElement CreateEllipseElement(DPoint3d startPo,DPoint3d endPo)
        {            
            double distance = startPo.Distance(endPo);//确定绘制圆的半径
            EllipseElement ellipse = new EllipseElement(m_dgnModel, null, DPoint3d.Zero, distance, distance, DMatrix3d.Identity);//创建椭圆元素(长轴=短轴,即圆)

            Session.GetActiveViewport().GetRotation().TryInvert(out DMatrix3d invertMatrix);//获得当前视角的旋转转置矩阵

            DTransform3d dTransform3D = new DTransform3d(invertMatrix);//使用旋转矩阵创建几何变换
            TransformInfo transform = new TransformInfo(dTransform3D);//使用几何变换创建变换信息
           
            ellipse.ApplyTransform(transform);//对椭圆元素应用变换

            dTransform3D = DTransform3d.FromTranslation(startPo);//创建用于平移的几何变换
            transform = new TransformInfo(dTransform3D);//使用几何变换创建变换信息

            ellipse.ApplyTransform(transform); //对椭圆元素应用变换

            return ellipse;//返回椭圆
        }
    }
}

在这里插入图片描述

修改实体元素颜色Demo

该工具涉及批量选择(框选/划选),单项选择(按住Ctrl点选)正选/反选元素的操作。
需求说明:
使用工具采用框选/划选/点选的方法选择元素,并对获取到的元素集执行颜色修改操作。
要求:
在使用过程中可以对选择集中的元素进行添加或删除。
分析:
根据需求说明及要求,该工具主要涉及到的功能及设置有:

  • 在执行命令加载工具后输出“选择需要修改颜色的元素”提示(OnPostInstall)
  • 保证在选择元素阶段可以由左键拖拽框选/点Alt后切换为划选/点Ctrl点选的方式正选/反选元素,在选择元素不为空后点击左键进行下一步操作(AllowDragSelect,WantAdditionalLocate)
  • 无需点击左键才开始处理元素(NeedAcceptPoint)
  • 在确定选择的元素后,点击左键接受,此时对选择集中的元素进行颜色修改与修改结果输出(OnModifyComplete)
  • 点击重置键(默认右键)时退出该工具(OnResetButton)
    在这里插入图片描述
    基于以上分析,我们将对应的业务功能写入重写的虚函数中,创建出用于颜色修改的交互式工具。在这里我们需要注意,关于选择元素的行为是根据我们在重写WantAdditionalLocate( )中进行设置的,该方法是用于判断是否需要拾取元素,而拖拽,Ctrl点选行为是我们在重写其中的内容控制的,由此看出通过重写虚方法赋予交互式工具极大的自由度与可定制性。
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.MstnPlatformNET;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InteractiveToolsIntroduction.Tools
{
    class ChangeSolidColorTool : DgnElementSetTool//Case: ChangeSolidColorTool
    {
        private DgnModelRef m_dgnModelRef;
        private int m_count;

        public ChangeSolidColorTool(int toolId, int prompt) : base(toolId, prompt)
        {

        }

        public static void InstallNewInstance()//交互式工具的入口函数,用于声明工具并进行加载
        {
            ChangeSolidColorTool primitiveTool = new ChangeSolidColorTool(0, 0);//创建实例
            primitiveTool.InstallTool();//加载工具       
        }

        /*
         * 如果我们对通过参数传递进来的元素进行修改,并且返回SUCCESS的话,在_DoOperationForModify
         * 中会用修改后的元素替换掉原来的元素,当然前提是_IsModifyOriginal返回true。否则的话会直接
         * 把修改后的元素重新添加到Dgn文件中。
         */
        public override StatusInt OnElementModify(Element element)
        {                        
            return StatusInt.Error;
        }       

        protected override void OnRestartTool()//重启工具时触发
        {
            InstallNewInstance();//重新启动交互式工具
        }

        protected override void OnPostInstall()//工具激活后执行
        {
            string tips = "Please select solids to be filled:";//设置提示语
            NotificationManager.OutputPrompt(tips);//将提示语输出到提示框中

            m_dgnModelRef = Session.Instance.GetActiveDgnModelRef();//获得当前激活的模型            
            m_count = 0;//计数清零
        }

        protected override bool WantAdditionalLocate(DgnButtonEvent ev)//判断当前是否需要拾取元素
        {
            if(ev==null)//若没有选择到元素
            {
                return true;
            }
            if(ev.IsControlKey)//若检测到按动Ctrl行为
            {
                return true;
            }
            if(ElementAgenda.GetCount()==0)//若选择集中没有元素
            {
                return true;
            }
            return false;
        }

        protected override bool OnResetButton(DgnButtonEvent ev)//重置键(默认右键)点击时触发
        {
            ExitTool();//退出交互式工具
            return true;
        }

        protected override UsesDragSelect AllowDragSelect()//判断是否要启用框选或者划选
        {
            return UsesDragSelect.Box;//使用框选选择元素
        }

        protected override bool NeedAcceptPoint()//判断是否需要用户再点击左键才开始处理元素
        {
            return false;
        }

        protected override bool OnModifyComplete(DgnButtonEvent ev)//修改完毕,对选择集中的元素进行处理
        {
            ChangeSolidsColor();//修改实体填充颜色
            OuputFilledResultMessage();//输出填充结果
            return base.OnModifyComplete(ev);
        }

        private void ChangeSolidsColor()
        {
            for (uint i = 0; i < ElementAgenda.GetCount(); i++)//遍历选择集中的元素
            {
                Element element = SetSolidColor(ElementAgenda.GetEntry(i));//对元素设置实体填充
                if (element != null)//判断元素是否被成功填充
                {
                    element.ReplaceInModel(ElementAgenda.GetEntry(i));//替换模型中的元素
                }
            }
        }

        private Element SetSolidColor(Element element)
        {
            if (element.ElementType == MSElementType.Solid)//判断元素类型是否为Solid
            {
                ElementPropertiesSetter setter = new ElementPropertiesSetter();//修改元素属性
                setter.SetColor(3);//设置索引值3的颜色为元素颜色
                setter.Apply(element);//将设置应用于指定元素
                m_count++;//计数加一
                return element;
            }
            return null;
        }

        private void OuputFilledResultMessage()
        {
            string tips = "Filled " + m_count + " solids.";//设置提示语
            MessageCenter.Instance.ShowInfoMessage(tips, tips, false);//将提示语输出到提示框中
        }
    }
}

在这里插入图片描述

围栅剪切Demo

该工具涉及使用围栅获取元素,使用激活的围栅剪切元素的操作。

需求说明:
在绘制剪切围栅后,使用交互式工具对围栅中的元素进行剪切。
分析:
根据需求说明,该工具主要涉及到的功能及设置有:

  • 在执行命令加载工具后输出“确认围栅存在”的提示(OnPostInstall)
  • 确定获取元素的方式为从围栅中获取(SetElementSource)
  • 点击重置键(默认右键)时退出该工具(OnResetButton)
  • 无需用户输入额外的确认点才开始处理选择集元素(NeedPointForSelection)
  • 无需点击左键才开始处理元素(NeedAcceptPoint)
  • 确定使用激活围栅(UseActiveFence)
  • 保证通过围栅获取元素(AllowFence)
  • 确认后执行元素修改流程(ProcessAgenda)
    在这里插入图片描述
    在本案例中,需要对交互式工具中获取元素的方法与对元素的操作进行设置。其中,在激活工具时触发OnInstall( ),设置元素来源为通过围栅获得SetElementSource(ElementSource.Fence),重写NeedPointForSelection( )并返回false设置用户无需输入额外的确认点即开始处理选择集元素,重写NeedAcceptPoint( )并返回false设置无需用户再点击左键即开始处理元素,重写UseActiveFence( )返回true设置使用激活的围栅,重写AllowFence( )并返回UsesFence.Required设置必须通过围栅获取元素。同时,在OnPostInstall( )写入初始化模型与输出提示的内容,在OnResetButton( )中写入退出交互式工具的命令,在ProcessAgenda( )中执行使用激活围栅对元素进行切割的业务功能。
using Bentley.DgnPlatformNET;

        protected override bool OnResetButton(DgnButtonEvent ev)//点击重置键(默认为右键)触发
        {
            ExitTool();
            return true;
        }

        protected override StatusInt ProcessAgenda(DgnButtonEvent ev)//执行元素修改的流程
        {
            int count= ClipElementsByFence();//使用围栅对元素进行剪切
            OuputFilledResultMessage(count);//输出剪切结果
            return StatusInt.Success;
        }

        private int ClipElementsByFence()
        {
            int count = 0;//输出生成剪切元素个数
            FenceParameters fenceParams = new FenceParameters(m_dgnModelRef, DTransform3d.Identity);//声明围栅信息
            FenceManager.InitFromActiveFence(fenceParams, true, true, FenceClipMode.Original);//使用围栅信息初始化围栅       
            for (uint i = 0; i < ElementAgenda.GetCount(); i++)//遍历元素容器中的元素
            {
                ElementAgenda insideElems = new ElementAgenda();//声明元素容器
                ElementAgenda outsideElems = new ElementAgenda();//声明元素容器
                Element element = ElementAgenda.GetEntry(i);//获得元素容器中的元素                    

                FenceManager.ClipElement(fenceParams, insideElems, outsideElems, element, FenceClipFlags.Optimized);//对围栅内的元素进行剪切
                for (uint j = 0; j < outsideElems.GetCount(); j++)//遍历围栅切割后生成的外围元素
                {
                    using (ElementCopyContext copyContext = new ElementCopyContext(m_dgnModelRef))//复制元素
                    {
                        Element elemToCopy = outsideElems.GetEntry(j);//获得切割后生成的外围元素
                        copyContext.DoCopy(elemToCopy);//将元素复制到指定模型中

                        count++;//剪切个数增加
                    }
                }
                for (uint j = 0; j < insideElems.GetCount(); j++)//遍历围栅切割后生成的外围元素
                {
                    using (ElementCopyContext copyContext = new ElementCopyContext(m_dgnModelRef))//复制元素
                    {
                        Element elemToCopy = insideElems.GetEntry(j);//获得切割后生成的外围元素
                        copyContext.DoCopy(elemToCopy);//将元素复制到指定模型中                        
                    }
                }
            }
            FenceManager.ClearFence();//清除围栅
            return count;
        }

        private void OuputFilledResultMessage(int count)
        {
            string tips = count + " elements clipped.";//设置提示语
            MessageCenter.Instance.ShowInfoMessage(tips, tips, false);//将提示语输出到提示框中
        }
    }    
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

各平台奇怪问题备忘录

微信小程序 小程序报错Page 页面路径 has not been register yet 描述&#xff1a;uniapp做微信小程序开发时&#xff0c;新增某页面后&#xff0c;小程序跳转该页面报错Page 页面路径 has not been register yet 已知&#xff1a;page.json已添加该页面&#xff0c;小程序a…

【Linux】文件目录及路径表示

1. Linux目录结构 在 Linux 系统中&#xff0c;有几个目录是比较重要的&#xff0c;平时需要注意不要误删除或者随意更改内部文件。 /etc&#xff1a; 这个是系统中的配置文件&#xff0c;如果更改了该目录下的某个文件可能会导致系统不能启动。 /bin, /sbin, /usr/bin, /usr…

vue快速入门(四十一)组件通信-依赖注入

注释很详细&#xff0c;直接上代码 上一篇 新增内容 祖先组件向下传值子代组件接受数据 源码 App.vue <template><div id"app"><sonComponent></sonComponent></div> </template> <script> import sonComponent from &qu…

python绘制随机地形地图

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 当我们谈论计算机编程中的地图生成时&#xff0c;通常会想到游戏开发、仿真模拟或者数据可视…

vue3 修改路由中的meta属性

有些时候可能需要在路由跳转前后修改meta里面的相关属性值&#xff0c;这个时候就需要使用钩子函数&#xff08;路由守卫&#xff09;&#xff0c;钩子函数有全局钩子&#xff0c;局部组件钩子函数以及路由配置里面的钩子函数 &#xff08;这些也叫路由守卫&#xff09; 1.全局…

python数字验证码自动识别

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在网络上&#xff0c;许多网站和应用程序使用验证码&#xff08;Completely Automated Publ…

Ubuntu系统开机长

Ubuntu系统开机长 1. 检查开机自启动软件的所占时间2. 将耗时最高的禁止开机自启动 1. 检查开机自启动软件的所占时间 systemd-analyze blame2. 将耗时最高的禁止开机自启动 sudo systemctl disable networking.service这个耗时是有阈值的&#xff0c;一般大于15s的算&#x…

【数据结构与算法】8.二叉树的基本概念|前序遍历|中序遍历|后序遍历

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

vue封装请求、合并js、合并多个js

vue封装请求、合并js、合并多个js 作为一个后端开发&#xff0c;写前端时发现&#xff0c;每次导入api接口都会有一堆代码&#xff0c;像下面这样&#xff1a; import {footprintList, footprintDelete} from /api/userApi.js import {addressList} from /api/userApi.js impor…

设置Linux开发板开机自启动QT程序的报错解决办法

设置Linux开发板开机自启动QT程序报错解决办法 设置开发板开机自启动QT 打开 /etc/init.d/rsC 文件&#xff0c;添加以下内容 cd / ./my_start_run.shmy_start_run.sh 是自己编写的自启动脚本&#xff0c;内容例如下&#xff1a;(也可以将这些直接写到 /etc/init.d/rsC 文件…

【算法刷题 | 贪心算法02】4.24(摆动序列)

文章目录 3.摆动序列3.1题目3.2解法&#xff1a;贪心3.2.1贪心思路3.2.2代码实现 3.摆动序列 3.1题目 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。 第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素…

嵌入式总线协议基础教学

在嵌入式系统设计中&#xff0c;总线协议&#xff08;bus protocols&#xff09;扮演着至关重要的角色&#xff0c;它们定义了设备如何在共享通信路径上交换数据。 本文将介绍两种常见的嵌入式总线协议&#xff1a;IC&#xff08;Inter-Integrated Circuit&#xff09;和SPI&a…

BFS解决FloodFill算法:(Leetcode:733. 图像渲染)

题目链接&#xff1a;733. 图像渲染 - 力扣&#xff08;LeetCode&#xff09; 使用广度优先遍历算法解决该问题&#xff1a; 从初始位置开始搜索&#xff0c;初始位置符合条件就入栈&#xff0c;并修改初始位置值。初始位置出栈。 再从初始位置开始广度优先搜索&#xff08;…

IDM下载器安装cmd注册

一、下载注册 安装包去IDM官网下载最新的试用版即可 或者直达百度网盘下载&#xff08;担心被河蟹&#xff0c;放在txt中了&#xff09;包含IDM下载器安装包和注册软件 IDM下载器安装包和注册软件下载地址链接 https://download.csdn.net/download/qq_31237581/89215452 如果…

sscanf和scanf区别

sscandf 从字符串中提取数据 scanf 标准输入流读取数据 int num; sscanf("42", "%d", &num);float f; sscanf("3.14", "%f", &f);char str[20]; sscanf("Hello, World!", "%s", str);int a, b; sscanf(…

vue3 引入@tsparticles/vue3和@tsparticles/slim 实现粒子特效

1.安装&#xff1a; yarn add tsparticles/vue3 tsparticles/slim2.main.ts 引入 import Particles from "tsparticles/vue3"; import { loadSlim } from "tsparticles/slim";app.use(Particles as any, {init: async (engine: any) > {await loadSli…

POJO,Entity,model,domain,view,DTO,VO,Param这些分别都是什么含义?怎样理解?

目录 1. 前言 2. POJO的含义 3. entity(实体) 4. model(模型) 5. domain(域) 6. view(视图) 7. DTO(数据传输对象) 8. VO(真正视图层) 9. Param(参数) 10. 总结 1. 前言 在日常开发的过程中&#xff0c;如果我们接手一个新的项目之后&#xff0c;通常会有各种各样的…

edu邮箱官方购买渠道手把手选购指南记录

教育优惠&#xff0c;是一项针对于在校大学生和教职员工推出的特殊优惠活动。一些公司会将旗下产品或服务以一定的折扣&#xff0c;甚至免费提供给高校师生。想想自己上大学的时候啥都不知道,毕业后才发现浪费了这么多优秀的资源.如果你还是一名在校大学生&#xff0c;那么就不…

40. 【Android教程】AsyncTask:异步任务

在前面的章节有提到过&#xff0c;Android 系统默认会在主线程&#xff08;UI 线程&#xff09;执行任务&#xff0c;但是如果有耗时程序就会阻塞 UI 线程&#xff0c;导致页面卡顿。这时候我们通常会将耗时任务放在独立的线程&#xff0c;然后通过 Handler 等线程间通信机制完…

扁平与圆形Cat6网线:区别与选择指南

&#x1f335;在构建家庭或办公室网络时&#xff0c;选择合适的网线类型至关重要。Cat6网线因其高速传输性能而广受欢迎&#xff0c;但在购买时&#xff0c;您可能会发现市场上有两种不同形状的Cat6网线&#xff1a;扁平和圆形。本文将探讨这两种网线的区别&#xff0c;并提供选…