根据点信息生成道路以及路口
<p><img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250424174135455-1386274952.gif" alt="" width="531" height="305" loading="lazy"> <img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250424174804568-1701915595.gif" alt="" width="496" height="295" loading="lazy"></p><p> </p>
<p> </p>
<p>一、目标</p>
<p> 1. 生成道路:通过提供的一些随机的点信息,自动扩展成一定宽度的道路,道路具有路沿点、道路中心点分上下行车道,点的方向根据实际车道运行的方向生成。</p>
<p> 2. 生成路口:如果多天道路之间有相交,则可以自动在交叉位置计算出道路路口,方便后续车辆在路口拐弯的计算和展示美观,无线路交叉感。</p>
<p>二、实现原理</p>
<p> 1. 如何生成一条道路</p>
<p> 1) 以每两个点形成一条直线向两侧扩展一定的宽度生成一个面(如图一),但是需要考虑多个连续的线段之间可能会有线段交叉或者无交叉的情况(如图二),</p>
<p> 如果两个线段有交点时需要把舍弃掉部分扩展道路点同时插入交叉点A,如果没有交点则需要插入直线的交点B来将道路连接起来</p>
<p> <img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250425145601427-1473809350.png" alt="" width="196" height="191" loading="lazy"> <img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250425145945064-148335068.png" alt="" width="234" height="182" loading="lazy"></p>
<p> 2) 将扩展的左、右两侧的道路点信息拼接起来,如果是逆时针,则上下行顺序正确,否则需要将点信息反转</p>
<p> <img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250425152022412-1425955120.png" alt="" loading="lazy"></p>
<p> 2. 如何生成相互交叉的道路和路口</p>
<p> 注:同一条道路如果有交叉,不会生成路口</p>
<p> 1)分组道路:如果多条道路在某一个点附近交叉,可以认为这些道路共用一个路口,循环遍历所有道路,如果道路交叉点之间的距离小于某个范围,则认为属于同一个路口</p>
<p> 2) 按组对道路点进行循环,对上下行道路点分别进行交叉点计算,同时生成一个多边形,按照算法获取这个多边形最大的凸包即路口的点信息,</p>
<p> 如图中红色点为多条道路中心线的交叉点,如果红点之间的距离小于一定范围,则认为这三条道路归属一个路口</p>
<p> 每个黑色的线(即上下行边线)相交的点(图中所有黑色的点)组成一个polygon,通过Graham扫描法寻找最大的凸包时会只保留较大的黑色点,三个小黑点由于在凸包范围内则被舍弃</p>
<p> 这样就获取到完整的路口点信息</p>
<p> <img src="https://img2024.cnblogs.com/blog/2310605/202504/2310605-20250425171321434-1483456710.png" alt="" loading="lazy"></p>
<p>三、代码逻辑</p>
<p> 1. 简单创建页面</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_9a317f1e-2b2b-4599-9f4c-b37f0bad7729" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_9a317f1e-2b2b-4599-9f4c-b37f0bad7729" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_9a317f1e-2b2b-4599-9f4c-b37f0bad7729" class="cnblogs_code_hide">
<pre><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>localhost:8086</title>
<script type="module" src="./main.js"></script>
</head>
<body style="margin: 0;">
<div class="button">
<img class="button-item" src="./images/road.svg" id="drawRoad">
<img class="button-item" src="./images/clear.svg" id="clear">
</div>
<canvas id="webgl"></canvas>
</body>
<style ><span style="color: rgba(0, 0, 0, 1)">
html, body, #webgl {
height: </span>100%<span style="color: rgba(0, 0, 0, 1)">;
width: </span>100%<span style="color: rgba(0, 0, 0, 1)">;
overflow: hidden;
}
.button {
</span><span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)">: right;
right: 50px;
top: 20px;
position: absolute;
z</span>-index: 100<span style="color: rgba(0, 0, 0, 1)">;
}
.button</span>-<span style="color: rgba(0, 0, 0, 1)">item {
width: 24px;
height: 24px;
box</span>-<span style="color: rgba(0, 0, 0, 1)">shadow: 0px 0px 7px #e1cccc;
border</span>-<span style="color: rgba(0, 0, 0, 1)">radius: 6px;
padding: 3px;
cursor: pointer;
background: white;
}
.button</span>-<span style="color: rgba(0, 0, 0, 1)">item:hover {
transform: scale(</span>1.2<span style="color: rgba(0, 0, 0, 1)">);
}
.webgl {
width: </span>100%<span style="color: rgba(0, 0, 0, 1)">;
height: </span>100%<span style="color: rgba(0, 0, 0, 1)">;
}
</span></style>
</html></pre>
</div>
<span class="cnblogs_code_collapse">index.html</span></div>
<p> 2. 为了快速测试功能,通过在界面手动戳点来快速创建随机的道路点信息</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_31f0f337-83d0-4319-b8c5-f66c164497f7" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_31f0f337-83d0-4319-b8c5-f66c164497f7" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_31f0f337-83d0-4319-b8c5-f66c164497f7" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> import { pushLine, refresh } from './Line.js';</span>
import * as roadCtrl from '../road/RoadControl.js'<span style="color: rgba(0, 0, 0, 1)">;
let that </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
export </span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)"> class Draw {
constructor(props) {
that </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标图钉对象</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 道路拐点信息</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.points =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx = document.getElementById(props.id).getContext('2d'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.width =<span style="color: rgba(0, 0, 0, 1)"> document.getElementById(props.id).offsetWidth;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.height =<span style="color: rgba(0, 0, 0, 1)"> document.getElementById(props.id).offsetHeight;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.thumbtack = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Image();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.thumbtack.src = './images/thumbtack.svg'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseX = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseY = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.drawEnd =<span style="color: rgba(0, 0, 0, 1)"> props.drawEnd;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.initMouse();
}
initMouse() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom = document.createElement('div'<span style="color: rgba(0, 0, 0, 1)">);
const imgDom </span>= document.createElement('img'<span style="color: rgba(0, 0, 0, 1)">);
imgDom.src </span>= './images/thumbtack-add.svg'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.style.position = 'absolute'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.style.right = '0px'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.style.top = '0px'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.style.width = '24px'<span style="color: rgba(0, 0, 0, 1)">;
document.body.appendChild(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mouseDom);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.registerEvent();
}
registerEvent() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.addEventListener('click', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.clickEvent);
document.addEventListener(</span>'mousemove', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mousemoveEvent);
document.addEventListener(</span>'keydown', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.keydownEvent);
document.addEventListener(</span>'dblclick', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.dblclickEvent);
}
clickEvent(event) {
that.points.push();
that.refresh();
}
keydownEvent(event) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (event.key === 'Escape'<span style="color: rgba(0, 0, 0, 1)">) {
that.points.pop();
that.refresh();
}
}
mousemoveEvent(e) {
that.mouseX </span>=<span style="color: rgba(0, 0, 0, 1)"> e.clientX;
that.mouseY </span>=<span style="color: rgba(0, 0, 0, 1)"> e.clientY;
that.mouseDom.style.left </span>= e.clientX - 3 + 'px'<span style="color: rgba(0, 0, 0, 1)">;
that.mouseDom.style.top </span>= e.clientY - 20 + 'px'<span style="color: rgba(0, 0, 0, 1)">;
that.mouseDom.innerHTML </span>=<span style="color: rgba(0, 0, 0, 1)"> `${e.clientX}, ${e.clientY}`;
that.refresh();
}
dblclickEvent() {
that.points.pop();
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (that.drawEnd) {
that.destory();
that.drawEnd(that.points);
}
}
refresh() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.clearRect(0, 0, <span style="color: rgba(0, 0, 255, 1)">this</span>.width, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.height);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.drawLine(<span style="color: rgba(0, 0, 255, 1)">this</span>.mouseX, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mouseY);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawPoint();
roadCtrl.refresh();
}
drawLine(lastX, lastY) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.clearRect(0, 0, <span style="color: rgba(0, 0, 255, 1)">this</span>.width, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.height);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.points.length !==0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.strokeStyle = '#9ec9df'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineWidth = 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineJoin="round"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.moveTo(...<span style="color: rgba(0, 0, 255, 1)">this</span>.points);
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < <span style="color: rgba(0, 0, 255, 1)">this</span>.points.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineTo(...<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.points);
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.lineTo(lastX, lastY);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.stroke();
}
}
drawPoint() {
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < <span style="color: rgba(0, 0, 255, 1)">this</span>.points.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.drawImage(<span style="color: rgba(0, 0, 255, 1)">this</span>.thumbtack, <span style="color: rgba(0, 0, 255, 1)">this</span>.points - 11, <span style="color: rgba(0, 0, 255, 1)">this</span>.points - 20, 24, 24<span style="color: rgba(0, 0, 0, 1)">);
}
}
destory() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.clearRect(0, 0, <span style="color: rgba(0, 0, 255, 1)">this</span>.width, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.height);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.mouseDom.removeEventListener('click', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.clickEvent);
document.removeEventListener(</span>'mousemove', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mousemoveEvent);
document.removeEventListener(</span>'keydown', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.keydownEvent);
document.removeEventListener(</span>'dblclick', <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.dblclickEvent);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mouseDom.remove();
}
}</span></pre>
</div>
<span class="cnblogs_code_collapse">Draw.js</span></div>
<p> 3. 创建工具文件,计算是否顺时针、计算凸包等算法功能</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_4204dcdc-de4e-4e5f-8258-aed265123aae" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_4204dcdc-de4e-4e5f-8258-aed265123aae" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_4204dcdc-de4e-4e5f-8258-aed265123aae" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 根据贝塞尔公式获取一条平滑的曲线
* @param {*} points
* @param {*} numSegments
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span> getBezierPoints(points, numSegments = 8<span style="color: rgba(0, 0, 0, 1)">) {
const bezierPoints </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < points.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">) {
const p0 </span>=<span style="color: rgba(0, 0, 0, 1)"> points;
const p1 </span>= points;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算控制点</span>
const cp1 =<span style="color: rgba(0, 0, 0, 1)"> {
x: p0[</span>0] + (p1 - p0) / 3<span style="color: rgba(0, 0, 0, 1)">,
y: p0[</span>1] + (p1 - p0) / 3<span style="color: rgba(0, 0, 0, 1)">
};
const cp2 </span>=<span style="color: rgba(0, 0, 0, 1)"> {
x: p0[</span>0] + 2 * (p1 - p0) / 3<span style="color: rgba(0, 0, 0, 1)">,
y: p0[</span>1] + 2 * (p1 - p0) / 3<span style="color: rgba(0, 0, 0, 1)">
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算贝塞尔曲线上的点</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (let t = 0; t <= 1; t += 1 /<span style="color: rgba(0, 0, 0, 1)"> numSegments) {
const t2 </span>= t *<span style="color: rgba(0, 0, 0, 1)"> t;
const t3 </span>= t2 *<span style="color: rgba(0, 0, 0, 1)"> t;
const mt </span>= 1 -<span style="color: rgba(0, 0, 0, 1)"> t;
const mt2 </span>= mt *<span style="color: rgba(0, 0, 0, 1)"> mt;
const mt3 </span>= mt2 *<span style="color: rgba(0, 0, 0, 1)"> mt;
const x </span>= mt3 * p0 + 3 * mt2 * t * cp1.x + 3 * mt * t2 * cp2.x + t3 * p1;
const y </span>= mt3 * p0 + 3 * mt2 * t * cp1.y + 3 * mt * t2 * cp2.y + t3 * p1;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (bezierPoints.length === 0 || x !== bezierPoints && y !== bezierPoints) {
bezierPoints.push();
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bezierPoints;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 求两个线段的交点
* @param {*} line1
* @param {*} line2
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getIntersectionPoint(line1, line2) {
const </span>=<span style="color: rgba(0, 0, 0, 1)"> [...line1];
const </span>=<span style="color: rgba(0, 0, 0, 1)"> [...line2];
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算线段1的向量</span>
const dx1 = p12 - p11;
const dy1 </span>= p12 - p11;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算线段2的向量</span>
const dx2 = p22 - p21;
const dy2 </span>= p22 - p21;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算行列式</span>
const determinant = dx1 * dy2 - dy1 *<span style="color: rgba(0, 0, 0, 1)"> dx2;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果行列式为0,则两条线段平行或共线,没有交点</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (determinant === 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [];
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算参数t1和t2</span>
const t1 = ((p21 - p11) * dy2 - (p21 - p11) * dx2) /<span style="color: rgba(0, 0, 0, 1)"> determinant;
const t2 </span>= ((p21 - p11) * dy1 - (p21 - p11) * dx1) /<span style="color: rgba(0, 0, 0, 1)"> determinant;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 检查交点是否在线段范围内</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算交点坐标</span>
const x = p11 + t1 *<span style="color: rgba(0, 0, 0, 1)"> dx1;
const y </span>= p11 + t1 *<span style="color: rgba(0, 0, 0, 1)"> dy1;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 没有交点</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [];
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 求两条直线的交点
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getIntersection(line1, line2) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算直线1的方程</span>
const = line1;
const </span>= line1;
const isVertical1 </span>= x1 ===<span style="color: rgba(0, 0, 0, 1)"> x2;
let A1, B1, C1;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isVertical1) {
A1 </span>= 1<span style="color: rgba(0, 0, 0, 1)">;
B1 </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
C1 </span>= -<span style="color: rgba(0, 0, 0, 1)">x1;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
const m1 </span>= (y2 - y1) / (x2 -<span style="color: rgba(0, 0, 0, 1)"> x1);
const b1 </span>= y1 - m1 *<span style="color: rgba(0, 0, 0, 1)"> x1;
A1 </span>=<span style="color: rgba(0, 0, 0, 1)"> m1;
B1 </span>= -1<span style="color: rgba(0, 0, 0, 1)">;
C1 </span>=<span style="color: rgba(0, 0, 0, 1)"> b1;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算直线2的方程</span>
const = line2;
const </span>= line2;
const isVertical2 </span>= x3 ===<span style="color: rgba(0, 0, 0, 1)"> x4;
let A2, B2, C2;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isVertical2) {
A2 </span>= 1<span style="color: rgba(0, 0, 0, 1)">;
B2 </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
C2 </span>= -<span style="color: rgba(0, 0, 0, 1)">x3;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
const m2 </span>= (y4 - y3) / (x4 -<span style="color: rgba(0, 0, 0, 1)"> x3);
const b2 </span>= y3 - m2 *<span style="color: rgba(0, 0, 0, 1)"> x3;
A2 </span>=<span style="color: rgba(0, 0, 0, 1)"> m2;
B2 </span>= -1<span style="color: rgba(0, 0, 0, 1)">;
C2 </span>=<span style="color: rgba(0, 0, 0, 1)"> b2;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断是否平行于 Y 轴</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (isVertical1 &&<span style="color: rgba(0, 0, 0, 1)"> isVertical2) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两条直线都平行于 Y 轴</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (x1 ===<span style="color: rgba(0, 0, 0, 1)"> x3) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两条直线重合</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 有无数个交点</span>
} <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两条直线平行但不重合</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 没有交点</span>
<span style="color: rgba(0, 0, 0, 1)"> }
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isVertical1) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 第一条直线平行于 Y 轴</span>
const x =<span style="color: rgba(0, 0, 0, 1)"> x1;
const y </span>= (-A2 * x - C2) /<span style="color: rgba(0, 0, 0, 1)"> B2;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isVertical2) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 第二条直线平行于 Y 轴</span>
const x =<span style="color: rgba(0, 0, 0, 1)"> x3;
const y </span>= (-A1 * x - C1) /<span style="color: rgba(0, 0, 0, 1)"> B1;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两条直线都不平行于 Y 轴</span>
const det = A1 * B2 - A2 *<span style="color: rgba(0, 0, 0, 1)"> B1;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (det === 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两条直线平行或重合</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 没有唯一交点</span>
} <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算交点坐标</span>
const x = (B1 * C2 - B2 * C1) /<span style="color: rgba(0, 0, 0, 1)"> det;
const y </span>= (A2 * C1 - A1 * C2) /<span style="color: rgba(0, 0, 0, 1)"> det;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ;
}
}
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 计算三个点的重心位置
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> calTriangleCenter(p1, p2, p3) {
const </span>=<span style="color: rgba(0, 0, 0, 1)"> p1;
const </span>=<span style="color: rgba(0, 0, 0, 1)"> p2;
const </span>=<span style="color: rgba(0, 0, 0, 1)"> p3;
const centerX </span>= (x1 + x2 + x3) / 3<span style="color: rgba(0, 0, 0, 1)">;
const centerY </span>= (y1 + y2 + y3) / 3<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 判断一个多边形是否是顺时针,如果返回true则为顺时针,false为逆时针,
* 需要考虑坐标系和普通坐标系相反的问题
* @param {*} poly
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> isClockWise(poly) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!poly || poly.length < 3) <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
let end </span>= poly.length - 1<span style="color: rgba(0, 0, 0, 1)">;
let sum </span>= poly * poly - poly * poly;
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i < end; ++<span style="color: rgba(0, 0, 0, 1)">i) {
const n </span>= i + 1<span style="color: rgba(0, 0, 0, 1)">;
sum </span>+= poly * poly - poly * poly;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> sum > 0<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 根据给定的多个点,采用Graham扫描法寻找最大的凸包
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getMaxPolygon(points) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算两个点之间的距离</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> distance(p1, p2) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> Math.sqrt((p1 - p2) ** 2 + (p1 - p2) ** 2<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算叉积</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> cross(o, a, b) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (a - o) * (b - o) - (a - o) * (b - o);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 极角排序比较函数</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> angleCompare(base) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(p1, p2) {
const angle1 </span>= Math.atan2(p1 - base, p1 - base);
const angle2 </span>= Math.atan2(p2 - base, p2 - base);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (angle1 ===<span style="color: rgba(0, 0, 0, 1)"> angle2) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> distance(base, p1) -<span style="color: rgba(0, 0, 0, 1)"> distance(base, p2);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> angle1 -<span style="color: rgba(0, 0, 0, 1)"> angle2;
};
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (points.length < 3) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> points;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 选择基准点</span>
const base = points.reduce((min, p) => p < min || (p === min && p < min) ? p : min, points);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 极角排序</span>
<span style="color: rgba(0, 0, 0, 1)"> points.sort(angleCompare(base));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构建凸包</span>
const stack = , points, points];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 3; i < points.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (stack.length > 1 && cross(stack, stack, points) <= 0<span style="color: rgba(0, 0, 0, 1)">) {
stack.pop();
}
stack.push(points);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> stack;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 拷贝数据
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> clone(data) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> JSON.parse(JSON.stringify(data));
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createRandomId(prefix) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> prefix + '_' + 'xx-xxxx-4xxx-yxxx'.replace(//g, (c) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> v.toString(16<span style="color: rgba(0, 0, 0, 1)">);
});
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 计算距离
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> distance(point1, point2) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> Math.sqrt(Math.pow(point1 - point2, 2) + Math.pow(point1 - point2, 2), 2<span style="color: rgba(0, 0, 0, 1)">);
}
export {
createRandomId,
getBezierPoints,
getIntersectionPoint,
isClockWise,
getIntersection,
calTriangleCenter,
clone,
getMaxPolygon,
distance
}</span></pre>
</div>
<span class="cnblogs_code_collapse">Util.js</span></div>
<p> 4. 创建主文件,与UI交互,获取道路、路口数据,绘制道路、路口功能</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_1b844148-217d-4c97-ac6a-c8cd990bb02d" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_1b844148-217d-4c97-ac6a-c8cd990bb02d" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_1b844148-217d-4c97-ac6a-c8cd990bb02d" class="cnblogs_code_hide">
<pre>import { refresh } from './control/Line.js'<span style="color: rgba(0, 0, 0, 1)">;
import Draw from </span>'./control/Draw.js'<span style="color: rgba(0, 0, 0, 1)">;
import </span>* as roadCtrl from './road/RoadControl.js'<span style="color: rgba(0, 0, 0, 1)">;
import </span>* as crossCtrl from './road/CrossControl.js'<span style="color: rgba(0, 0, 0, 1)">;
import { distance, getIntersectionPoint, getMaxPolygon } from </span>'./road/Util.js'<span style="color: rgba(0, 0, 0, 1)">;
let flag </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
let drawIns </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
let canvasDom </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
let ctx </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> initEvent() {
const map </span>=<span style="color: rgba(0, 0, 0, 1)"> {
drawRoad,
clear
}
const list </span>= document.getElementsByClassName('button-item'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < list.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
list.addEventListener(</span>'click', (e) =><span style="color: rgba(0, 0, 0, 1)"> {
map();
})
}
canvasDom </span>= document.getElementById('webgl'<span style="color: rgba(0, 0, 0, 1)">);
ctx </span>= canvasDom.getContext('2d'<span style="color: rgba(0, 0, 0, 1)">);
canvasDom.setAttribute(</span>'width'<span style="color: rgba(0, 0, 0, 1)">, canvasDom.offsetWidth);
canvasDom.setAttribute(</span>'height'<span style="color: rgba(0, 0, 0, 1)">, canvasDom.offsetHeight);
roadCtrl.setCtx(ctx);
crossCtrl.setCtx(ctx);
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> drawRoad() {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">flag) {
flag </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
drawIns </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Draw({ id: 'webgl', drawEnd: (coords) =><span style="color: rgba(0, 0, 0, 1)"> {
roadCtrl.addRoad({ coords, width: </span>20<span style="color: rgba(0, 0, 0, 1)"> });
roadCtrl.refresh();
flag </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
const allRoads </span>=<span style="color: rgba(0, 0, 0, 1)"> roadCtrl.getAllRoad();
getCross(allRoads);
console.log(crossCtrl.getAllCross());
} });
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
drawIns.destory();
flag </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
refresh();
}
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取所有的焦点
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInterPoint(line1, line2) {
const inter </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i < line1.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">){
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(let j = 0; j < line2.length - 1; j++<span style="color: rgba(0, 0, 0, 1)">){
const interPoint </span>=getIntersectionPoint(, line1], , line2]);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (interPoint.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
inter.push(interPoint);
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> inter;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 判断两个点之间相近
* @param {*} point1 点1
* @param {*} point2 点2
* @param {*} tolerance 容忍值
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> isNear(point1, point2, tolerance) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> distance(point1, point2) <<span style="color: rgba(0, 0, 0, 1)"> tolerance;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 判断是否存在道路列表中
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> isNotExist(roads, id) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> roads.filter(e => e.id === id).length === 0<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 从多个点中获取距离基准点最近的点
* @param {*} points
* @param {*} basePoint
* @param {*} tolerance
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span> getNearestPoint(points, basePoint, tolerance = 160<span style="color: rgba(0, 0, 0, 1)">) {
const pointDis </span>= points.map(e =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
point: e,
dis: distance(e, basePoint)
};
});
pointDis.sort((a, b) </span>=> a.dis -<span style="color: rgba(0, 0, 0, 1)"> b.dis);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (distance(pointDis.point, basePoint) <<span style="color: rgba(0, 0, 0, 1)"> tolerance) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> pointDis.point;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [];
}
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> groupCross(roads) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算原则,多条路相交于一点或者近乎一点时</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> same 格式 XY 轴坐标联合作为key值存储数据</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'x,y': {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> point: [], 道路交点,多条道路只存储一个交点</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> links: [] 该路口的关联道路信息</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
const same =<span style="color: rgba(0, 0, 0, 1)"> {};
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < roads.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let j = i + 1; j < roads.length; j++<span style="color: rgba(0, 0, 0, 1)">) {
const tempInter </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterPoint(roads.CCoords, roads.CCoords);
tempInter.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
let flag </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (const o <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> same) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (isNear(same.point, e, 40<span style="color: rgba(0, 0, 0, 1)">)) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isNotExist(same.links, roads.id)) {
same.links.push(roads);
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isNotExist(same.links, roads.id)) {
same.links.push(roads);
}
flag </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">flag) {
same =<span style="color: rgba(0, 0, 0, 1)"> {
point: e,
links: , roads]
};
}
});
}
}
const linkVals </span>=<span style="color: rgba(0, 0, 0, 1)"> Object.values(same);
const allInter </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < linkVals.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
allInter </span>=<span style="color: rgba(0, 0, 0, 1)"> {
coords: [],
links: linkVals.links
};
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let j = 0; j < linkVals.links.length - 1; j++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let m = j + 1; m < linkVals.links.length; m++<span style="color: rgba(0, 0, 0, 1)">) {
const cPoint </span>=<span style="color: rgba(0, 0, 0, 1)"> linkVals.point;
const LL </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterPoint(linkVals.links.LCoords, linkVals.links.LCoords, cPoint);
const LR </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterPoint(linkVals.links.LCoords, linkVals.links.RCoords, cPoint);
const RL </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterPoint(linkVals.links.RCoords, linkVals.links.LCoords, cPoint);
const RR </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterPoint(linkVals.links.RCoords, linkVals.links.RCoords, cPoint);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (LL.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
const temp </span>=<span style="color: rgba(0, 0, 0, 1)"> getNearestPoint(LL, cPoint);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (temp.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
allInter.coords.push(temp);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (LR.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
const temp </span>=<span style="color: rgba(0, 0, 0, 1)"> getNearestPoint(LR, cPoint);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (temp.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
allInter.coords.push(temp);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (RL.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
const temp </span>=<span style="color: rgba(0, 0, 0, 1)"> getNearestPoint(RL, cPoint);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (temp.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
allInter.coords.push(temp);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (RR.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
const temp </span>=<span style="color: rgba(0, 0, 0, 1)"> getNearestPoint(RR, cPoint);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (temp.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
allInter.coords.push(temp);
}
}
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> allInter.filter(e => e.length !== 0<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 计算道路口
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getCross(roads) {
crossCtrl.removeAll();
const allInter </span>=<span style="color: rgba(0, 0, 0, 1)"> groupCross(roads);
allInter.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
const crossObj </span>=<span style="color: rgba(0, 0, 0, 1)"> getMaxPolygon(e.coords);
crossCtrl.add({
coords: crossObj,
linkRoad: e.links
});
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> drawPolygon(out);</span>
<span style="color: rgba(0, 0, 0, 1)"> });
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span> drawPoint(points, color = 'red'<span style="color: rgba(0, 0, 0, 1)">) {
ctx.save()
points.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
ctx.beginPath();
ctx.arc(...e, </span>3, 0, 2 *<span style="color: rgba(0, 0, 0, 1)"> Math.PI);
ctx.fillStyle </span>= color; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置原点的颜色</span>
<span style="color: rgba(0, 0, 0, 1)"> ctx.fill();
ctx.closePath();
});
ctx.restore();
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> drawPolygon(points) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (points.length === 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
ctx.save();
ctx.beginPath();
ctx.strokeStyle </span>= '#dbdae3'<span style="color: rgba(0, 0, 0, 1)">;
ctx.lineWidth </span>= 5<span style="color: rgba(0, 0, 0, 1)">;
ctx.moveTo(...points[</span>0<span style="color: rgba(0, 0, 0, 1)">]);
points.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
ctx.lineTo(...e);
});
ctx.closePath();
ctx.stroke();
ctx.fillStyle </span>= '#dbdae3'<span style="color: rgba(0, 0, 0, 1)">;
ctx.fill();
ctx.restore();
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> clear() {
roadCtrl.removeAll();
ctx.clearRect(</span>0, 0<span style="color: rgba(0, 0, 0, 1)">, canvasDom.offsetWidth, canvasDom.offsetHeight);
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> drawId(text, points) {
ctx.save();
ctx.font </span>= '15px Arial'<span style="color: rgba(0, 0, 0, 1)">;
ctx.fillStyle </span>= 'blue'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字颜色为蓝色</span>
ctx.textAlign = 'center'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 水平对齐方式为居中</span>
ctx.textBaseline = 'middle'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 垂直对齐方式为居中</span>
ctx.fillText(text, ...points); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在坐标(100, 100)处绘制文字</span>
<span style="color: rgba(0, 0, 0, 1)"> ctx.restore();
}
window.onload </span>= () =><span style="color: rgba(0, 0, 0, 1)"> {
initEvent();
}</span></pre>
</div>
<span class="cnblogs_code_collapse">main.js</span></div>
<p> 5. 创建道路类,包括绘制道路、获取扩展点等</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_a5b5e352-1076-443e-ab14-862520c82718" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_a5b5e352-1076-443e-ab14-862520c82718" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_a5b5e352-1076-443e-ab14-862520c82718" class="cnblogs_code_hide">
<pre>import { getBezierPoints, getIntersectionPoint, isClockWise, getIntersection, clone, calTriangleCenter } from './Util.js'<span style="color: rgba(0, 0, 0, 1)">;
class Road {
constructor(props) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 车道ID</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> props.id;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 顶点数</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords =<span style="color: rgba(0, 0, 0, 1)"> props.coords;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 单向车道数</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.laneNum = 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 道路宽度</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.width = props.width || 20<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 车道中心点信息</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.CCoords =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 左车道点信息</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 右车道点信息</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx =<span style="color: rgba(0, 0, 0, 1)"> props.ctx;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.init();
}
init() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.extendRoadCoord();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.draw();
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取线段上垂直的点
* @param {*} line
* @param {*} point
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
getVerticalPoint(line, point, width) {
const </span>= [...line];
const </span>= [...line];
const </span>=<span style="color: rgba(0, 0, 0, 1)"> [...point];
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (y1 - y2 !== 0<span style="color: rgba(0, 0, 0, 1)">) {
const beta </span>= Math.abs(Math.cos(Math.atan((x2 - x1) / (y1 - y2))) *<span style="color: rgba(0, 0, 0, 1)"> width);
const tempX1 </span>= px +<span style="color: rgba(0, 0, 0, 1)"> beta;
const tempX2 </span>= px -<span style="color: rgba(0, 0, 0, 1)"> beta;
const tempY1 </span>= (x2 - x1) / (y1 - y2) *<span style="color: rgba(0, 0, 0, 1)"> tempX1
</span>+ (py * (y1 - y2) - px * (x2 - x1)) / (y1 -<span style="color: rgba(0, 0, 0, 1)"> y2);
const tempY2 </span>= (x2 - x1) / (y1 - y2) *<span style="color: rgba(0, 0, 0, 1)"> tempX2
</span>+ (py * (y1 - y2) - px * (x2 - x1)) / (y1 -<span style="color: rgba(0, 0, 0, 1)"> y2);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [, ];
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> [, ];
}
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取道路扩展后的顶点信息
* 原理:通过判断两条线段是否有交点,如果有交点则代表扩展的点需要舍弃一个同时插入交点,否则线路就会有交叉
* 如果没有交点,则代表线段不相交,需要插入两条线段代表的直线的交点
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
getSideCoord() {
const </span>=<span style="color: rgba(0, 0, 0, 1)"> [[], []];
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i < <span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">){
const polygon </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
const preSides </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.getVerticalPoint([<span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords, <span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords], <span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.width);
const nextSides </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.getVerticalPoint([<span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords, <span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords], <span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.width);
polygon.push(preSides[</span>0], nextSides, nextSides, preSides);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isClockWise(polygon)) {
left.push(preSides[</span>0], nextSides);
right.push(preSides[</span>1], nextSides);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
left.push(preSides[</span>1], nextSides);
right.push(preSides[</span>0], nextSides);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> { left, right };
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 根据获取的边线顶点
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
extendRoadCoord() {
const sides </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getSideCoord();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.turnCoords.length <= 2<span style="color: rgba(0, 0, 0, 1)">) {
const cloneLeft </span>=<span style="color: rgba(0, 0, 0, 1)"> sides.left;
const cloneRight </span>=<span style="color: rgba(0, 0, 0, 1)"> sides.right;
const polygon </span>=<span style="color: rgba(0, 0, 0, 1)"> cloneLeft.concat(cloneRight.reverse());
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isClockWise(polygon)) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords =<span style="color: rgba(0, 0, 0, 1)"> sides.left;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords =<span style="color: rgba(0, 0, 0, 1)"> sides.right;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords =<span style="color: rgba(0, 0, 0, 1)"> sides.left;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords =<span style="color: rgba(0, 0, 0, 1)"> sides.right.reverse();
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.CCoords = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.turnCoords;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords.push(<span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords[<span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords.length - 1<span style="color: rgba(0, 0, 0, 1)">]);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords.unshift(<span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords.push(<span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords[<span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords.length - 1<span style="color: rgba(0, 0, 0, 1)">]);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords.unshift(<span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
const left </span>=<span style="color: rgba(0, 0, 0, 1)"> sides.left;
const right </span>=<span style="color: rgba(0, 0, 0, 1)"> sides.right;
let </span>= [[], []]; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 最终生成的道路左右边线顶点</span>
let =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < left.length - 2; i += 2<span style="color: rgba(0, 0, 0, 1)">) {
const interPoint </span>= getIntersectionPoint(, left], , left]);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (interPoint.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === 0<span style="color: rgba(0, 0, 0, 1)">) {
tempLeft.push(left, interPoint);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempLeft.push(interPoint);
}
preLeftInterPoint </span>=<span style="color: rgba(0, 0, 0, 1)"> interPoint;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线所组成的直线对应的交点</span>
const straightInterPoint = getIntersection(, left], , left]);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">preLeftInterPoint) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === 0<span style="color: rgba(0, 0, 0, 1)">) {
tempLeft.push(left, straightInterPoint);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempLeft.push(straightInterPoint);
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempLeft.push(straightInterPoint);
}
preLeftInterPoint </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === left.length - 4<span style="color: rgba(0, 0, 0, 1)">) {
tempLeft.push(left);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < right.length - 2; i += 2<span style="color: rgba(0, 0, 0, 1)">) {
const interPoint </span>= getIntersectionPoint(, right], , right]);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (interPoint.length !== 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === 0<span style="color: rgba(0, 0, 0, 1)">) {
tempRight.push(right, interPoint);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempRight.push(interPoint);
}
preRightInterPoint </span>=<span style="color: rgba(0, 0, 0, 1)"> interPoint;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线所组成的直线对应的交点</span>
const straightInterPoint = getIntersection(, right], , right]);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">preRightInterPoint) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === 0<span style="color: rgba(0, 0, 0, 1)">) {
tempRight.push(right, straightInterPoint);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempRight.push(straightInterPoint);
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
tempRight.push(straightInterPoint);
}
preRightInterPoint </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i === right.length - 4<span style="color: rgba(0, 0, 0, 1)">) {
tempRight.push(right);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.drawPoint(, tempLeft], 'red'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.drawPoint(, tempRight], 'blue'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 为了在末端绘制的更加圆滑,所以增加几个重复点,使用贝塞尔曲线绘制底色时不会出现圆弧</span>
tempLeft.push(tempLeft);
tempLeft.unshift(tempLeft[</span>0<span style="color: rgba(0, 0, 0, 1)">]);
tempRight.push(tempRight);
tempRight.unshift(tempRight[</span>0<span style="color: rgba(0, 0, 0, 1)">]);
tempRight.reverse();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.LCoords =<span style="color: rgba(0, 0, 0, 1)"> getBezierPoints(tempLeft);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.RCoords =<span style="color: rgba(0, 0, 0, 1)"> getBezierPoints(tempRight);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.CCoords = getBezierPoints(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.turnCoords);
}
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 绘制车道外轮廓
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
drawOutline() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘制左侧车道</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.drawLine(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.LCoords);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘制右侧车道</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.drawLine(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.RCoords);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘制车道中心线</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.drawLine(<span style="color: rgba(0, 0, 255, 1)">this</span>.CCoords, { color: '#aaa', dash: <span style="color: rgba(0, 0, 255, 1)">false</span>, width: 2<span style="color: rgba(0, 0, 0, 1)"> });
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 绘制道路背景色
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
drawBackground() {
const cloneLeft </span>= clone(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.LCoords);
const cloneRight </span>= clone(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.RCoords);
const polygon </span>=<span style="color: rgba(0, 0, 0, 1)"> cloneLeft.concat(cloneRight);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.save();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.moveTo(...polygon);
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < polygon.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">) {
const xc </span>= (polygon + polygon) / 2<span style="color: rgba(0, 0, 0, 1)">;
const yc </span>= (polygon + polygon) / 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.quadraticCurveTo(...polygon, xc, yc);
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineTo(...polygon);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineTo(...polygon);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.closePath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.fillStyle = '#dbdae3'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.fill();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.restore();
}
draw() {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawBackground();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawOutline();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawLane();
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 绘制车道线
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
drawLane() {
}
drawLine(points, style </span>=<span style="color: rgba(0, 0, 0, 1)"> {}) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.save();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.strokeStyle = style.color || '#666'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineWidth = style.width || 3<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineJoin = 'round'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (style.dash) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.setLineDash([<span style="color: rgba(0, 0, 255, 1)">this</span>.width * 0.8, <span style="color: rgba(0, 0, 255, 1)">this</span>.width * 0.6<span style="color: rgba(0, 0, 0, 1)">]);
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.moveTo(...points);
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < points.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">) {
const xc </span>= (points + points) / 2<span style="color: rgba(0, 0, 0, 1)">;
const yc </span>= (points + points) / 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.quadraticCurveTo(...points, xc, yc);
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineTo(...points);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.stroke();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.restore();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主要用来测试,直观的观察点的位置以及线的方向顺序</span>
<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawArrow(points);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> this.drawPoint(points, style.color);</span>
<span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 计算方向向量用于测试
* @param {*} start
* @param {*} end
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
calculateDirectionVector(start, end) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
dx: end.x </span>-<span style="color: rgba(0, 0, 0, 1)"> start.x,
dy: end.y </span>-<span style="color: rgba(0, 0, 0, 1)"> start.y
};
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 计算中间点 用于测试
* @param {*} start
* @param {*} end
* @returns
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
calculateMiddlePoint(start, end) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
x: (start.x </span>+ end.x) / 2<span style="color: rgba(0, 0, 0, 1)">,
y: (start.y </span>+ end.y) / 2<span style="color: rgba(0, 0, 0, 1)">
};
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 绘制方向向量用于测试
* @param {*} middle
* @param {*} direction
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
drawDirectionVector(middle, direction) {
const arrowLength </span>= 10<span style="color: rgba(0, 0, 0, 1)">;
const angle </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.atan2(direction.dy, direction.dx);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算箭头的两个端点</span>
const arrowX1 = middle.x + arrowLength * Math.cos(angle - Math.PI / 6<span style="color: rgba(0, 0, 0, 1)">);
const arrowY1 </span>= middle.y + arrowLength * Math.sin(angle - Math.PI / 6<span style="color: rgba(0, 0, 0, 1)">);
const arrowX2 </span>= middle.x + arrowLength * Math.cos(angle + Math.PI / 6<span style="color: rgba(0, 0, 0, 1)">);
const arrowY2 </span>= middle.y + arrowLength * Math.sin(angle + Math.PI / 6<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘制箭头</span>
<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.save();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.strokeStyle = '#666'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.moveTo(middle.x, middle.y);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.lineTo(arrowX1, arrowY1);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.moveTo(middle.x, middle.y);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.lineTo(arrowX2, arrowY2);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.stroke();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.restore();
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 绘制箭头,主要用于测试,查看绘制线路的方向
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
drawArrow(points) {
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < points.length - 1; i++<span style="color: rgba(0, 0, 0, 1)">) {
const start </span>= { x: points, y: points };
const end </span>= { x: points, y: points };
const directionVector </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.calculateDirectionVector(start, end);
const middlePoint </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.calculateMiddlePoint(start, end);
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawDirectionVector(middlePoint, directionVector);
}
}
drawPoint(points, color) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.save()
points.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.arc(...e, 3, 0, 2 *<span style="color: rgba(0, 0, 0, 1)"> Math.PI);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.fillStyle = color; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置原点的颜色</span>
<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.fill();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.closePath();
});
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.restore();
}
}
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> Road;</pre>
</div>
<span class="cnblogs_code_collapse">Road.js</span></div>
<p> 6. 创建道路管理器,用于存储、新建、删除和刷新道路</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_f5e1dbc4-eb60-495a-b7d8-0228f237a977" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_f5e1dbc4-eb60-495a-b7d8-0228f237a977" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_f5e1dbc4-eb60-495a-b7d8-0228f237a977" class="cnblogs_code_hide">
<pre>import Road from './Road.js'<span style="color: rgba(0, 0, 0, 1)">;
import { createRandomId } from </span>'./Util.js'<span style="color: rgba(0, 0, 0, 1)">;
let instances </span>= []; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 道路实例</span>
let ctx = <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> canvas上下文</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> setCtx(context) {
ctx </span>=<span style="color: rgba(0, 0, 0, 1)"> context;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 添加道路
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> addRoad(param) {
instances.push(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Road({
id: param.id </span>|| createRandomId('road'<span style="color: rgba(0, 0, 0, 1)">),
coords: param.coords,
width: param.width,
ctx
}));
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 删除道路
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> removeRoad(id) {
const index </span>= instances.findIndex(e => e.id ===<span style="color: rgba(0, 0, 0, 1)"> id);
instances.splice(index, </span>1<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 刷新绘制道路
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> refresh() {
instances.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
e.draw();
});
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> removeAll() {
instances </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getAllRoad() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> instances;
}
export {
setCtx,
addRoad,
removeRoad,
refresh,
removeAll,
getAllRoad
}</span></pre>
</div>
<span class="cnblogs_code_collapse">RoadControl.js</span></div>
<p> 7. 创建路口类</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_370b1552-765d-45fd-89ac-603c792bc761" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_370b1552-765d-45fd-89ac-603c792bc761" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_370b1552-765d-45fd-89ac-603c792bc761" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">class Cross {
constructor(props) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 路口ID</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> props.id;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 路口坐标</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.coords =<span style="color: rgba(0, 0, 0, 1)"> props.coords;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 路口连接的道路</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.linkRoad =<span style="color: rgba(0, 0, 0, 1)"> props.linkRoad;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx =<span style="color: rgba(0, 0, 0, 1)"> props.ctx;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.draw();
}
draw() {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.coords.length === 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.save();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.strokeStyle = '#dbdae3'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.lineWidth = 5<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.moveTo(...<span style="color: rgba(0, 0, 255, 1)">this</span>.coords);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.coords.forEach(e =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.lineTo(...e);
});
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.closePath();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.stroke();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.ctx.fillStyle = '#dbdae3'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.fill();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ctx.restore();
}
}
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> Cross;</pre>
</div>
<span class="cnblogs_code_collapse">Cross.js</span></div>
<p> 8. 创建路口管理器,用于存储、新建、删除等功能</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_94c1417e-7d04-4526-bc96-6d2a84deede5" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_94c1417e-7d04-4526-bc96-6d2a84deede5" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_94c1417e-7d04-4526-bc96-6d2a84deede5" class="cnblogs_code_hide">
<pre>import Cross from './Cross.js'<span style="color: rgba(0, 0, 0, 1)">;
import { createRandomId } from </span>'./Util.js'<span style="color: rgba(0, 0, 0, 1)">;
const instances </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
let ctx </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> setCtx(context) {
ctx </span>=<span style="color: rgba(0, 0, 0, 1)"> context;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> add(param) {
instances.push(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Cross({
id: param.id </span>|| createRandomId('cross'<span style="color: rgba(0, 0, 0, 1)">),
coords: param.coords,
linkRoad: param.linkRoad,
ctx
}));
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> remove() {
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> removeAll() {
instances.splice(</span>0<span style="color: rgba(0, 0, 0, 1)">, instances.length);
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getAllCross() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> instances;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> refresh() {
instances.forEach(e </span>=><span style="color: rgba(0, 0, 0, 1)"> {
e.draw();
})
}
export { setCtx, add, remove, removeAll, getAllCross, refresh };</span></pre>
</div>
<span class="cnblogs_code_collapse">CrossControl.js</span></div>
<p> </p><br><br>
来源:https://www.cnblogs.com/codeOnMar/p/18454913
頁:
[1]