JAVA代码 实现定位数据动态聚集并绘制多边形区域
文章目录
- 思路
- 1、限制聚合距离
- 2、绘制多边形区域
- 3、多边形区域之间合并
- 4、多边形定边点
- 4、逻辑流程
- 一些性能上的优化
- 1、多边形设置圆心
- 2、采用分支合并思路
- 3、清理聚集较分散区域
- 合理性处理
- 1、解决多边形内凹角问题
- 2、解决定边点插入位置问题
- 3、多边形区域扩展
- 成果展示
最近有根据一堆离散的报警数据(内部包含经纬度 报警类型)需要聚合出每个报警发生的区域需求,比如 超速报警 聚集点有哪些,疲劳驾驶报警有哪些等等,个人没有采用已成型的算法 比如DBSCAN,而是自己实现

思路
为了让聚合的区域更精确,以及聚合的区域过大,我们采取了如下措施
1、限制聚合距离
何为限制聚合距离呢,就是定位点与定位点间 或定位点与多边形区域之间设置距离限制,如果点与点 或点与多边形距离小于设置阈值,则点加入该区域,否则成都一个独立区域?
2、绘制多边形区域
为了避免区域内非聚集空白区过多,我们取消了圆形区域,决定基于聚集的点形成多边形区域
3、多边形区域之间合并
为什么多边形区域之间需要合并呢,随着区域的增多,可能一个点同时与多个多边形区域距离符合阈值需要加入,那此时,对应的多边形就需要合并在一起组成新的区域
4、多边形定边点
组成多边形我们就使用定位数据点,并按顺序存入,最后前端根据定位点顺序绘制出多边形(A>B>C) 那么前端就会基于 A>B B>C C>A 绘制出一个三角形区域
报警模型
/*** @author lei* @create 2023-02-27 15:51* @desc**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Alarm {private Integer vehicleId;@ApiModelProperty("经度")private Integer longitude;@ApiModelProperty("纬度")private Integer latitude;private String pointName;private Integer alarmType;public Alarm(Integer vehicleId, Integer longitude, Integer latitude, String pointName) {this.vehicleId = vehicleId;this.longitude = longitude;this.latitude = latitude;this.pointName = pointName;}
}
4、逻辑流程
基于当前定位点循环当前所有的多边形区域,与区域元素进行判断,满足则加入(contine区域列表并记录已有区域)并与剩下区域列表中区域依次比对,不满足则新建区域,已有满足区域但还有匹配区域则两个区域进行合并
private static boolean collectCalc(List<PolygonMapArea> polygonMapAreas, Alarm curAlarm, Double collectDistance) {// 是否需要初始化新多边形boolean needInitNewPolygon = true;PolygonMapArea belongedArea = null;MapPoint curPoint = new MapPoint(curAlarm.getLongitude(), curAlarm.getLatitude(), curAlarm.getPointName());for (PolygonMapArea polygonMapArea : polygonMapAreas) {if (!polygonMapArea.isLive()) {continue;}// 先算圆心到当前点距离是否超过指定阈值,超过则进行下一个多边形判断double distance = AreaUtil.distance(polygonMapArea.getCycleCenter(), curPoint);if (distance > polygonMapArea.getRadius() + collectDistance) {continue;}if (polygonMapArea.getPoints().getSize() == 1) {needInitNewPolygon = false;if (belongedArea == null) {// 归属当前聚集点,计算最大经纬度与圆心polygonMapArea.getAlarms().add(curAlarm);polygonDrawCircle(curPoint, polygonMapArea, distance);polygonMapArea.setBelong(true);belongedArea = polygonMapArea;} else {mergePolygonArea(belongedArea, polygonMapArea, collectDistance);}continue;}// 属于当前多边形扫描圆距离,则进行多边形内外部判断boolean inPolygonArea = AreaUtil.locateInPolygonArea(curPoint, polygonMapArea);if (inPolygonArea) {// 当前点在现多边形内needInitNewPolygon = false;if (belongedArea == null) {polygonMapArea.getAlarms().add(curAlarm);polygonMapArea.setBelong(true);belongedArea = polygonMapArea;} else {mergePolygonArea(belongedArea, polygonMapArea, collectDistance);}continue;}// 当前点在多边形之外,则与各边进行判断,找到与其相邻最近边,如距离小于指定阈值则加入多边形Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double> nearestEdge = getNearestEdge(curPoint, polygonMapArea.getPoints());if (nearestEdge == null) {log.warn("当前点:{}未找到最近边", curAlarm);continue;}Pair<Node<MapPoint>, Node<MapPoint>> nearestNode = nearestEdge.getKey();double nearestEdgeDistance = nearestEdge.getValue();if (nearestEdgeDistance <= collectDistance) {needInitNewPolygon = false;if (belongedArea == null) {polygonMapArea.getAlarms().add(curAlarm);if (nearestEdgeDistance > AreaUtil.ON_LINE_DISTANCE) {// 加入多边形并削内凹角tryRecalculationArea(polygonMapArea, nearestNode.getKey(), nearestNode.getValue(), curPoint);}polygonMapArea.setBelong(true);belongedArea = polygonMapArea;} else {mergePolygonArea(belongedArea, polygonMapArea, collectDistance);}}}return needInitNewPolygon;}
一些性能上的优化
1、多边形设置圆心
多边形圆心是由 多边形定边点数据中洗出来的 (最大经度,最大纬度) (最小经度最小纬度) 获取出的中心点
当判断点是否加入多边形时 先与圆心距离判断 (点与圆心点距离小于等于 圆半径+聚合距离是着可能需要加入,如大于着必不可能加入该多边形)
2、采用分支合并思路
区域列表循环采用分支合并思路,基于当前机器核心线程数拆分现有区域列表,异步计算最后合并汇总数据
/*** 获取对应报警类型计算线程池** @param alarm* @return ThreadPoolExecutor* @author lei* @date 2023-03-27 11:06:57*/private static ThreadPoolExecutor getCalcExecutor(Alarm alarm) {return ALARM_TYPE_EXECUTOR_MAP.computeIfAbsent(alarm.getAlarmType(), alarmType -> {alarmType = Optional.ofNullable(alarmType).orElse(0);ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE, CORE, 10, TimeUnit.MINUTES,new ArrayBlockingQueue<>(1024), new ThreadFactoryBuilder().setNameFormat(alarmType + "-calc-%d").setUncaughtExceptionHandler((t, e) -> log.error("线程:{}处理异常", t.getName(), e)).build(), new ThreadPoolExecutor.CallerRunsPolicy());log.debug("初始化报警类型:{}计算线程池!", alarmType);return executor;});}/*** 加入多边形计算** @param polygonMapAreas 现有聚集区* @param curAlarm 当前报警* @param collectDistance 聚集距离* @param calcIncr 累计计算量* @param incrId* @return void* @author lei* @date 2023-03-08 11:24:30*/private static void forkJoinPolygonArea(List<PolygonMapArea> polygonMapAreas, Alarm curAlarm, Double collectDistance,AtomicLong calcIncr, AtomicLong incrId) {long calcNum = calcIncr.incrementAndGet();if (CollUtil.isEmpty(polygonMapAreas)) {initPolygonArea(curAlarm, polygonMapAreas, incrId);return;}boolean needInitNewPolygon;List<List<PolygonMapArea>> splitAreaList = splitPolygonArea(polygonMapAreas);int splitAreaSize = splitAreaList.size();if (splitAreaSize > 1) {// 与各个子分支区域列表计算ThreadPoolExecutor calcExecutor = getCalcExecutor(curAlarm);List<CompletableFuture<Boolean>> collect = splitAreaList.stream().map(areas ->CompletableFuture.supplyAsync(() -> collectCalc(areas, curAlarm, collectDistance), calcExecutor)).collect(toList());List<Boolean> forkResultList = collect.stream().map(CompletableFuture::join).collect(toList());// 分支结果全真为真,非全真则再次合并needInitNewPolygon = splitAreaSize == forkResultList.stream().filter(x -> x).count();if (!needInitNewPolygon) {forkMergePolygonArea(polygonMapAreas, collectDistance);}} else {needInitNewPolygon = collectCalc(polygonMapAreas, curAlarm, collectDistance);}if (needInitNewPolygon) {initPolygonArea(curAlarm, polygonMapAreas, incrId);}// 清理较为离散的区域cleanDispersedArea(polygonMapAreas, calcNum);}/*** 合并线程子分支区域计算结果** @return List<PolygonMapArea> 返回分支合并后的区域列表,此时的区域列表为当前定位点计算后的最新结果* @author lei* @date 2023-03-27 15:46:26*/private static void forkMergePolygonArea(List<PolygonMapArea> polygonMapAreas, Double collectDistance) {PolygonMapArea belongArea = null;for (PolygonMapArea polygonMapArea : polygonMapAreas) {if (polygonMapArea.isBelong() && polygonMapArea.isLive()) {if (belongArea == null) {belongArea = polygonMapArea;} else {mergePolygonArea(belongArea, polygonMapArea, collectDistance);}}}}
3、清理聚集较分散区域
我们采取了定量清理区域逻辑思路,比如计算了20000个定位点清理一部分区域(区域一个点),区域数量达到10000个时清理区域内小于三个点的数据
合理性处理
1、解决多边形内凹角问题
由于每个定位点都有可能成为组成多边形区域的点,故此有可能组成的多边形是弯弯曲曲的畸形,比如像手,像魔爪等等,不是一个外凸的多边形
我们期望减少内凹角,使其成为一个更加饱满的多边形区域,比如下图
使用jts依赖库
compile 'org.locationtech.jts:jts-core:1.19.0'
核心思路是拿需消除内凹角的多边形所有定边点,使用jts依赖库绘制图形然后获取凸包,然后过滤出多边形定边点 不在凸包列表的数据
// 转换多边形定边点数据
Coordinate[] coordinates = points.getList().stream().map(x -> {Coordinate coordinate = new Coordinate(x.getLongitude(), x.getLatitude());return coordinate;}).toArray(Coordinate[]::new);
// 计算凸包
ConvexHull convexHull = new ConvexHull(coordinates, new GeometryFactory());
Geometry geometry = convexHull.getConvexHull();
Set<Coordinate> after = Arrays.stream(geometry.getCoordinates()).collect(Collectors.toSet());
// 踢出多边形定边点中不在Set集合中的数据
2、解决定边点插入位置问题
当新的定位点时要成为组成多边形定边点的时候会面临一个问题,这个点要插入哪里呢(插入顺序)?因为一旦位置选错了后,绘制成的多边形地图就会交叉
比如下图的多边形

先分析上图问题产生原因
1、最开始 是 2 3 4组成三角区域,5点到来时,需要先判断该点与多边形哪一边更近(答案很显然,与 3 4 更近)于是加入了 3 后 成为新多边形 2 3 5 4
6点到来,则需要与多边形 2 3 5 4判断最近边,但此时其与 3 5 54 边距离是相等的,由于我逻辑的不完整性,选错了边,选了3 5 边,绘制最终多边形 2 3 6 5 4,导致多边形交叉
如何解决选错边的问题?如何选择插入的边?
思考了很久,我们可以将要插入的点与最近两个边夹角大小来判断,即上图的 3 5 6 与 4 5 6两个夹角的大小来判断,插入夹角较小的那一边。
35 54 一个最近边的结束 也是另一个最近边的开始
但还特别需要注意的是 多边形的组成顺序并不一定都是我上图的 2 3 5…这样顺时针(多边形从右边开始绘制)组成的,也可能多边形是逆时针绘制组成出来的(多边形从左边开始生成绘制)
抛除6点,我们假设上图多边形是从左边绘制的,并且 6点不是与 35 54最近,而是与 24 32 最近,那么此时会发现,相邻的两个边,一个最近边的结束不是另一个最近边的开始 这个时候我们夹角度数就要修改为 4 2 6 与 3 2 6,这样计算夹角才对
那么我们如何确定顺时针与逆时针呢?我们只需要判断第二个最近边的开始是不是第一边的结束即可
/*** 根据当前点 获取与当前多边形最近边** @param curPoint 当前点* @param points 当前多边形组合点* @return Pair<Pair < Node < MapPoint>,Node<MapPoint>>,Double> 最近边组成点 当前点与最近边距离* @author lei* @date 2023-03-02 15:45:18*/private static Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double> getNearestEdge(MapPoint curPoint, LinkList<MapPoint> points) {Node<MapPoint> foreachNode = points.getFirst();Double nearestEdgeDistance = null;List<Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double>> pairList = new ArrayList<>();for (int i = 0; i < points.getSize(); i++) {Node<MapPoint> endPoint = foreachNode.getNext();double curDistance = AreaUtil.pointToLine(foreachNode.getData(), endPoint.getData(), curPoint);if (nearestEdgeDistance == null || nearestEdgeDistance >= curDistance) {nearestEdgeDistance = curDistance;Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double> nearestEdge = new Pair<>(Pair.of(foreachNode, foreachNode.getNext()), curDistance);pairList.add(nearestEdge);}foreachNode = endPoint;}Map<Double, List<Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double>>> map = pairList.stream().collect(Collectors.groupingBy(Pair::getValue));List<Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double>> nearestEdgeList = map.get(nearestEdgeDistance);// 特殊情况会出现当前点d与多边形两个边 (顺时针查找ab bc、或逆时针查找 ab ca)距离相同情况,因此做特殊处理,返回其夹角度数最小所在的那一边if (points.getSize() >= 3 && nearestEdgeList.size() == 2) {// 边1Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double> nearestEdgeOne = nearestEdgeList.get(0);Pair<Node<MapPoint>, Node<MapPoint>> edgeOne = nearestEdgeOne.getKey();Node<MapPoint> edgeOneStart = edgeOne.getKey();Node<MapPoint> edgeOneEnd = edgeOne.getValue();// 边2Pair<Pair<Node<MapPoint>, Node<MapPoint>>, Double> nearestEdgeTwo = nearestEdgeList.get(1);Pair<Node<MapPoint>, Node<MapPoint>> edgeTwo = nearestEdgeTwo.getKey();Node<MapPoint> edgeTwoStart = edgeTwo.getKey();Node<MapPoint> edgeTwoEnd = edgeTwo.getValue();double cosValue1;double cosValue2;// 顺时针相邻if (edgeTwoStart.equals(edgeOneEnd)) {// 求 边1 开始 结束 当前点组成夹角余弦 (a b d)cosValue1 = AreaUtil.cosValue(edgeOneStart.getData(), edgeOneEnd.getData(), curPoint);// 求 边2 结束 开始 当前点组成夹角余弦 (c b d)cosValue2 = AreaUtil.cosValue(edgeTwoEnd.getData(), edgeTwoStart.getData(), curPoint);} else {// a b c a// 求 边1 结束 开始 当前点组成夹角余弦 (b a d)cosValue1 = AreaUtil.cosValue(edgeOneEnd.getData(), edgeOneStart.getData(), curPoint);// 求 边2 开始 结束 当前点组成夹角余弦 (c a d)cosValue2 = AreaUtil.cosValue(edgeTwoStart.getData(), edgeTwoEnd.getData(), curPoint);}// 返回小夹角所在边,如夹角一致则交由下一步消内凹逻辑return cosValue1 >= cosValue2 ? nearestEdgeOne : nearestEdgeTwo;}return nearestEdgeList.get(0);}
3、多边形区域扩展
我们生成了某一类型报警的 N个聚集区域后,当其他车辆快要经过这里时我们怎么提前预警呢?
1、基于现在车辆定位点计算其与报警聚集区距离,小于等于阈值则报警
此方案可行,但是如果车辆速度过快(且我们的车辆定位是30s传一条)且聚集区比较小的话可能还没起到提示作用就已经过了该聚集区了
2、在原有多边形区域基础之上,向外扩展指定阈值,当车辆在记录扩展后的区域达到阈值或在进入到扩展后的区域时触发提醒
我们最终选择了方案二
那么多边形区域如何扩展呢?
使用jts依赖库
compile 'org.locationtech.jts:jts-core:1.19.0'
我们将原多边形区域定边点使用jts依赖库组成几何图形,并设置外扩,我们拿到外扩后的几何图形凸包即可
/*** 多边形区域扩展** @param points 定位点* @param extendDistance 外扩距离 m* @return List<MapPoint>* @author lei* @date 2023-03-21 16:19:30*/
public static List<MapPoint> extendPoints(List<MapPoint> points, double extendDistance) {List<MapPoint> extendsPoints = points;if (extendDistance > 1 && points.size() >= NEED_EXTEND_SIZE) {Coordinate[] coordinates = points.stream().map(point -> new Coordinate(point.getLongitude(), point.getLatitude())).toArray(Coordinate[]::new);ConvexHull convexHull = new ConvexHull(coordinates, new GeometryFactory());Geometry polygon = convexHull.getConvexHull();// 每个圆弧的线段数,值越夹角越平滑,int quadrantSegments = 1;// 端点类型int endCapStyle = BufferParameters.CAP_SQUARE;// 连接类型int joinStyle = BufferParameters.JOIN_MITRE;// 指定斜接连接的斜率限制 当两个线段夹角很小时,斜接点锐角非常尖锐; 避免锐化可限制斜接点的斜率,当斜率超过指定阈值将强使用JOIN_BEVELdouble mitreLimit = 5.0;BufferParameters bufferParams = new BufferParameters(quadrantSegments, endCapStyle, joinStyle, mitreLimit);bufferParams.setSingleSided(true);// 向外扩展区域Geometry expandedPolygon = BufferOp.bufferOp(polygon, extendDistance * 10, bufferParams);Coordinate[] extendArray = expandedPolygon.convexHull().getCoordinates();extendsPoints = Arrays.stream(extendArray).map(x -> new MapPoint((int) x.x, (int) x.y)).distinct().collect(Collectors.toList());}return extendsPoints;
}
成果展示
相关文章:

JAVA代码 实现定位数据动态聚集并绘制多边形区域
文章目录思路1、限制聚合距离2、绘制多边形区域3、多边形区域之间合并4、多边形定边点4、逻辑流程一些性能上的优化1、多边形设置圆心2、采用分支合并思路3、清理聚集较分散区域合理性处理1、解决多边形内凹角问题2、解决定边点插入位置问题3、多边形区域扩展成果展示最近有根据…...

基于储能进行调峰和频率调节研究【超线性增益的联合优化】(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

体验 Linux 的几个监控命令(htop、nmon、netdata)
体验 Linux 的几个监控命令htopnmonnetdatahtop 安装, sudo dnf install -y htop使用, htopnmon 安装, sudo dnf install -y nmon使用, nmon输入c, 输入C, 输入m, 输入n, 输入…...

NOC大赛2022NOC软件创意编程初赛图形化小低组(小学高年级组)
一、选择题 1.如果要控制所有角色一起朝舞台区右侧移动,下面哪个积太块是不需要的 2.要想让三个角色一起移动起来,下面哪个积木块没有作用 ? 3.小猴按照下面的程序前进,小猴最后一次前进了()步。 4.小可同学写了一个画笔程序画出花朵,但是运行后什么都看不到,不可…...
python进行股票收益率计算和风险控制的实现
股票收益率计算和风险控制的实现 在进行股票投资时,计算收益率和进行风险控制是非常重要的。本文将介绍一个与此相关的函数:radio_day_cal()。 radio_day_cal()函数 def radio_day_cal(last_day, sheet_name, df_dict, code_list, new_list):i 0days…...

自从有了这套近4000页的开发文档后,Java面试路上就像开了挂一样
Java是世界最流行的编程语言,也是国内大多数IT公司的主流语言。招聘网站上Java岗位众多,Java工程师似乎不愁找工作。但仔细一看就会发现,Java岗位的招聘薪酬天差地别,人才要求也是五花八门。而在Java工程师求职过程中,…...

Python文件操作
目录 一、文件操作介绍 二、文件的打开和关闭 三、文件的读写 四、文件文件夹相关操作 五、test 一、文件操作介绍 文件 : python中文件是对象 Liunx 文件 : 一切设备都可以看成是文件 磁盘文件 管道 网络Socket 文件属性: 读 写 执行权限 就是把一些存储存放起来&…...

036:cesium加载GPX文件,显示图形
第036个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载GPX文件, 显示图形。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共83行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https:/…...

【AI探索】我问了ChatGPT几个终极问题
终于尝试了一把ChatGPT的强大之处,问了一下关心的几个问题: chatGPT现在在思考吗?有没有什么你感兴趣的问题? 你认为AI会对人类产生哪些方面的影响? 你对人类所涉及到的学科有了解吗?你认为在哪些方面与人类…...

Leetcode 优先队列详解
优先队列 优先队列(Priority Queue):一种特殊的队列。在优先队列中,元素被赋予优先级,当访问队列元素时,具有最高优先级的元素最先删除 普通队列详解Leetcode 队列详解 优先队列与普通队列最大的不同点在于…...

通过两道一年级数学题反思自己
背景 做完这两道题我开始反思自己,到底是什么限制了我?是我自己?是曾经教导我的老师?还是我的父母? 是考试吗?还是什么? 提目 1、正方体个数问题 2、相碰可能性 过程 静态思维: …...

Pytorch :从零搭建一个神经网络
文章目录安装依赖从源码编译pytorchCXX_ABI问题数据集归一化Transforms搭建神经网络Components of a neural networknn.Flattennn.Linearnn.Sequentialnn.SoftmaxModel Parameters优化模型参数设置超参数添加优化循环添加 loss function优化过程完整实现模型的保存和加载安装 …...
【华为OD机试 2023最新 】 区块链文件转储系统(C++ 100%)
题目描述 区块链底层存储是一个链式文件系统,由顺序的N个文件组成,每个文件的大小不一,依次为F1,F2,…,Fn。随着时间的推移,所占存储会越来越大。 云平台考虑将区块链按文件转储到廉价的SATA盘,只有连续的区块链文件才能转储到SATA盘上,且转储的文件之和不能超过SATA盘…...

基于springcloud实现分布式架构网上商城演示【项目源码】分享
基于springcloud实现分布式架构网上商城演示摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包…...

【Qt】(自制类)适用于QTextCharFormat的字体选择对话框
先附上github链接:https://github.com/Ls-Jan/Qt_CharFormatDialog 主要是作为QFontDialog的平替/增强,毕竟Qt自带的字体选择器一言难尽(用过的都叹气)。 【运行界面】 【功能】 一目了然,可以选择字体,设置字号,设置…...

Unity即时战略/塔防项目实战(一)——构造网格建造系统
Unity即时战略/塔防项目实战(一)—— 构造网格建造系统 效果展示 Unity RTS游戏网格建造系统实现原理 地形和格子划分,建造系统BuildManager构建 地形最终需要划分成一个一个的小方格,首先定义一下小方格: private…...
【ZOJ 1095】Humble Numbers 题解(动态规划)
一个素数只有2,3,5或7的数被称为谦逊数。序列1、2、3、4、5、6、7、8、9、10、12、14、15、16、18、20、21、24、25、27。。。显示了前20个不起眼的数字。 编写一个程序来查找并打印此序列中的第n个元素。 输入规范 输入由一个或多个测试用例组成。每个…...

百科媒体背书,什么媒体的收录可以修改百科?
传媒如春雨,润物细无声,大家好 大家都知道百科在百度搜索引擎中有很高的权重,排名非常靠前,任何机构,个人,或者企业做网络宣传百科是必不可少的,虽然任何人都可以注册并编辑其内容。但是&#x…...
USB鼠标实现——HID 报告的返回(八)
文章目录HID 报告的返回仓库地址USB 鼠标阅读顺序报告返回HID 报告的返回 仓库地址 仓库地址 USB 鼠标阅读顺序 枚举过程USB鼠标实现——设备描述符(一)USB鼠标实现——设置地址(二)USB鼠标实现——配置描述符集合(…...

DOPE PEG Maleimide,DOPE-PEG-Mal,二油酰磷脂酰乙醇胺PEG马来酰亚胺
文章关键词:高分子PEG,DOPE,聚乙二醇化修饰试剂基团反应特点: DOPE PEG Maleimide是一种由 DOPE 和马来酰亚胺基团组成的 PEG 化合物。基础产品数据: CAS号:N/A 中文名:1,2-二油酰-SN-甘油-3-磷…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...