一个简单的可视化的A星自动寻路

一个简单的应用场景,流程图连线

源码:

    addExample("A星路径查找", function () {return {template: `<div><div ref="main"></div></div>`,data() { return {}; },computed: {},methods: {},mounted() {var container = this.$refs.main;var render = new CanvasShapeRender(container, {width: 700,height: 700,background: '#efefef'})var group = render.addShape({ type: 'group', x: 50, y: 50 })const start = Vector.create(2, 2)const end = Vector.create(8, 6)let dragObjconst tileMap = group.addShape({type: 'tileMap',visibleGrid: true,onCreateTileData(col, row) {if (row === start.y && col === start.x) {return {type: 'rect',color: '#ff0000',value: 1,canMove: true}}else if (row === end.y && col === end.x) {return {type: 'rect',color: '#00ff00',value: 2,canMove: true}} else {return {type: 'rect',color: '#ddd',value: 0}}},onAfterDrawMapCell(ctx, col, row, x, y, data) {if (!gui.visibleDist || data.value !== 4) {return}ctx.beginPath()ctx.fillStyle = '#000'ctx.font = '12px sans-serif'ctx.textAlign = 'start'ctx.textBaseline = 'base'const getDist = distOps[gui.dist]const startDist = Number(data.startDist.toFixed(2)) // Number(getDist({ col: start.x, row: start.y }, { col, row }).toFixed(2))const endDist = Number(data.endDist.toFixed(2))// Number(getDist({ col, row }, { col: end.x, row: end.y }).toFixed(2))const dist = Number(data.dist.toFixed(2))//Number((endDist + startDist).toFixed(2))ctx.fillText('' + startDist, x, y + 10)ctx.fillText('' + endDist, x, y + this.cellSize[1] - 5)ctx.beginPath()ctx.font = '14px sans-serif'ctx.textAlign = 'center'ctx.textBaseline = 'middle'//  CanvasRenderingContext2D.prototype.textBaselinectx.fillText('' + dist, x + this.cellSize[0] / 2, y + this.cellSize[1] / 2)},cellSize: [50, 50],mapSize: [10, 10],mousedown(e) {const downPoint = e.downPointconst [x, y] = group.transformLocalCoord(downPoint.x, downPoint.y)const [col, row] = this.getMapCoordinate(x, y)const data = this.getCellData(col, row)if (data && data.canMove) {dragObj = {col,row,data}} else if (data && (data.value == 0 || data.value == 3)) {dragObj = {col,row,data: {value: data.value}}}},drag(e) {if (dragObj) {const point = e.pointconst [x, y] = group.transformLocalCoord(point.x, point.y)let [col, row] = this.getMapCoordinate(x, y)const data = this.getCellData(col, row)if (dragObj.data.value === 0 && !data.canMove) {// 变成障碍data.value = 3data.color = '#666'this.setCellData(col, row, data)render.requestDraw()} else if (dragObj.data.value === 3 && !data.canMove) {// 移除障碍data.value = 0data.color = '#ddd'this.setCellData(col, row, data)render.requestDraw()}else if (dragObj.data.canMove && data && data !== dragObj.data) {this.setCellData(dragObj.col, dragObj.row, data)this.setCellData(col, row, dragObj.data)if (dragObj.data.value === 1) {start.x = colstart.y = row}if (dragObj.data.value === 2) {end.x = colend.y = row}dragObj.col = coldragObj.row = rowrender.requestDraw()}}},mouseup() {dragObj = null}})render.requestDraw()const map = tileMap.map // 0 空 1 起点 2终点 3障碍const clear = () => {tileMap.visitMap(tileMap.map, (r, c, data) => {if (data.value === 4) {data.value = 0data.color = '#ddd'}})render.requestDraw()}const renderPaths = (paths, color, renderPath, duration = 1000) => {if (paths.length <= 0) {return}let start = performance.now()let len = paths.length - 1const animate = (time) => {const d = performance.now() - startconst p = Math.min(d / duration, 1)const index = Math.floor(p * len);const data = paths[index]if (renderPath || !data.isPath) {tileMap.setCellData(data.col, data.row, {...data,type: 'rect',value: 4,color: color})}render.requestDraw()if (p < 1) {requestAnimationFrame(animate)}}requestAnimationFrame(animate)}// 计算两个点的距离//Manhattan Distanceconst getManhattanDist = (a, b) => {// 曼哈顿距离 return Math.abs(a.col - b.col) + Math.abs(a.row - b.row)}// 欧几里得距离( Euclidean distance)也称欧氏距离const getEuclideanDist = (a, b) => {const x = a.col - b.colconst y = a.row - b.rowreturn Math.sqrt(x * x + y * y)}//,切比雪夫距离(Chebyshev distance)const getChebyshevDist = (a, b) => {const x = a.col - b.colconst y = a.row - b.rowreturn Math.max(Math.abs(x), Math.abs(y))}const distOps = {getManhattanDist,getEuclideanDist,getChebyshevDist}// 返回最短路径const findPath = function* (start, end, _map) {// 创建图顶点信息const map = _map.map((rd, row) => {return rd.map((cd, col) => {return {...cd,row,col,value: cd.value,isPath: false,visited: false,// 是否访问过// 无有可走的路closed: false, // 已经查找过parent: null,startDist: 0, // 起点距离当前格子endDist: 0, // 当前距离终点dist: 0, // 总距离weight: 0, // 权重order: 0,}})})const rows = map.length, cols = map[0].lengthconst getNode = (col, row) => {if (col < 0 || col >= cols || row < 0 || row >= rows) {return null}return map[row][col]}// 找相邻的const getAdjacent = (node) => {const c = node.colconst r = node.rowconst left = getNode(c - 1, r) // leftconst top = getNode(c, r - 1) // topconst right = getNode(c + 1, r) // rightconst bottom = getNode(c, r + 1) // bottomreturn [left, top, right, bottom].filter(Boolean)}const getCost=()=>{return 0.1}const findNearestDistance = (node) => {const adjacent = getAdjacent(node)let min = Infinity, minNode// let resultNode;adj:for (let i = 0; i < adjacent.length; i++) {const adj = adjacent[i]// 如果已关闭或是障碍,不处理if (adj.closed || adj.value === 3) {continue;}let startDist=node.startDist+getCost(adj,node) //getDist(adj,node)// 如果还未访问if (!adj.visited) {// g(n)表示从初始结点到任意结点n的代价,// h(n)表示从结点n到目标点的启发式评估代价(heuristic estimated cost)。// f=g(n)+h(n)// getDist(startNode, adj)adj.startDist = startDistadj.endDist = getDist(adj, endNode)adj.dist = adj.startDist + adj.endDist //getDist(adj, startNode)adj.parent = nodeadj.visited = trueopenList.push(adj)// 如果是空闲if (adj.value === 0) {visitedPaths.push(adj)}}else{if(startDist<node.startDist){adj.parent = nodeadj.startDist = startDistadj.dist = adj.startDist + adj.endDist //getDist(adj, startNode)}}if (adj.value === 2) {return adj}}openList.sort((a, b) => a.dist - b.dist)// openList.sort((a, b) => a.dist === b.dist ? a.dist - b.dist : a.order - b.order)}const getDist = distOps[gui.dist]// 查找邻居四个方位,上下左右let current = nulllet startNode = getNode(start[0], start[1])let endNode = getNode(end[0], end[1])let paths = []let visitedPaths = []let openList = []openList.push(startNode)let resultNode;path:while (openList.length) {yield { visitedPaths, paths };current = openList.shift()current.closed = true;if (current === endNode) {resultNode = currentbreak}resultNode = findNearestDistance(current)if (resultNode) {break}}current = resultNode ? resultNode.parent : nullwhile (current && current !== startNode) {current.isPath = true;paths.unshift(current)current = current.parent}return {paths: paths,visitedPaths}}const resultGenerator = (result) => {let current;do {current = result.next();} while (!current.done)return current.value}const stepGenerator = (generatorFn, callback) => {let result;let isStart = falseconst next = () => {if (!isStart) {isStart = true;result = generatorFn()}let current = result.next();callback(current.value)if (current.done) {isStart = false}}return {next,}}const distList = Object.keys(distOps)const step = stepGenerator(function* () {return yield* findPath([start.x, start.y], [end.x, end.y], map)}, ({ visitedPaths, paths }) => {renderPaths(visitedPaths, '#aaa', false)renderPaths(paths, '#ffff00', true)})const gui = addGuiScheme(this.$gui, {source: {dist: 'getEuclideanDist',visibleDist: false,start: () => {const { paths, visitedPaths } = resultGenerator(findPath([start.x, start.y], [end.x, end.y], map))renderPaths(visitedPaths, '#aaa', false)renderPaths(paths, '#ffff00', true)},step: () => {step.next()},clear() {clear()}},schemes: {dist: { type: 'list', params: distList }},onChange() {render.requestDraw()}})}}})

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

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

相关文章

Python中的比较两个字符串

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python编程中&#xff0c;字符串比较是一项常见且关键的操作&#xff0c;涵盖了诸多方法和技巧。比较两个字符串是否相等、大小写是否一致&#xff0c;或者在一个字符串中寻找特定的子字符串&#xff0c;都是日…

征途漫漫:汽车MCU的国产替代往事

01.西雁东飞&#xff0c;南下创业 1985年&#xff0c;山东大学物理系毕业的周生明加入878厂&#xff08;“北霸天”&#xff09;参与MOS电路研发&#xff0c;随后几年&#xff0c;大洋彼岸的英特尔相继推出CPU 386\486、奔腾系列等产品。在摩尔定律的凸显、进口和走私的剧烈冲…

class067 二维动态规划【算法】

class067 二维动态规划 code1 64. 最小路径和 // 最小路径和 // 给定一个包含非负整数的 m x n 网格 grid // 请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 // 说明&#xff1a;每次只能向下或者向右移动一步。 // 测试链接 : https://leetcode…

<JavaEE> 经典设计模式之 -- 线程池

目录 一、线程池的概念 二、Java 标准库中的线程池类 2.1 ThreadPoolExecutor 类 2.1.1 corePoolSize 和 maximumPoolSize 2.1.2 keepAliveTime 和 unit 2.1.3 workQueue 2.1.4 threadFactory 2.1.5 handler 2.1.6 创建一个参数自定义的线程池 2.2 Executors 类 2.3…

go学习笔记(17)Blob and ArrayBuffer

最近在学习go websocket的时候&#xff0c;在学习实验过程遇到一个比较奇怪问题。为什么我的数据返回是blob&#xff0c;而不是arrayBuffer&#xff1f;百思不得其解。 直到同事打包的时候微信小游戏遇到了一个报错。FileReader不支持。 经过在社区查询&#xff0c;官方答复是…

[RoBERTa]论文实现:RoBERTa: A Robustly Optimized BERT Pretraining Approach

文章目录 一、完整代码二、论文解读2.1 模型架构2.2 参数设置2.3 数据2.4 评估 三、对比四、整体总结 论文&#xff1a;RoBERTa&#xff1a;A Robustly Optimized BERT Pretraining Approach 作者&#xff1a;Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Da…

P10 Linux进程编程 fork创建子进程

目录 前言 01 fork()创建子进程 示例 1使用 fork()创建子进程。 02 fork创建新进程时发生了什么事&#xff1f; 2.1 父、子进程中对应的文件描述符指向了相同的文件表 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《Linux C应用编程&#xf…

异步回调模式

异步回调 所谓异步回调&#xff0c;本质上就是多线程中线程的通信&#xff0c;如今很多业务系统中&#xff0c;某个业务或者功能调用多个外部接口&#xff0c;通常这种调用就是异步的调用。如何得到这些异步调用的结果自然也就很重要了。 Callable、Future、FutureTask publi…

半导体划片机助力氧化铝陶瓷片切割:科技与工艺的完美结合

在当今半导体制造领域&#xff0c;氧化铝陶瓷片作为一种高性能、高可靠性的材料&#xff0c;被广泛应用于各种电子设备中。而半导体划片机的出现&#xff0c;则为氧化铝陶瓷片的切割提供了新的解决方案&#xff0c;实现了科技与工艺的完美结合。 氧化铝陶瓷片是一种以氧化铝为基…

《巫师3》缺失vcomp110.dll如何解决,如何快速修复vcomp110.dll丢失问题

在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp110.dll丢失”。这个错误提示通常意味着vcomp110.dll文件在系统中无法找到或加载。那么&#xff0c;vcomp110.dll丢失的原因是什么&#xff1f;它对电脑有什么影响&#xff1f;本…

高德地图vue实现自定义标点热力图效果(缩放时展示不同数据)

高德地图插件引入省略。。。样式和vue基础组件省略。。。 如果每个标点没有数值&#xff0c;则可以用点聚合来实现功能下面例子&#xff0c;每个标点会有按市统计的数值&#xff0c;而且缩放一定程度时&#xff0c;需要展示按省统计的标点&#xff0c;因此需要自定义标点样式和…

leetcode刷题日志-54螺旋矩阵

思路&#xff1a; 上下左右设置四个边界 每走完一行或者一列&#xff0c;移动相应边界&#xff0c;当左边界大于右边界&#xff0c;或者上边界大于下边界时&#xff0c;结束 代码如下&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {…

线程上下文切换

线程上下文切换 巧妙地利用了时间片轮转的方式, CPU 给每个任务都服务一定的时间&#xff0c;然后把当前任务的状态保存下来&#xff0c;在加载下一任务的状态后&#xff0c;继续服务下一任务&#xff0c;任务的状态保存及再加载, 这段过程就叫做上下文切换。时间片轮转的方式…

冒泡排序和直接选择排序(C/C++实现)

文章目录 冒泡排序(交换排序&#xff09;基本思想特性总结代码实现 直接选择排序基本思想特性总结代码实现&#xff08;优化&#xff0c;每次循环同时选择最小和最大的数&#xff09; 冒泡排序(交换排序&#xff09; 基本思想 基本思想&#xff1a;所谓交换&#xff0c;就是根…

class065 A星、Floyd、Bellman-Ford与SPFA【算法】

class065 A星、Floyd、Bellman-Ford与SPFA【算法】 2023-12-9 19:27:02 算法讲解065【必备】A星、Floyd、Bellman-Ford与SPFA code1 A*算法模版 // A*算法模版&#xff08;对数器验证&#xff09; package class065;import java.util.PriorityQueue;// A*算法模版&#xff…

两年外包生涯做完,感觉自己废了一半。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

laravel的ORM 对象关系映射

Laravel 中的 ORM&#xff08;Eloquent ORM&#xff09;是 Laravel 框架内置的一种对象关系映射系统&#xff0c;用于在 PHP 应用中与数据库进行交互。Eloquent 提供了一种优雅而直观的语法&#xff0c;使得开发者可以使用面向对象的方式进行数据库查询和操作。 定义模型&…

结合ColorUI组件开发微信小程序

1.自定义组件生命周期函数&#xff1a; Component({data: {},attached() {console.log("自定义组件生命周期函数 attached--先执行");this.getPos();},ready() {console.log("ready生命周期函数---在attached之后执行")},methods: {getPos() {var that th…

数据结构:位图、布隆过滤器以及海量数据面试题

位图、布隆过滤器以及海量数据面试题 1.位图1.1概念1.2实现1.3位图应用 2.布隆过滤器2.1布隆过滤器的提出2.2布隆过滤器的概念2.3布隆过滤器的查找2.4布隆过滤器的实现2.5布隆过滤器的删除2.6布隆过滤器的优点2.7布隆过滤器的缺点 3.海量数据面试题3.1哈希切分3.2位图应用3.3布…

如何成为前1%的程序员

如果你想成为前1%的程序员&#xff0c;你必须遵循1%的程序员做什么&#xff0c;了解其他99%的人不做什么。在现代&#xff0c;我们有各种学习平台&#xff0c;里面充满了与编程相关的视频、图文以及其他资料。 举例来说&#xff0c;我作为编程的初学者&#xff0c;去寻找路线图…