Merge branch 'test' of https://git.code.tencent.com/lian-cbtc/jl-client into test
This commit is contained in:
commit
652e9aa5d7
@ -354,7 +354,7 @@ export function Jl3dpassflow(dom) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},3000);
|
},1000);
|
||||||
};
|
};
|
||||||
},1000);
|
},1000);
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ export function Jl3dpassflow(dom) {
|
|||||||
}
|
}
|
||||||
moveanimateupdate();
|
moveanimateupdate();
|
||||||
|
|
||||||
scope.anime = requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +468,7 @@ export function Jl3dpassflow(dom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(humans[i].stage == 0){
|
if(humans[i].stage == 0){
|
||||||
console.log(humans[i].doors);
|
// console.log(humans[i].doors);
|
||||||
zhajiin[humans[i].doors].waiting = 0;
|
zhajiin[humans[i].doors].waiting = 0;
|
||||||
humans[i].stage = 1;
|
humans[i].stage = 1;
|
||||||
}
|
}
|
||||||
@ -805,8 +805,7 @@ export function Jl3dpassflow(dom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function zhajicontrol(type,door){
|
function zhajicontrol(type,door){
|
||||||
console.log(door);
|
|
||||||
console.log(zhajiin);
|
|
||||||
let devicenum = door-1;
|
let devicenum = door-1;
|
||||||
if(type == "in"){
|
if(type == "in"){
|
||||||
deviceaction[zhajiin[devicenum].id].action.reset();
|
deviceaction[zhajiin[devicenum].id].action.reset();
|
||||||
|
1102
src/jlmap3d/jl3dpassflow/jl3dpassflownew.js
Normal file
1102
src/jlmap3d/jl3dpassflow/jl3dpassflownew.js
Normal file
File diff suppressed because it is too large
Load Diff
0
src/jlmap3d/jl3dpassflow/model/humanmanager.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmanager.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmodel.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmodel.js
Normal file
136
src/jlmap3d/jl3dpassflow/model/zonemanager.js
Normal file
136
src/jlmap3d/jl3dpassflow/model/zonemanager.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { ZoneModel } from '@/jlmap3d/jl3dpassflow/model/zonemodel.js';
|
||||||
|
|
||||||
|
let enter1 = {
|
||||||
|
code : '001',
|
||||||
|
name : "enter1",
|
||||||
|
type : "normal",
|
||||||
|
stage : "0",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(34,9.8,-6),
|
||||||
|
new THREE.Vector3(32,9.8,-6)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let enter2 = {
|
||||||
|
code : '002',
|
||||||
|
name : "enter2",
|
||||||
|
type : "normal",
|
||||||
|
stage : "0",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(35,9.8,31.5),
|
||||||
|
new THREE.Vector3(31,9.8,31.5)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let security = {
|
||||||
|
code : '003',
|
||||||
|
name : "security",
|
||||||
|
type : "device",
|
||||||
|
stage : "1",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(20.5,9.8,18),
|
||||||
|
new THREE.Vector3(21,9.8,21)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let entergate = {
|
||||||
|
code : '004',
|
||||||
|
name : "entergate",
|
||||||
|
type : "device",
|
||||||
|
stage : "2",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(6.3,9.8,17.4),
|
||||||
|
new THREE.Vector3(4.8,9.8,17.4),
|
||||||
|
new THREE.Vector3(3.4,9.8,17.4),
|
||||||
|
new THREE.Vector3(2.1,9.8,17.4),
|
||||||
|
new THREE.Vector3(0.7,9.8,17.4)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let standtop = {
|
||||||
|
code : '005',
|
||||||
|
name : "standtop",
|
||||||
|
type : "stand",
|
||||||
|
stage : "3",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(52.1,1.77,-1.8),
|
||||||
|
new THREE.Vector3(-63.5,1.77,-1.8)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let standdown = {
|
||||||
|
code : '006',
|
||||||
|
name : "standdown",
|
||||||
|
type : "stand",
|
||||||
|
stage : "3",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(52.1,1.77,24),
|
||||||
|
new THREE.Vector3(-64,1.77,24)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
//4是刚下车状态
|
||||||
|
let exitgate = {
|
||||||
|
code : '007',
|
||||||
|
name : "exitgate",
|
||||||
|
type : "device",
|
||||||
|
stage : "5",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(18.8,9.8,-0.27),
|
||||||
|
new THREE.Vector3(18.8,9.8,1.18),
|
||||||
|
new THREE.Vector3(18.8,9.8,2.64),
|
||||||
|
new THREE.Vector3(18.8,9.8,4.1),
|
||||||
|
new THREE.Vector3(18.8,9.8,5.4)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let exit1 = {
|
||||||
|
code : '008',
|
||||||
|
name : "exit1",
|
||||||
|
type : "normal",
|
||||||
|
stage : "6",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(28.2,9.8,-7),
|
||||||
|
new THREE.Vector3(30.5,9.8,-7.4)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let exit2 = {
|
||||||
|
code : '009',
|
||||||
|
name : "exit2",
|
||||||
|
type : "normal",
|
||||||
|
stage : "6",
|
||||||
|
railpoints : [
|
||||||
|
new THREE.Vector3(28.3,9.8,28.8),
|
||||||
|
new THREE.Vector3(31.2,9.8,28.8)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ZoneManager() {
|
||||||
|
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.name = "test";
|
||||||
|
|
||||||
|
this.list = [];
|
||||||
|
|
||||||
|
initzone();
|
||||||
|
|
||||||
|
function initzone(){
|
||||||
|
scope.list[enter1.name] = new ZoneModel(enter1);
|
||||||
|
scope.list[enter2.name] = new ZoneModel(enter2);
|
||||||
|
scope.list[security.name] = new ZoneModel(security);
|
||||||
|
scope.list[entergate.name] = new ZoneModel(entergate);
|
||||||
|
scope.list[standtop.name] = new ZoneModel(standtop);
|
||||||
|
scope.list[standdown.name] = new ZoneModel(standdown);
|
||||||
|
scope.list[exitgate.name] = new ZoneModel(exitgate);
|
||||||
|
scope.list[exit1.name] = new ZoneModel(exit1);
|
||||||
|
scope.list[exit2.name] = new ZoneModel(exit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getzoneposition = function(name){
|
||||||
|
// let random = Math.random();
|
||||||
|
let position = scope.list[name].railline.getPointAt(Math.random());
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/jlmap3d/jl3dpassflow/model/zonemodel.js
Normal file
15
src/jlmap3d/jl3dpassflow/model/zonemodel.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export function ZoneModel(data) {
|
||||||
|
var scope = this;
|
||||||
|
//code
|
||||||
|
this.code = data.code;
|
||||||
|
//命名
|
||||||
|
this.name = data.name;
|
||||||
|
this.type = data.type;
|
||||||
|
this.stage = data.stage;
|
||||||
|
this.status = 0;
|
||||||
|
//轨迹点
|
||||||
|
this.railpoints = data.railpoints;
|
||||||
|
|
||||||
|
this.railline = new THREE.CatmullRomCurve3(data.railpoints);
|
||||||
|
|
||||||
|
}
|
123
src/jlmap3d/jl3dpassflow/utils/AStar.js
Normal file
123
src/jlmap3d/jl3dpassflow/utils/AStar.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { BinaryHeap } from './BinaryHeap';
|
||||||
|
import { Utils } from './Utils.js';
|
||||||
|
|
||||||
|
class AStar {
|
||||||
|
static init (graph) {
|
||||||
|
for (let x = 0; x < graph.length; x++) {
|
||||||
|
//for(var x in graph) {
|
||||||
|
const node = graph[x];
|
||||||
|
node.f = 0;
|
||||||
|
node.g = 0;
|
||||||
|
node.h = 0;
|
||||||
|
node.cost = 1.0;
|
||||||
|
node.visited = false;
|
||||||
|
node.closed = false;
|
||||||
|
node.parent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static cleanUp (graph) {
|
||||||
|
for (let x = 0; x < graph.length; x++) {
|
||||||
|
const node = graph[x];
|
||||||
|
delete node.f;
|
||||||
|
delete node.g;
|
||||||
|
delete node.h;
|
||||||
|
delete node.cost;
|
||||||
|
delete node.visited;
|
||||||
|
delete node.closed;
|
||||||
|
delete node.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static heap () {
|
||||||
|
return new BinaryHeap(function (node) {
|
||||||
|
return node.f;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static search (graph, start, end) {
|
||||||
|
this.init(graph);
|
||||||
|
//heuristic = heuristic || astar.manhattan;
|
||||||
|
|
||||||
|
|
||||||
|
const openHeap = this.heap();
|
||||||
|
|
||||||
|
openHeap.push(start);
|
||||||
|
|
||||||
|
while (openHeap.size() > 0) {
|
||||||
|
|
||||||
|
// Grab the lowest f(x) to process next. Heap keeps this sorted for us.
|
||||||
|
const currentNode = openHeap.pop();
|
||||||
|
|
||||||
|
// End case -- result has been found, return the traced path.
|
||||||
|
if (currentNode === end) {
|
||||||
|
let curr = currentNode;
|
||||||
|
const ret = [];
|
||||||
|
while (curr.parent) {
|
||||||
|
ret.push(curr);
|
||||||
|
curr = curr.parent;
|
||||||
|
}
|
||||||
|
this.cleanUp(ret);
|
||||||
|
return ret.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal case -- move currentNode from open to closed, process each of its neighbours.
|
||||||
|
currentNode.closed = true;
|
||||||
|
|
||||||
|
// Find all neighbours for the current node. Optionally find diagonal neighbours as well (false by default).
|
||||||
|
const neighbours = this.neighbours(graph, currentNode);
|
||||||
|
|
||||||
|
for (let i = 0, il = neighbours.length; i < il; i++) {
|
||||||
|
const neighbour = neighbours[i];
|
||||||
|
|
||||||
|
if (neighbour.closed) {
|
||||||
|
// Not a valid node to process, skip to next neighbour.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The g score is the shortest distance from start to current node.
|
||||||
|
// We need to check if the path we have arrived at this neighbour is the shortest one we have seen yet.
|
||||||
|
const gScore = currentNode.g + neighbour.cost;
|
||||||
|
const beenVisited = neighbour.visited;
|
||||||
|
|
||||||
|
if (!beenVisited || gScore < neighbour.g) {
|
||||||
|
|
||||||
|
// Found an optimal (so far) path to this node. Take score for node to see how good it is.
|
||||||
|
neighbour.visited = true;
|
||||||
|
neighbour.parent = currentNode;
|
||||||
|
if (!neighbour.centroid || !end.centroid) throw new Error('Unexpected state');
|
||||||
|
neighbour.h = neighbour.h || this.heuristic(neighbour.centroid, end.centroid);
|
||||||
|
neighbour.g = gScore;
|
||||||
|
neighbour.f = neighbour.g + neighbour.h;
|
||||||
|
|
||||||
|
if (!beenVisited) {
|
||||||
|
// Pushing to heap will put it in proper place based on the 'f' value.
|
||||||
|
openHeap.push(neighbour);
|
||||||
|
} else {
|
||||||
|
// Already seen the node, but since it has been rescored we need to reorder it in the heap
|
||||||
|
openHeap.rescoreElement(neighbour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No result was found - empty array signifies failure to find path.
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
static heuristic (pos1, pos2) {
|
||||||
|
return Utils.distanceToSquared(pos1, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static neighbours (graph, node) {
|
||||||
|
const ret = [];
|
||||||
|
|
||||||
|
for (let e = 0; e < node.neighbours.length; e++) {
|
||||||
|
ret.push(graph[node.neighbours[e]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AStar };
|
134
src/jlmap3d/jl3dpassflow/utils/BinaryHeap.js
Normal file
134
src/jlmap3d/jl3dpassflow/utils/BinaryHeap.js
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// javascript-astar
|
||||||
|
// http://github.com/bgrins/javascript-astar
|
||||||
|
// Freely distributable under the MIT License.
|
||||||
|
// Implements the astar search algorithm in javascript using a binary heap.
|
||||||
|
|
||||||
|
class BinaryHeap {
|
||||||
|
constructor (scoreFunction) {
|
||||||
|
this.content = [];
|
||||||
|
this.scoreFunction = scoreFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
push (element) {
|
||||||
|
// Add the new element to the end of the array.
|
||||||
|
this.content.push(element);
|
||||||
|
|
||||||
|
// Allow it to sink down.
|
||||||
|
this.sinkDown(this.content.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pop () {
|
||||||
|
// Store the first element so we can return it later.
|
||||||
|
const result = this.content[0];
|
||||||
|
// Get the element at the end of the array.
|
||||||
|
const end = this.content.pop();
|
||||||
|
// If there are any elements left, put the end element at the
|
||||||
|
// start, and let it bubble up.
|
||||||
|
if (this.content.length > 0) {
|
||||||
|
this.content[0] = end;
|
||||||
|
this.bubbleUp(0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (node) {
|
||||||
|
const i = this.content.indexOf(node);
|
||||||
|
|
||||||
|
// When it is found, the process seen in 'pop' is repeated
|
||||||
|
// to fill up the hole.
|
||||||
|
const end = this.content.pop();
|
||||||
|
|
||||||
|
if (i !== this.content.length - 1) {
|
||||||
|
this.content[i] = end;
|
||||||
|
|
||||||
|
if (this.scoreFunction(end) < this.scoreFunction(node)) {
|
||||||
|
this.sinkDown(i);
|
||||||
|
} else {
|
||||||
|
this.bubbleUp(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size () {
|
||||||
|
return this.content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
rescoreElement (node) {
|
||||||
|
this.sinkDown(this.content.indexOf(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
sinkDown (n) {
|
||||||
|
// Fetch the element that has to be sunk.
|
||||||
|
const element = this.content[n];
|
||||||
|
|
||||||
|
// When at 0, an element can not sink any further.
|
||||||
|
while (n > 0) {
|
||||||
|
// Compute the parent element's index, and fetch it.
|
||||||
|
const parentN = ((n + 1) >> 1) - 1;
|
||||||
|
const parent = this.content[parentN];
|
||||||
|
|
||||||
|
if (this.scoreFunction(element) < this.scoreFunction(parent)) {
|
||||||
|
// Swap the elements if the parent is greater.
|
||||||
|
this.content[parentN] = element;
|
||||||
|
this.content[n] = parent;
|
||||||
|
// Update 'n' to continue at the new position.
|
||||||
|
n = parentN;
|
||||||
|
} else {
|
||||||
|
// Found a parent that is less, no need to sink any further.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bubbleUp (n) {
|
||||||
|
// Look up the target element and its score.
|
||||||
|
const length = this.content.length,
|
||||||
|
element = this.content[n],
|
||||||
|
elemScore = this.scoreFunction(element);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Compute the indices of the child elements.
|
||||||
|
const child2N = (n + 1) << 1,
|
||||||
|
child1N = child2N - 1;
|
||||||
|
// This is used to store the new position of the element,
|
||||||
|
// if any.
|
||||||
|
let swap = null;
|
||||||
|
let child1Score;
|
||||||
|
// If the first child exists (is inside the array)...
|
||||||
|
if (child1N < length) {
|
||||||
|
// Look it up and compute its score.
|
||||||
|
const child1 = this.content[child1N];
|
||||||
|
child1Score = this.scoreFunction(child1);
|
||||||
|
|
||||||
|
// If the score is less than our element's, we need to swap.
|
||||||
|
if (child1Score < elemScore) {
|
||||||
|
swap = child1N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same checks for the other child.
|
||||||
|
if (child2N < length) {
|
||||||
|
const child2 = this.content[child2N],
|
||||||
|
child2Score = this.scoreFunction(child2);
|
||||||
|
if (child2Score < (swap === null ? elemScore : child1Score)) {
|
||||||
|
swap = child2N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the element needs to be moved, swap it, and continue.
|
||||||
|
if (swap !== null) {
|
||||||
|
this.content[n] = this.content[swap];
|
||||||
|
this.content[swap] = element;
|
||||||
|
n = swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we are done.
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BinaryHeap };
|
200
src/jlmap3d/jl3dpassflow/utils/Builder.js
Normal file
200
src/jlmap3d/jl3dpassflow/utils/Builder.js
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import {
|
||||||
|
Vector3,
|
||||||
|
} from 'three';
|
||||||
|
|
||||||
|
import { Utils } from './Utils';
|
||||||
|
|
||||||
|
class Builder {
|
||||||
|
/**
|
||||||
|
* Constructs groups from the given navigation mesh.
|
||||||
|
* @param {Geometry} geometry
|
||||||
|
* @return {Zone}
|
||||||
|
*/
|
||||||
|
static buildZone (geometry) {
|
||||||
|
|
||||||
|
const navMesh = this._buildNavigationMesh(geometry);
|
||||||
|
|
||||||
|
const zone = {};
|
||||||
|
|
||||||
|
navMesh.vertices.forEach((v) => {
|
||||||
|
v.x = Utils.roundNumber(v.x, 2);
|
||||||
|
v.y = Utils.roundNumber(v.y, 2);
|
||||||
|
v.z = Utils.roundNumber(v.z, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
zone.vertices = navMesh.vertices;
|
||||||
|
|
||||||
|
const groups = this._buildPolygonGroups(navMesh);
|
||||||
|
|
||||||
|
// TODO: This block represents a large portion of navigation mesh construction time
|
||||||
|
// and could probably be optimized. For example, construct portals while
|
||||||
|
// determining the neighbor graph.
|
||||||
|
zone.groups = new Array(groups.length);
|
||||||
|
groups.forEach((group, groupIndex) => {
|
||||||
|
|
||||||
|
const indexByPolygon = new Map(); // { polygon: index in group }
|
||||||
|
group.forEach((poly, polyIndex) => { indexByPolygon.set(poly, polyIndex); });
|
||||||
|
|
||||||
|
const newGroup = new Array(group.length);
|
||||||
|
group.forEach((poly, polyIndex) => {
|
||||||
|
|
||||||
|
const neighbourIndices = [];
|
||||||
|
poly.neighbours.forEach((n) => neighbourIndices.push(indexByPolygon.get(n)));
|
||||||
|
|
||||||
|
// Build a portal list to each neighbour
|
||||||
|
const portals = [];
|
||||||
|
poly.neighbours.forEach((n) => portals.push(this._getSharedVerticesInOrder(poly, n)));
|
||||||
|
|
||||||
|
const centroid = new Vector3( 0, 0, 0 );
|
||||||
|
centroid.add( zone.vertices[ poly.vertexIds[0] ] );
|
||||||
|
centroid.add( zone.vertices[ poly.vertexIds[1] ] );
|
||||||
|
centroid.add( zone.vertices[ poly.vertexIds[2] ] );
|
||||||
|
centroid.divideScalar( 3 );
|
||||||
|
centroid.x = Utils.roundNumber(centroid.x, 2);
|
||||||
|
centroid.y = Utils.roundNumber(centroid.y, 2);
|
||||||
|
centroid.z = Utils.roundNumber(centroid.z, 2);
|
||||||
|
|
||||||
|
newGroup[polyIndex] = {
|
||||||
|
id: polyIndex,
|
||||||
|
neighbours: neighbourIndices,
|
||||||
|
vertexIds: poly.vertexIds,
|
||||||
|
centroid: centroid,
|
||||||
|
portals: portals
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
zone.groups[groupIndex] = newGroup;
|
||||||
|
});
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a navigation mesh from the given geometry.
|
||||||
|
* @param {Geometry} geometry
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
static _buildNavigationMesh (geometry) {
|
||||||
|
geometry.mergeVertices();
|
||||||
|
return this._buildPolygonsFromGeometry(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _buildPolygonGroups (navigationMesh) {
|
||||||
|
|
||||||
|
const polygons = navigationMesh.polygons;
|
||||||
|
|
||||||
|
const polygonGroups = [];
|
||||||
|
|
||||||
|
const spreadGroupId = function (polygon) {
|
||||||
|
polygon.neighbours.forEach((neighbour) => {
|
||||||
|
if (neighbour.group === undefined) {
|
||||||
|
neighbour.group = polygon.group;
|
||||||
|
spreadGroupId(neighbour);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
polygons.forEach((polygon) => {
|
||||||
|
if (polygon.group !== undefined) {
|
||||||
|
// this polygon is already part of a group
|
||||||
|
polygonGroups[polygon.group].push(polygon);
|
||||||
|
} else {
|
||||||
|
// we need to make a new group and spread its ID to neighbors
|
||||||
|
polygon.group = polygonGroups.length;
|
||||||
|
spreadGroupId(polygon);
|
||||||
|
polygonGroups.push([polygon]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return polygonGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _buildPolygonNeighbours (polygon, vertexPolygonMap) {
|
||||||
|
const neighbours = new Set();
|
||||||
|
|
||||||
|
const groupA = vertexPolygonMap[polygon.vertexIds[0]];
|
||||||
|
const groupB = vertexPolygonMap[polygon.vertexIds[1]];
|
||||||
|
const groupC = vertexPolygonMap[polygon.vertexIds[2]];
|
||||||
|
|
||||||
|
// It's only necessary to iterate groups A and B. Polygons contained only
|
||||||
|
// in group C cannot share a >1 vertex with this polygon.
|
||||||
|
// IMPORTANT: Bublé cannot compile for-of loops.
|
||||||
|
groupA.forEach((candidate) => {
|
||||||
|
if (candidate === polygon) return;
|
||||||
|
if (groupB.includes(candidate) || groupC.includes(candidate)) {
|
||||||
|
neighbours.add(candidate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
groupB.forEach((candidate) => {
|
||||||
|
if (candidate === polygon) return;
|
||||||
|
if (groupC.includes(candidate)) {
|
||||||
|
neighbours.add(candidate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return neighbours;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _buildPolygonsFromGeometry (geometry) {
|
||||||
|
|
||||||
|
const polygons = [];
|
||||||
|
const vertices = geometry.vertices;
|
||||||
|
|
||||||
|
// Constructing the neighbor graph brute force is O(n²). To avoid that,
|
||||||
|
// create a map from vertices to the polygons that contain them, and use it
|
||||||
|
// while connecting polygons. This reduces complexity to O(n*m), where 'm'
|
||||||
|
// is related to connectivity of the mesh.
|
||||||
|
const vertexPolygonMap = new Array(vertices.length); // array of polygon objects by vertex index
|
||||||
|
for (let i = 0; i < vertices.length; i++) {
|
||||||
|
vertexPolygonMap[i] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the faces into a custom format that supports more than 3 vertices
|
||||||
|
geometry.faces.forEach((face) => {
|
||||||
|
const poly = { vertexIds: [face.a, face.b, face.c], neighbours: null };
|
||||||
|
polygons.push(poly);
|
||||||
|
vertexPolygonMap[face.a].push(poly);
|
||||||
|
vertexPolygonMap[face.b].push(poly);
|
||||||
|
vertexPolygonMap[face.c].push(poly);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build a list of adjacent polygons
|
||||||
|
polygons.forEach((polygon) => {
|
||||||
|
polygon.neighbours = this._buildPolygonNeighbours(polygon, vertexPolygonMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
polygons: polygons,
|
||||||
|
vertices: vertices
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static _getSharedVerticesInOrder (a, b) {
|
||||||
|
|
||||||
|
const aList = a.vertexIds;
|
||||||
|
const a0 = aList[0], a1 = aList[1], a2 = aList[2];
|
||||||
|
|
||||||
|
const bList = b.vertexIds;
|
||||||
|
const shared0 = bList.includes(a0);
|
||||||
|
const shared1 = bList.includes(a1);
|
||||||
|
const shared2 = bList.includes(a2);
|
||||||
|
|
||||||
|
// it seems that we shouldn't have an a and b with <2 shared vertices here unless there's a bug
|
||||||
|
// in the neighbor identification code, or perhaps a malformed input geometry; 3 shared vertices
|
||||||
|
// is a kind of embarrassing but possible geometry we should handle
|
||||||
|
if (shared0 && shared1 && shared2) {
|
||||||
|
return Array.from(aList);
|
||||||
|
} else if (shared0 && shared1) {
|
||||||
|
return [a0, a1];
|
||||||
|
} else if (shared1 && shared2) {
|
||||||
|
return [a1, a2];
|
||||||
|
} else if (shared0 && shared2) {
|
||||||
|
return [a2, a0]; // this ordering will affect the string pull algorithm later, not clear if significant
|
||||||
|
} else {
|
||||||
|
console.warn("Error processing navigation mesh neighbors; neighbors with <2 shared vertices found.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Builder };
|
93
src/jlmap3d/jl3dpassflow/utils/Channel.js
Normal file
93
src/jlmap3d/jl3dpassflow/utils/Channel.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { Utils } from './Utils';
|
||||||
|
|
||||||
|
class Channel {
|
||||||
|
constructor () {
|
||||||
|
this.portals = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
push (p1, p2) {
|
||||||
|
if (p2 === undefined) p2 = p1;
|
||||||
|
this.portals.push({
|
||||||
|
left: p1,
|
||||||
|
right: p2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stringPull () {
|
||||||
|
const portals = this.portals;
|
||||||
|
const pts = [];
|
||||||
|
// Init scan state
|
||||||
|
let portalApex, portalLeft, portalRight;
|
||||||
|
let apexIndex = 0,
|
||||||
|
leftIndex = 0,
|
||||||
|
rightIndex = 0;
|
||||||
|
|
||||||
|
portalApex = portals[0].left;
|
||||||
|
portalLeft = portals[0].left;
|
||||||
|
portalRight = portals[0].right;
|
||||||
|
|
||||||
|
// Add start point.
|
||||||
|
pts.push(portalApex);
|
||||||
|
|
||||||
|
for (let i = 1; i < portals.length; i++) {
|
||||||
|
const left = portals[i].left;
|
||||||
|
const right = portals[i].right;
|
||||||
|
|
||||||
|
// Update right vertex.
|
||||||
|
if (Utils.triarea2(portalApex, portalRight, right) <= 0.0) {
|
||||||
|
if (Utils.vequal(portalApex, portalRight) || Utils.triarea2(portalApex, portalLeft, right) > 0.0) {
|
||||||
|
// Tighten the funnel.
|
||||||
|
portalRight = right;
|
||||||
|
rightIndex = i;
|
||||||
|
} else {
|
||||||
|
// Right over left, insert left to path and restart scan from portal left point.
|
||||||
|
pts.push(portalLeft);
|
||||||
|
// Make current left the new apex.
|
||||||
|
portalApex = portalLeft;
|
||||||
|
apexIndex = leftIndex;
|
||||||
|
// Reset portal
|
||||||
|
portalLeft = portalApex;
|
||||||
|
portalRight = portalApex;
|
||||||
|
leftIndex = apexIndex;
|
||||||
|
rightIndex = apexIndex;
|
||||||
|
// Restart scan
|
||||||
|
i = apexIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update left vertex.
|
||||||
|
if (Utils.triarea2(portalApex, portalLeft, left) >= 0.0) {
|
||||||
|
if (Utils.vequal(portalApex, portalLeft) || Utils.triarea2(portalApex, portalRight, left) < 0.0) {
|
||||||
|
// Tighten the funnel.
|
||||||
|
portalLeft = left;
|
||||||
|
leftIndex = i;
|
||||||
|
} else {
|
||||||
|
// Left over right, insert right to path and restart scan from portal right point.
|
||||||
|
pts.push(portalRight);
|
||||||
|
// Make current right the new apex.
|
||||||
|
portalApex = portalRight;
|
||||||
|
apexIndex = rightIndex;
|
||||||
|
// Reset portal
|
||||||
|
portalLeft = portalApex;
|
||||||
|
portalRight = portalApex;
|
||||||
|
leftIndex = apexIndex;
|
||||||
|
rightIndex = apexIndex;
|
||||||
|
// Restart scan
|
||||||
|
i = apexIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pts.length === 0) || (!Utils.vequal(pts[pts.length - 1], portals[portals.length - 1].left))) {
|
||||||
|
// Append last point to path.
|
||||||
|
pts.push(portals[portals.length - 1].left);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path = pts;
|
||||||
|
return pts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Channel };
|
315
src/jlmap3d/jl3dpassflow/utils/Pathfinding.js
Normal file
315
src/jlmap3d/jl3dpassflow/utils/Pathfinding.js
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
import {
|
||||||
|
Vector3,
|
||||||
|
Plane,
|
||||||
|
Geometry,
|
||||||
|
Triangle,
|
||||||
|
} from 'three';
|
||||||
|
|
||||||
|
import { Utils } from './Utils';
|
||||||
|
import { AStar } from './AStar';
|
||||||
|
import { Builder } from './Builder';
|
||||||
|
import { Channel } from './Channel';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines an instance of the pathfinding module, with one or more zones.
|
||||||
|
*/
|
||||||
|
class Pathfinding {
|
||||||
|
constructor () {
|
||||||
|
this.zones = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Static) Builds a zone/node set from navigation mesh geometry.
|
||||||
|
* @param {BufferGeometry} geometry
|
||||||
|
* @return {Zone}
|
||||||
|
*/
|
||||||
|
static createZone (geometry) {
|
||||||
|
if ( geometry.isGeometry ) {
|
||||||
|
// Haven't actually implemented support for BufferGeometry yet, but Geometry is somewhat
|
||||||
|
// not-recommended these days, so go ahead and start warning.
|
||||||
|
console.warn('[three-pathfinding]: Use BufferGeometry, not Geometry, to create zone.');
|
||||||
|
} else {
|
||||||
|
geometry = new Geometry().fromBufferGeometry(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Builder.buildZone(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets data for the given zone.
|
||||||
|
* @param {string} zoneID
|
||||||
|
* @param {Zone} zone
|
||||||
|
*/
|
||||||
|
setZoneData (zoneID, zone) {
|
||||||
|
this.zones[zoneID] = zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random node within a given range of a given position.
|
||||||
|
* @param {string} zoneID
|
||||||
|
* @param {number} groupID
|
||||||
|
* @param {Vector3} nearPosition
|
||||||
|
* @param {number} nearRange
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
getRandomNode (zoneID, groupID, nearPosition, nearRange) {
|
||||||
|
|
||||||
|
if (!this.zones[zoneID]) return new Vector3();
|
||||||
|
|
||||||
|
nearPosition = nearPosition || null;
|
||||||
|
nearRange = nearRange || 0;
|
||||||
|
|
||||||
|
const candidates = [];
|
||||||
|
const polygons = this.zones[zoneID].groups[groupID];
|
||||||
|
|
||||||
|
polygons.forEach((p) => {
|
||||||
|
if (nearPosition && nearRange) {
|
||||||
|
if (Utils.distanceToSquared(nearPosition, p.centroid) < nearRange * nearRange) {
|
||||||
|
candidates.push(p.centroid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
candidates.push(p.centroid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Utils.sample(candidates) || new Vector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the closest node to the target position.
|
||||||
|
* @param {Vector3} position
|
||||||
|
* @param {string} zoneID
|
||||||
|
* @param {number} groupID
|
||||||
|
* @param {boolean} checkPolygon
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
getClosestNode (position, zoneID, groupID, checkPolygon = false) {
|
||||||
|
const nodes = this.zones[zoneID].groups[groupID];
|
||||||
|
const vertices = this.zones[zoneID].vertices;
|
||||||
|
let closestNode = null;
|
||||||
|
let closestDistance = Infinity;
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const distance = Utils.distanceToSquared(node.centroid, position);
|
||||||
|
if (distance < closestDistance
|
||||||
|
&& (!checkPolygon || Utils.isVectorInPolygon(position, node, vertices))) {
|
||||||
|
closestNode = node;
|
||||||
|
closestDistance = distance;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return closestNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a path between given start and end points. If a complete path
|
||||||
|
* cannot be found, will return the nearest endpoint available.
|
||||||
|
*
|
||||||
|
* @param {Vector3} startPosition Start position.
|
||||||
|
* @param {Vector3} targetPosition Destination.
|
||||||
|
* @param {string} zoneID ID of current zone.
|
||||||
|
* @param {number} groupID Current group ID.
|
||||||
|
* @return {Array<Vector3>} Array of points defining the path.
|
||||||
|
*/
|
||||||
|
findPath (startPosition, targetPosition, zoneID, groupID) {
|
||||||
|
const nodes = this.zones[zoneID].groups[groupID];
|
||||||
|
const vertices = this.zones[zoneID].vertices;
|
||||||
|
|
||||||
|
const closestNode = this.getClosestNode(startPosition, zoneID, groupID, true);
|
||||||
|
const farthestNode = this.getClosestNode(targetPosition, zoneID, groupID, true);
|
||||||
|
|
||||||
|
// If we can't find any node, just go straight to the target
|
||||||
|
if (!closestNode || !farthestNode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const paths = AStar.search(nodes, closestNode, farthestNode);
|
||||||
|
|
||||||
|
const getPortalFromTo = function (a, b) {
|
||||||
|
for (var i = 0; i < a.neighbours.length; i++) {
|
||||||
|
if (a.neighbours[i] === b.id) {
|
||||||
|
return a.portals[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// We have the corridor, now pull the rope.
|
||||||
|
const channel = new Channel();
|
||||||
|
channel.push(startPosition);
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
const polygon = paths[i];
|
||||||
|
const nextPolygon = paths[i + 1];
|
||||||
|
|
||||||
|
if (nextPolygon) {
|
||||||
|
const portals = getPortalFromTo(polygon, nextPolygon);
|
||||||
|
channel.push(
|
||||||
|
vertices[portals[0]],
|
||||||
|
vertices[portals[1]]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channel.push(targetPosition);
|
||||||
|
channel.stringPull();
|
||||||
|
|
||||||
|
// Return the path, omitting first position (which is already known).
|
||||||
|
const path = channel.path.map((c) => new Vector3(c.x, c.y, c.z));
|
||||||
|
path.shift();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns closest node group ID for given position.
|
||||||
|
* @param {string} zoneID
|
||||||
|
* @param {Vector3} position
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
Pathfinding.prototype.getGroup = (function() {
|
||||||
|
const plane = new Plane();
|
||||||
|
return function (zoneID, position, checkPolygon = false) {
|
||||||
|
if (!this.zones[zoneID]) return null;
|
||||||
|
|
||||||
|
let closestNodeGroup = null;
|
||||||
|
let distance = Math.pow(50, 2);
|
||||||
|
const zone = this.zones[zoneID];
|
||||||
|
|
||||||
|
for (let i = 0; i < zone.groups.length; i++) {
|
||||||
|
const group = zone.groups[i];
|
||||||
|
for (const node of group) {
|
||||||
|
if (checkPolygon) {
|
||||||
|
plane.setFromCoplanarPoints(
|
||||||
|
zone.vertices[node.vertexIds[0]],
|
||||||
|
zone.vertices[node.vertexIds[1]],
|
||||||
|
zone.vertices[node.vertexIds[2]]
|
||||||
|
);
|
||||||
|
if (Math.abs(plane.distanceToPoint(position)) < 0.01) {
|
||||||
|
const poly = [
|
||||||
|
zone.vertices[node.vertexIds[0]],
|
||||||
|
zone.vertices[node.vertexIds[1]],
|
||||||
|
zone.vertices[node.vertexIds[2]]
|
||||||
|
];
|
||||||
|
if(Utils.isPointInPoly(poly, position)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const measuredDistance = Utils.distanceToSquared(node.centroid, position);
|
||||||
|
if (measuredDistance < distance) {
|
||||||
|
closestNodeGroup = i;
|
||||||
|
distance = measuredDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestNodeGroup;
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps a step along the navmesh, given start and desired endpoint. May be
|
||||||
|
* used to constrain first-person / WASD controls.
|
||||||
|
*
|
||||||
|
* @param {Vector3} start
|
||||||
|
* @param {Vector3} end Desired endpoint.
|
||||||
|
* @param {Node} node
|
||||||
|
* @param {string} zoneID
|
||||||
|
* @param {number} groupID
|
||||||
|
* @param {Vector3} endTarget Updated endpoint.
|
||||||
|
* @return {Node} Updated node.
|
||||||
|
*/
|
||||||
|
Pathfinding.prototype.clampStep = (function () {
|
||||||
|
const point = new Vector3();
|
||||||
|
const plane = new Plane();
|
||||||
|
const triangle = new Triangle();
|
||||||
|
|
||||||
|
const endPoint = new Vector3();
|
||||||
|
|
||||||
|
let closestNode;
|
||||||
|
let closestPoint = new Vector3();
|
||||||
|
let closestDistance;
|
||||||
|
|
||||||
|
return function (startRef, endRef, node, zoneID, groupID, endTarget) {
|
||||||
|
const vertices = this.zones[zoneID].vertices;
|
||||||
|
const nodes = this.zones[zoneID].groups[groupID];
|
||||||
|
|
||||||
|
const nodeQueue = [node];
|
||||||
|
const nodeDepth = {};
|
||||||
|
nodeDepth[node.id] = 0;
|
||||||
|
|
||||||
|
closestNode = undefined;
|
||||||
|
closestPoint.set(0, 0, 0);
|
||||||
|
closestDistance = Infinity;
|
||||||
|
|
||||||
|
// Project the step along the current node.
|
||||||
|
plane.setFromCoplanarPoints(
|
||||||
|
vertices[node.vertexIds[0]],
|
||||||
|
vertices[node.vertexIds[1]],
|
||||||
|
vertices[node.vertexIds[2]]
|
||||||
|
);
|
||||||
|
plane.projectPoint(endRef, point);
|
||||||
|
endPoint.copy(point);
|
||||||
|
|
||||||
|
for (let currentNode = nodeQueue.pop(); currentNode; currentNode = nodeQueue.pop()) {
|
||||||
|
|
||||||
|
triangle.set(
|
||||||
|
vertices[currentNode.vertexIds[0]],
|
||||||
|
vertices[currentNode.vertexIds[1]],
|
||||||
|
vertices[currentNode.vertexIds[2]]
|
||||||
|
);
|
||||||
|
|
||||||
|
triangle.closestPointToPoint(endPoint, point);
|
||||||
|
|
||||||
|
if (point.distanceToSquared(endPoint) < closestDistance) {
|
||||||
|
closestNode = currentNode;
|
||||||
|
closestPoint.copy(point);
|
||||||
|
closestDistance = point.distanceToSquared(endPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
const depth = nodeDepth[currentNode.id];
|
||||||
|
if (depth > 2) continue;
|
||||||
|
|
||||||
|
for (let i = 0; i < currentNode.neighbours.length; i++) {
|
||||||
|
const neighbour = nodes[currentNode.neighbours[i]];
|
||||||
|
if (neighbour.id in nodeDepth) continue;
|
||||||
|
|
||||||
|
nodeQueue.push(neighbour);
|
||||||
|
nodeDepth[neighbour.id] = depth + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endTarget.copy(closestPoint);
|
||||||
|
return closestNode;
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a zone of interconnected groups on a navigation mesh.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
* @property {Array<Group>} groups
|
||||||
|
* @property {Array<Vector3>} vertices
|
||||||
|
*/
|
||||||
|
const Zone = {}; // jshint ignore:line
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a group within a navigation mesh.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
const Group = {}; // jshint ignore:line
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a node (or polygon) within a group.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
* @property {number} id
|
||||||
|
* @property {Array<number>} neighbours IDs of neighboring nodes.
|
||||||
|
* @property {Array<number>} vertexIds
|
||||||
|
* @property {Vector3} centroid
|
||||||
|
* @property {Array<Array<number>>} portals Array of portals, each defined by two vertex IDs.
|
||||||
|
* @property {boolean} closed
|
||||||
|
* @property {number} cost
|
||||||
|
*/
|
||||||
|
const Node = {}; // jshint ignore:line
|
||||||
|
|
||||||
|
export { Pathfinding };
|
53
src/jlmap3d/jl3dpassflow/utils/PathfindingHelper.js
Normal file
53
src/jlmap3d/jl3dpassflow/utils/PathfindingHelper.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import {
|
||||||
|
Color,
|
||||||
|
Object3D,
|
||||||
|
LineBasicMaterial,
|
||||||
|
MeshBasicMaterial,
|
||||||
|
SphereBufferGeometry,
|
||||||
|
BoxGeometry,
|
||||||
|
Mesh,
|
||||||
|
SphereGeometry,
|
||||||
|
Geometry,
|
||||||
|
Vector3,
|
||||||
|
Line,
|
||||||
|
} from 'three';
|
||||||
|
|
||||||
|
const OFFSET = 0.2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for debugging pathfinding behavior.
|
||||||
|
*/
|
||||||
|
class PathfindingHelper extends Object3D {
|
||||||
|
constructor () {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._playerMarker = null;
|
||||||
|
|
||||||
|
this._markers = [
|
||||||
|
this._playerMarker,
|
||||||
|
];
|
||||||
|
|
||||||
|
this._markers.forEach( ( marker ) => {
|
||||||
|
this.add( marker );
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Vector3} position
|
||||||
|
* @return {this}
|
||||||
|
*/
|
||||||
|
setPlayerPosition( position ) {
|
||||||
|
// this._playerMarker.lookAt(position);
|
||||||
|
this._playerMarker.position.copy( position );
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PathfindingHelper };
|
66
src/jlmap3d/jl3dpassflow/utils/Utils.js
Normal file
66
src/jlmap3d/jl3dpassflow/utils/Utils.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
class Utils {
|
||||||
|
|
||||||
|
static roundNumber (value, decimals) {
|
||||||
|
const factor = Math.pow(10, decimals);
|
||||||
|
return Math.round(value * factor) / factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sample (list) {
|
||||||
|
return list[Math.floor(Math.random() * list.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static distanceToSquared (a, b) {
|
||||||
|
|
||||||
|
var dx = a.x - b.x;
|
||||||
|
var dy = a.y - b.y;
|
||||||
|
var dz = a.z - b.z;
|
||||||
|
|
||||||
|
return dx * dx + dy * dy + dz * dz;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//+ Jonas Raoni Soares Silva
|
||||||
|
//@ http://jsfromhell.com/math/is-point-in-poly [rev. #0]
|
||||||
|
static isPointInPoly (poly, pt) {
|
||||||
|
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
|
||||||
|
((poly[i].z <= pt.z && pt.z < poly[j].z) || (poly[j].z <= pt.z && pt.z < poly[i].z)) && (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x) && (c = !c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isVectorInPolygon (vector, polygon, vertices) {
|
||||||
|
|
||||||
|
// reference point will be the centroid of the polygon
|
||||||
|
// We need to rotate the vector as well as all the points which the polygon uses
|
||||||
|
|
||||||
|
var lowestPoint = 100000;
|
||||||
|
var highestPoint = -100000;
|
||||||
|
|
||||||
|
var polygonVertices = [];
|
||||||
|
|
||||||
|
polygon.vertexIds.forEach((vId) => {
|
||||||
|
lowestPoint = Math.min(vertices[vId].y, lowestPoint);
|
||||||
|
highestPoint = Math.max(vertices[vId].y, highestPoint);
|
||||||
|
polygonVertices.push(vertices[vId]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (vector.y < highestPoint + 0.5 && vector.y > lowestPoint - 0.5 &&
|
||||||
|
this.isPointInPoly(polygonVertices, vector)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static triarea2 (a, b, c) {
|
||||||
|
var ax = b.x - a.x;
|
||||||
|
var az = b.z - a.z;
|
||||||
|
var bx = c.x - a.x;
|
||||||
|
var bz = c.z - a.z;
|
||||||
|
return bx * az - ax * bz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vequal (a, b) {
|
||||||
|
return this.distanceToSquared(a, b) < 0.00001;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Utils };
|
4
src/jlmap3d/jl3dpassflow/utils/index.js
Normal file
4
src/jlmap3d/jl3dpassflow/utils/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Pathfinding } from './Pathfinding';
|
||||||
|
import { PathfindingHelper } from './PathfindingHelper';
|
||||||
|
|
||||||
|
export { Pathfinding, PathfindingHelper };
|
@ -53,12 +53,12 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
|||||||
jsonwebwork.onmessage = function (event) {
|
jsonwebwork.onmessage = function (event) {
|
||||||
|
|
||||||
|
|
||||||
|
// console.log(event.data);
|
||||||
// if(event.data.deviceType == "TRAIN"){
|
// if(event.data.deviceType == "TRAIN"){
|
||||||
// // console.log(event.data);
|
// // console.log(event.data);
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
console.log(event.data);
|
// console.log(event.data);
|
||||||
if(event.data.type == "Device_Load_Destroy_3D"){
|
if(event.data.type == "Device_Load_Destroy_3D"){
|
||||||
DeviceDestroy(event.data);
|
DeviceDestroy(event.data);
|
||||||
return;
|
return;
|
||||||
@ -150,7 +150,6 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
|||||||
let code = data.code;
|
let code = data.code;
|
||||||
|
|
||||||
if(trainlisttest.list[code].right != data.right){
|
if(trainlisttest.list[code].right != data.right){
|
||||||
|
|
||||||
if(data.right == "0"){
|
if(data.right == "0"){
|
||||||
trainlisttest.list[code].right = "0";
|
trainlisttest.list[code].right = "0";
|
||||||
trainlisttest.list[code].rotation.y = Math.PI;
|
trainlisttest.list[code].rotation.y = Math.PI;
|
||||||
@ -442,27 +441,28 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
|||||||
for(let i=0,leni=data.length;i<leni;i++){
|
for(let i=0,leni=data.length;i<leni;i++){
|
||||||
if(data[i].deviceType == "SWITCH"){
|
if(data[i].deviceType == "SWITCH"){
|
||||||
initswitch(data[i]);
|
initswitch(data[i]);
|
||||||
}
|
}else if(data[i].deviceType == "PSD"){
|
||||||
if(data[i].deviceType == "PSD"){
|
|
||||||
initstand(data[i]);
|
initstand(data[i]);
|
||||||
|
}else{
|
||||||
|
console.log(data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeviceDestroy(data){
|
function DeviceDestroy(data){
|
||||||
for(let i=0,leni=data.body.length;i<leni;i++){
|
for(let i=0,leni=data.body.deviceList.length;i<leni;i++){
|
||||||
|
|
||||||
if(data.body[i].type == "TRAIN"){
|
if(data.body.deviceList[i].type == "TRAIN"){
|
||||||
code =data.body[i].code;
|
code =data.body.deviceList[i].code;
|
||||||
if (trainlisttest.list[code].dispose != data.body[i].dispose && data.body[i].dispose == "0") {
|
if (trainlisttest.list[code].dispose != data.body.deviceList[i].dispose && data.body.deviceList[i].dispose == "0") {
|
||||||
|
|
||||||
if (rails.sectionrail[data.body[i].section]) {
|
if (rails.sectionrail[data.body.deviceList[i].section]) {
|
||||||
|
|
||||||
trainlisttest.group.add(trainlisttest.list[code]);
|
trainlisttest.group.add(trainlisttest.list[code]);
|
||||||
trainlisttest.list[code].position.y = 0;
|
trainlisttest.list[code].position.y = 0;
|
||||||
// trainlisttest.list[code].progress = 0;
|
// trainlisttest.list[code].progress = 0;
|
||||||
trainlisttest.list[code].dispose = "0";
|
trainlisttest.list[code].dispose = "0";
|
||||||
trainlisttest.list[code].nowcode = data.body[i].section;
|
trainlisttest.list[code].nowcode = data.body.deviceList[i].section;
|
||||||
trainlisttest.list[code].nextcode = null;
|
trainlisttest.list[code].nextcode = null;
|
||||||
trainlisttest.list[code].curve = null;
|
trainlisttest.list[code].curve = null;
|
||||||
trainlisttest.list[code].nextcurve = null;
|
trainlisttest.list[code].nextcurve = null;
|
||||||
@ -476,7 +476,7 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
|||||||
trainlisttest.list[code].mixerpush = true;
|
trainlisttest.list[code].mixerpush = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (trainlisttest.list[code].dispose != data.body[i].dispose && data.body[i].dispose == "1") {
|
} else if (trainlisttest.list[code].dispose != data.body.deviceList[i].dispose && data.body.deviceList[i].dispose == "1") {
|
||||||
trainlisttest.list[code].status = 1;
|
trainlisttest.list[code].status = 1;
|
||||||
trainlisttest.group.remove(trainlisttest.list[code]);
|
trainlisttest.group.remove(trainlisttest.list[code]);
|
||||||
trainlisttest.list[code].progress = null;
|
trainlisttest.list[code].progress = null;
|
||||||
@ -493,17 +493,17 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(data.body[i].type == "SIGNAL"){
|
if(data.body.deviceList[i].type == "SIGNAL"){
|
||||||
signalupdate(data.body[i]);
|
signalupdate(data.body.deviceList[i]);
|
||||||
}
|
}
|
||||||
if(data.body[i].type == "SWITCH"){
|
if(data.body.deviceList[i].type == "SWITCH"){
|
||||||
switchupdate(data.body[i]);
|
switchupdate(data.body.deviceList[i]);
|
||||||
}
|
}
|
||||||
if(data.body[i].type == "PSD"){
|
if(data.body.deviceList[i].type == "PSD"){
|
||||||
standupdate(data.body[i]);
|
standupdate(data.body.deviceList[i]);
|
||||||
}
|
}
|
||||||
if(data.body[i].type == "TRAIN_DOOR"){
|
if(data.body.deviceList[i].type == "TRAIN_DOOR"){
|
||||||
traindoorupdate(data.body[i]);
|
traindoorupdate(data.body.deviceList[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.StationStand] = {
|
this[deviceType.StationStand] = {
|
||||||
common: { // 通用属性
|
common: { // 通用属性
|
||||||
textFontSize: 8, // 站台默认字体大小
|
textFontSize: 8, // 站台默认字体大小
|
||||||
|
@ -363,6 +363,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.Switch] = {
|
this[deviceType.Switch] = {
|
||||||
text: {
|
text: {
|
||||||
show: true, // 道岔名称显示
|
show: true, // 道岔名称显示
|
||||||
|
@ -200,6 +200,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.StationStand] = {
|
this[deviceType.StationStand] = {
|
||||||
common: { // 通用属性
|
common: { // 通用属性
|
||||||
textFontSize: 10, // 站台默认字体大小
|
textFontSize: 10, // 站台默认字体大小
|
||||||
|
@ -383,6 +383,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.Switch] = {
|
this[deviceType.Switch] = {
|
||||||
text: {
|
text: {
|
||||||
show: true, // 道岔名称显示
|
show: true, // 道岔名称显示
|
||||||
|
@ -329,8 +329,8 @@ class SkinCode extends defaultStyle {
|
|||||||
},
|
},
|
||||||
StationControl:{
|
StationControl:{
|
||||||
text: {
|
text: {
|
||||||
distance: 2, // 灯和文字之间的距离
|
distance: 10, // 灯和文字之间的距离
|
||||||
fontSize: 11, // 字体大小
|
fontSize: 14, // 字体大小
|
||||||
fontFormat: 'consolas', // 字体格式
|
fontFormat: 'consolas', // 字体格式
|
||||||
fontColor: '#ffffff', // 字体颜色
|
fontColor: '#ffffff', // 字体颜色
|
||||||
fontWeight: 'normal', // 字体粗细
|
fontWeight: 'normal', // 字体粗细
|
||||||
@ -345,9 +345,9 @@ class SkinCode extends defaultStyle {
|
|||||||
},
|
},
|
||||||
lamp: {
|
lamp: {
|
||||||
count: 2, // 控制模式灯个数
|
count: 2, // 控制模式灯个数
|
||||||
offset: {x: 0, y: 0}, // 控制模式灯偏移量
|
offset: {x: 0, y: 3}, // 控制模式灯偏移量
|
||||||
radiusR: 4, // 控制模式灯的半径
|
radiusR: 7, // 控制模式灯的半径
|
||||||
distance: 36, // 控制模式之间灯之间的距离
|
distance: 42, // 控制模式之间灯之间的距离
|
||||||
grayColor: '#7F7F7F', // 控制模式灰色
|
grayColor: '#7F7F7F', // 控制模式灰色
|
||||||
greenColor: '#00FF00', // 控制模式绿色
|
greenColor: '#00FF00', // 控制模式绿色
|
||||||
redColor: '#FF0000', // 控制模式红色
|
redColor: '#FF0000', // 控制模式红色
|
||||||
@ -418,6 +418,12 @@ class SkinCode extends defaultStyle {
|
|||||||
this[deviceType.Line] = {
|
this[deviceType.Line] = {
|
||||||
lineColor: '#FFFFFF' // 线条颜色
|
lineColor: '#FFFFFF' // 线条颜色
|
||||||
};
|
};
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 8 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.LcControl] = {
|
this[deviceType.LcControl] = {
|
||||||
text: {
|
text: {
|
||||||
|
@ -392,6 +392,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.Switch] = {
|
this[deviceType.Switch] = {
|
||||||
text: {
|
text: {
|
||||||
show: true, // 道岔名称显示
|
show: true, // 道岔名称显示
|
||||||
|
@ -411,6 +411,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.StationDelayUnlock] = {
|
this[deviceType.StationDelayUnlock] = {
|
||||||
text: {
|
text: {
|
||||||
distance: 3, // 延迟解锁和设备之间的距离
|
distance: 3, // 延迟解锁和设备之间的距离
|
||||||
|
@ -387,6 +387,13 @@ class SkinCode extends defaultStyle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.Switch] = {
|
this[deviceType.Switch] = {
|
||||||
text: {
|
text: {
|
||||||
show: true, // 道岔名称显示
|
show: true, // 道岔名称显示
|
||||||
|
@ -509,6 +509,14 @@ class SkinCode extends defaultStyle {
|
|||||||
lineColor: '#FFFFFF', // 线条颜色
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
lineDash: [8, 4]
|
lineDash: [8, 4]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 供电线路
|
||||||
|
this[deviceType.Power] = {
|
||||||
|
lineColor: '#FFFFFF', // 线条颜色
|
||||||
|
strokeColor: '#ccc', // 线条颜色
|
||||||
|
extendLength: 10 // 延伸长度
|
||||||
|
};
|
||||||
|
|
||||||
this[deviceType.AutomaticRoute] = {
|
this[deviceType.AutomaticRoute] = {
|
||||||
// 是否显示
|
// 是否显示
|
||||||
displayCondition: '03', // 显示条件 prdType
|
displayCondition: '03', // 显示条件 prdType
|
||||||
|
@ -245,4 +245,9 @@ deviceRender[deviceType.Arrow] = {
|
|||||||
_type: deviceType.Arrow,
|
_type: deviceType.Arrow,
|
||||||
zlevel: 1
|
zlevel: 1
|
||||||
};
|
};
|
||||||
|
/** 供电线路 */
|
||||||
|
deviceRender[deviceType.Power] = {
|
||||||
|
_type: deviceType.Power,
|
||||||
|
zlevel: 1
|
||||||
|
};
|
||||||
export default deviceRender;
|
export default deviceRender;
|
||||||
|
@ -42,7 +42,8 @@ const deviceType = {
|
|||||||
Axle: 'Axle',
|
Axle: 'Axle',
|
||||||
SplitStation:'SplitStation',
|
SplitStation:'SplitStation',
|
||||||
SwitchFault: 'SwitchFault',
|
SwitchFault: 'SwitchFault',
|
||||||
Arrow: 'Arrow'
|
Arrow: 'Arrow',
|
||||||
|
Power: 'Power'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default deviceType;
|
export default deviceType;
|
||||||
|
47
src/jmapNew/shape/Power/ESeparator.js
Normal file
47
src/jmapNew/shape/Power/ESeparator.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import Group from 'zrender/src/container/Group';
|
||||||
|
import Polyline from 'zrender/src/graphic/shape/Polyline';
|
||||||
|
|
||||||
|
/** 分隔符*/
|
||||||
|
export default class ESeparator extends Group {
|
||||||
|
constructor(model) {
|
||||||
|
super();
|
||||||
|
this.model = model;
|
||||||
|
this.zlevel = model.zlevel;
|
||||||
|
this.z = model.z || 6;
|
||||||
|
this.style = model.style;
|
||||||
|
this.setType();
|
||||||
|
}
|
||||||
|
|
||||||
|
createModel(points) {
|
||||||
|
const model = this.model;
|
||||||
|
this.partition = new Polyline({
|
||||||
|
zlevel: this.zlevel,
|
||||||
|
progressive: model.progressive,
|
||||||
|
z: this.z,
|
||||||
|
shape: {
|
||||||
|
points: points
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
lineWidth: model.width,
|
||||||
|
stroke: model.stroke
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.add(this.partition);
|
||||||
|
}
|
||||||
|
|
||||||
|
setType() {
|
||||||
|
const model = this.model;
|
||||||
|
if (model && model.traingle) {
|
||||||
|
const points = [
|
||||||
|
[model.point.x, model.point.y - (this.style.Power.extendLength)],
|
||||||
|
[model.point.x, model.point.y + (this.style.Power.extendLength)]
|
||||||
|
];
|
||||||
|
this.createModel(points);
|
||||||
|
}
|
||||||
|
if (model.traingle) {
|
||||||
|
this.origin = [model.point.x, model.point.y];
|
||||||
|
this.rotation = Math.PI * 2 - Math.atan2(model.traingle.absy, model.traingle.absx) * model.traingle.drictx * model.traingle.dricty;
|
||||||
|
this.dirty(); // 可以无需调用
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
src/jmapNew/shape/Power/index.js
Normal file
131
src/jmapNew/shape/Power/index.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import Polyline from 'zrender/src/graphic/shape/Polyline';
|
||||||
|
import Group from 'zrender/src/container/Group';
|
||||||
|
import JTriangle from '../../utils/JTriangle';
|
||||||
|
import ESeparator from './ESeparator';
|
||||||
|
import {isShowThePrdType} from '../../utils/handlePath';
|
||||||
|
|
||||||
|
export default class Line2 extends Group {
|
||||||
|
constructor(model, style) {
|
||||||
|
super();
|
||||||
|
this._code = model.code;
|
||||||
|
this._type = model._type;
|
||||||
|
this.zlevel = model.zlevel;
|
||||||
|
this.z = 0;
|
||||||
|
this.model = model;
|
||||||
|
this.style = style;
|
||||||
|
this.isShowShape = true;
|
||||||
|
if (isShowThePrdType(model.prdType, model.showConditions) || model.previewOrMapDraw) {
|
||||||
|
this.create();
|
||||||
|
this.createTerminal();
|
||||||
|
this.setState(model);
|
||||||
|
}
|
||||||
|
if (model.previewOrMapDraw) {
|
||||||
|
this.setShowMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
const model = this.model;
|
||||||
|
const style = this.style;
|
||||||
|
if (model && model.points.length > 1) {
|
||||||
|
const points = [];
|
||||||
|
for (let i = 0; i < model.points.length; i++) {
|
||||||
|
points.push([model.points[i].x, model.points[i].y]);
|
||||||
|
}
|
||||||
|
this.line = new Polyline({
|
||||||
|
zlevel: this.zlevel,
|
||||||
|
progressive: model.progressive,
|
||||||
|
z: this.z,
|
||||||
|
shape: {
|
||||||
|
points: points
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
lineWidth: model.width,
|
||||||
|
stroke: style.Power.strokeColor
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.add(this.line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createTerminal() { // 创建左右端点
|
||||||
|
const model = this.model;
|
||||||
|
const style = this.style;
|
||||||
|
if (model && model.leftTerminal) { // 左端点
|
||||||
|
const traingle = new JTriangle(model.points[0], model.points[1]);
|
||||||
|
this.leftTerminal = new ESeparator({
|
||||||
|
style: style,
|
||||||
|
zlevel: this.zlevel,
|
||||||
|
z: this.z + 3,
|
||||||
|
traingle: traingle,
|
||||||
|
width: model.width,
|
||||||
|
stroke: style.Power.strokeColor,
|
||||||
|
point: {
|
||||||
|
x: model.points[0].x,
|
||||||
|
y: model.points[0].y
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.add(this.leftTerminal);
|
||||||
|
}
|
||||||
|
if (model && model.rightTerminal) { // 右端点
|
||||||
|
const traingle = new JTriangle(model.points[model.points.length - 2], model.points[model.points.length - 1]);
|
||||||
|
this.rightTerminal = new ESeparator({
|
||||||
|
style: style,
|
||||||
|
zlevel: this.zlevel,
|
||||||
|
z: this.z + 3,
|
||||||
|
traingle: traingle,
|
||||||
|
width: model.width,
|
||||||
|
stroke: style.Power.strokeColor,
|
||||||
|
point: {
|
||||||
|
x: model.points[model.points.length - 1].x,
|
||||||
|
y: model.points[model.points.length - 1].y
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.add(this.rightTerminal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLineType(type) {
|
||||||
|
switch (type) {
|
||||||
|
case '01': break;
|
||||||
|
case '02':
|
||||||
|
this.eachChild((child) => {
|
||||||
|
child.setStyle('lineDash', this.style.Line.lineDash || [4]);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(model) {
|
||||||
|
if (!this.isShowShape) return;
|
||||||
|
this.setLineType(model.type);
|
||||||
|
}
|
||||||
|
// 设置显示模式
|
||||||
|
setShowMode() {
|
||||||
|
const showMode = this.model.showMode;
|
||||||
|
const showConditions = this.model.showConditions;
|
||||||
|
if (!showConditions || showConditions === '01' || showMode === showConditions) {
|
||||||
|
this.eachChild((child) => {
|
||||||
|
child.show();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.eachChild((child) => {
|
||||||
|
child.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setShowStation(stationCode) {
|
||||||
|
if (!stationCode || this.model.stationCode === stationCode) {
|
||||||
|
this.eachChild((child) => {
|
||||||
|
child.show();
|
||||||
|
});
|
||||||
|
this.isShowShape = true;
|
||||||
|
this.setState(this.model);
|
||||||
|
} else {
|
||||||
|
this.eachChild((child) => {
|
||||||
|
child.hide();
|
||||||
|
});
|
||||||
|
this.isShowShape = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -70,6 +70,12 @@ export default class ESingleControl extends Group {
|
|||||||
this.control.setStyle('fill', color);
|
this.control.setStyle('fill', color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTextColor(color) {
|
||||||
|
if (color) {
|
||||||
|
this.text.setStyle('textFill', color);
|
||||||
|
}
|
||||||
|
}
|
||||||
getArcBoundingRect() {
|
getArcBoundingRect() {
|
||||||
const rect = this.control.getBoundingRect().clone();
|
const rect = this.control.getBoundingRect().clone();
|
||||||
const scale = this.control.scale[0];
|
const scale = this.control.scale[0];
|
||||||
|
@ -291,12 +291,15 @@ export default class Station extends Group {
|
|||||||
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||||
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||||
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.greenColor);
|
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.greenColor);
|
||||||
|
this.centerControl && this.centerControl.setTextColor(this.style.Station.StationControl.lamp.greenColor); // 文字颜色
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLocal() { // 站控
|
handleLocal() { // 站控
|
||||||
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||||
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.yellowColor);
|
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.yellowColor);
|
||||||
|
this.substationControl && this.substationControl.setTextColor(this.style.Station.StationControl.lamp.yellowColor); // 文字颜色
|
||||||
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||||
|
this.arrowsControl && this.arrowsControl.setColor(this.style.Station.StationControl.lamp.greenColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEmergency() { // 紧急站控
|
handleEmergency() { // 紧急站控
|
||||||
@ -315,7 +318,8 @@ export default class Station extends Group {
|
|||||||
setState(model) {
|
setState(model) {
|
||||||
if (!this.isShowShape) return;
|
if (!this.isShowShape) return;
|
||||||
this.recover();
|
this.recover();
|
||||||
model.controlMode && this['handle' + model.controlMode]();
|
// model.controlMode && this['handle' + model.controlMode]();
|
||||||
|
this.handleLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
getShapeTipPoint(opts) {
|
getShapeTipPoint(opts) {
|
||||||
|
@ -24,6 +24,7 @@ import AutomaticRoute from './AutomacticRoute/index.js';
|
|||||||
import SaidLamp from './SaidLamp/index.js';
|
import SaidLamp from './SaidLamp/index.js';
|
||||||
import SplitStation from './SplitStation/index';
|
import SplitStation from './SplitStation/index';
|
||||||
import Arrow from './Arrow/index';
|
import Arrow from './Arrow/index';
|
||||||
|
import Power from './Power/index';
|
||||||
|
|
||||||
/** 图库*/
|
/** 图库*/
|
||||||
const mapShape = {};
|
const mapShape = {};
|
||||||
@ -69,6 +70,7 @@ mapShape[deviceType.Axle] = SaidLamp;
|
|||||||
mapShape[deviceType.SwitchFault] = SaidLamp;
|
mapShape[deviceType.SwitchFault] = SaidLamp;
|
||||||
mapShape[deviceType.SplitStation] = SplitStation;
|
mapShape[deviceType.SplitStation] = SplitStation;
|
||||||
mapShape[deviceType.Arrow] = Arrow;
|
mapShape[deviceType.Arrow] = Arrow;
|
||||||
|
mapShape[deviceType.Power] = Power;
|
||||||
|
|
||||||
function shapefactory(device, jmap) {
|
function shapefactory(device, jmap) {
|
||||||
const type = device._type;
|
const type = device._type;
|
||||||
|
@ -147,6 +147,9 @@ export function parser(data, skinCode, showConfig) {
|
|||||||
zrUtil.each(data.arrowList || [], elem => {
|
zrUtil.each(data.arrowList || [], elem => {
|
||||||
mapDevice[elem.code] = createDevice(deviceType.Arrow, elem, propConvert, showConfig);
|
mapDevice[elem.code] = createDevice(deviceType.Arrow, elem, propConvert, showConfig);
|
||||||
}, this);
|
}, this);
|
||||||
|
zrUtil.each(data.powerList || [], elem => {
|
||||||
|
mapDevice[elem.code] = createDevice(deviceType.Power, elem, propConvert, showConfig);
|
||||||
|
}, this);
|
||||||
zrUtil.each(data.indicatorLightList || [], elem => {
|
zrUtil.each(data.indicatorLightList || [], elem => {
|
||||||
switch (elem.type) {
|
switch (elem.type) {
|
||||||
case 'AtsControl':
|
case 'AtsControl':
|
||||||
@ -326,6 +329,7 @@ export function updateMapData(state, model) {
|
|||||||
case deviceType.SplitStation: updateForList(model, state, 'splitStationList'); break;
|
case deviceType.SplitStation: updateForList(model, state, 'splitStationList'); break;
|
||||||
case deviceType.SwitchFault: updateForList(model, state, 'indicatorLightList'); break;
|
case deviceType.SwitchFault: updateForList(model, state, 'indicatorLightList'); break;
|
||||||
case deviceType.Arrow: updateForList(model, state, 'arrowList'); break;
|
case deviceType.Arrow: updateForList(model, state, 'arrowList'); break;
|
||||||
|
case deviceType.Power: updateForList(model, state, 'powerList'); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,6 +342,13 @@ const map = {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
powerList: (state) => {
|
||||||
|
if (state.map) {
|
||||||
|
return state.map.powerList || [];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
tempSpeedLimitList: (state) => {
|
tempSpeedLimitList: (state) => {
|
||||||
if (state.map) {
|
if (state.map) {
|
||||||
return state.map.tempSpeedLimitList;
|
return state.map.tempSpeedLimitList;
|
||||||
|
@ -30,7 +30,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
jl3d: null,
|
jl3d: null,
|
||||||
rendermode:'监控视角',
|
rendermode:'监控视角',
|
||||||
renderswitch:true
|
renderswitch:false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -133,6 +133,14 @@
|
|||||||
@setCenter="setCenter"
|
@setCenter="setCenter"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="供电线" class="tab_pane_box" name="Power" :lazy="lazy">
|
||||||
|
<power-draft
|
||||||
|
ref="Power"
|
||||||
|
:selected="selected"
|
||||||
|
@updateMapModel="updateMapModel"
|
||||||
|
@setCenter="setCenter"
|
||||||
|
/>
|
||||||
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('map.text')" class="tab_pane_box" name="Text" :lazy="lazy">
|
<el-tab-pane :label="$t('map.text')" class="tab_pane_box" name="Text" :lazy="lazy">
|
||||||
<text-draft
|
<text-draft
|
||||||
ref="Text"
|
ref="Text"
|
||||||
@ -211,6 +219,7 @@ import PsdDraft from './psdDraft';
|
|||||||
import EspDraft from './espDraft';
|
import EspDraft from './espDraft';
|
||||||
import TrainDraft from './train/index';
|
import TrainDraft from './train/index';
|
||||||
import LineDraft from './line';
|
import LineDraft from './line';
|
||||||
|
import PowerDraft from './power';
|
||||||
import TextDraft from './text';
|
import TextDraft from './text';
|
||||||
import ControlDraft from './ControlDraft';
|
import ControlDraft from './ControlDraft';
|
||||||
import TrainWindowDraft from './trainwindow';
|
import TrainWindowDraft from './trainwindow';
|
||||||
@ -242,6 +251,7 @@ export default {
|
|||||||
TrainWindowDraft,
|
TrainWindowDraft,
|
||||||
TrainDraft,
|
TrainDraft,
|
||||||
LineDraft,
|
LineDraft,
|
||||||
|
PowerDraft,
|
||||||
TextDraft,
|
TextDraft,
|
||||||
ZcControlDraft,
|
ZcControlDraft,
|
||||||
OutFrameDraft,
|
OutFrameDraft,
|
||||||
|
@ -225,7 +225,7 @@ export default {
|
|||||||
this.editModel.points.splice(index + 1, 0, data);
|
this.editModel.points.splice(index + 1, 0, data);
|
||||||
},
|
},
|
||||||
delPoint(index) {
|
delPoint(index) {
|
||||||
this.editModel.points.splice(index + 1, 0);
|
this.editModel.points.splice(index, 1);
|
||||||
},
|
},
|
||||||
addPointAddModel(index) {
|
addPointAddModel(index) {
|
||||||
const data = { x: 0, y: 0};
|
const data = { x: 0, y: 0};
|
||||||
|
315
src/views/newMap/newMapdraft/mapoperate/power.vue
Normal file
315
src/views/newMap/newMapdraft/mapoperate/power.vue
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
<template>
|
||||||
|
<el-tabs v-model="activeName" class="card">
|
||||||
|
<el-tab-pane class="view-control" :label="$t('map.property')" name="first" :lazy="lazy">
|
||||||
|
<div style="height: calc(100% - 46px);">
|
||||||
|
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||||
|
<config-list ref="form" :form="form" :form-model="editModel" :rules="rules" />
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<el-button-group class="map-draft-group">
|
||||||
|
<el-button type="primary" size="small" @click="edit">{{ $t('map.updateObj') }}</el-button>
|
||||||
|
<el-button type="danger" size="small" @click="deleteObj">{{ $t('map.deleteObj') }}</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane class="view-control" :label="$t('map.newConstruction')" name="second" :lazy="lazy">
|
||||||
|
<div style="height: calc(100% - 46px);">
|
||||||
|
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||||
|
<el-form ref="make" label-width="120px" :model="addModel" size="mini" :rules="makeRules">
|
||||||
|
<el-form-item :label="$t('map.lineWidth')" prop="width">
|
||||||
|
<el-input-number v-model="addModel.width" :min="1" />px
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('map.showConditions')" prop="showConditions">
|
||||||
|
<el-radio-group v-model="addModel.showConditions">
|
||||||
|
<el-radio label="01">{{ $t('map.localCenter') }}</el-radio>
|
||||||
|
<el-radio label="02">{{ $t('map.center') }}</el-radio>
|
||||||
|
<el-radio label="03">{{ $t('map.local') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="coordinate">
|
||||||
|
<span class="title">{{ $t('map.linePoint') }}</span>
|
||||||
|
<div class="point-section">
|
||||||
|
<template v-for="(point, index) in addModel.points">
|
||||||
|
<div :key="index" style="overflow: hidden;">
|
||||||
|
<el-form-item
|
||||||
|
label=""
|
||||||
|
:prop="'points[' + index + '].x'"
|
||||||
|
style="display: table; float: left;"
|
||||||
|
label-width="0px"
|
||||||
|
>
|
||||||
|
<el-input-number v-model="point.x" />
|
||||||
|
</el-form-item>
|
||||||
|
<span style="display: table; margin-left: 8px; float: left; line-height: 28px;">
|
||||||
|
, </span>
|
||||||
|
<el-form-item
|
||||||
|
label=""
|
||||||
|
:prop="'points[' + index + '].y'"
|
||||||
|
style="display: table; float: left; margin-right: 5px;"
|
||||||
|
label-width="10px"
|
||||||
|
>
|
||||||
|
<el-input-number v-model="point.y" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-plus"
|
||||||
|
circle
|
||||||
|
class="point-button"
|
||||||
|
@click="addPointAddModel(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-minus"
|
||||||
|
:disabled="index == 0 || index == addModel.points.length - 1"
|
||||||
|
circle
|
||||||
|
class="point-button"
|
||||||
|
@click="delPointAddModel(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<el-button-group class="map-draft-group">
|
||||||
|
<el-button type="primary" size="small" @click="create">{{ $t('map.create') }}</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
import { getUID } from '@/jmapNew/utils/Uid';
|
||||||
|
import ConfigList from './config/list';
|
||||||
|
import { deepAssign } from '@/utils/index';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'StationStandDraft',
|
||||||
|
components: {
|
||||||
|
ConfigList
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
selected: {
|
||||||
|
type: Object,
|
||||||
|
default: function () {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: 'first',
|
||||||
|
lazy: true,
|
||||||
|
showConditionsList: [
|
||||||
|
{ label: this.$t('map.localCenter'), value: '01'},
|
||||||
|
{ label: this.$t('map.center'), value: '02' },
|
||||||
|
{ label: this.$t('map.local'), value: '03'}
|
||||||
|
],
|
||||||
|
terminalList: [
|
||||||
|
{ label: '显示', value: true},
|
||||||
|
{ label: '隐藏', value: false }
|
||||||
|
],
|
||||||
|
editModel: {
|
||||||
|
code: '',
|
||||||
|
width: 1,
|
||||||
|
leftTerminal: true,
|
||||||
|
rightTerminal: true,
|
||||||
|
showConditions: '01', // 显示条件
|
||||||
|
points: []
|
||||||
|
},
|
||||||
|
addModel: {
|
||||||
|
width: 1,
|
||||||
|
showConditions: '01',
|
||||||
|
points: [
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x: 100, y: 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
code: [
|
||||||
|
{ required: true, message: this.$t('rules.pleaseSelectLine'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
width: [
|
||||||
|
{ required: true, message: this.$t('rules.pleaseSelectLineWidth'), trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
makeRules: {
|
||||||
|
code: [
|
||||||
|
{ required: true, message: this.$t('rules.pleaseSelectLine'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
width: [
|
||||||
|
{ required: true, message: this.$t('rules.pleaseSelectLineWidth'), trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('map', [
|
||||||
|
'powerList'
|
||||||
|
]),
|
||||||
|
form() {
|
||||||
|
const form = {
|
||||||
|
labelWidth: '120px',
|
||||||
|
items: {
|
||||||
|
code: {
|
||||||
|
name: '',
|
||||||
|
item: []
|
||||||
|
},
|
||||||
|
draw: {
|
||||||
|
name: this.$t('map.drawData'),
|
||||||
|
item: [
|
||||||
|
{ prop: 'code', label: '供电线路', type: 'select', optionLabel: 'code', optionValue: 'code', options: this.powerList, change: true, deviceChange: this.deviceChange },
|
||||||
|
{ prop: 'width', label: '供电线路宽度', type: 'number', min: 1, placeholder: 'px' },
|
||||||
|
{ prop: 'showConditions', label: this.$t('map.showConditions'), type: 'radio', optionLabel: 'label', optionValue:'value', radioList: this.showConditionsList},
|
||||||
|
{ prop: 'leftTerminal', label: '左侧端点:', type: 'select', optionLabel: 'label', optionValue:'value', options: this.terminalList},
|
||||||
|
{ prop: 'rightTerminal', label: '右侧端点:', type: 'select', optionLabel: 'label', optionValue:'value', options: this.terminalList},
|
||||||
|
{ prop: 'points', label: this.$t('map.segmentCoordinates'), type: 'points', width: '100px', isHidden: !this.isPointsShow, addPoint: this.addPoint, delPoint: this.delPoint }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
name: this.$t('map.mapData'),
|
||||||
|
item: [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return form;
|
||||||
|
},
|
||||||
|
isPointsShow() {
|
||||||
|
return this.editModel.points.length > 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
deviceChange(code) {
|
||||||
|
this.$emit('setCenter', code);
|
||||||
|
this.deviceSelect(this.$store.getters['map/getDeviceByCode'](code));
|
||||||
|
},
|
||||||
|
deviceSelect(selected) {
|
||||||
|
if (selected && selected._type.toUpperCase() === 'Power'.toUpperCase()) {
|
||||||
|
this.$refs.form && this.$refs.form.resetFields();
|
||||||
|
this.$refs.make && this.$refs.make.resetFields();
|
||||||
|
this.activeName = 'first';
|
||||||
|
this.editModel = deepAssign(this.editModel, selected);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addPoint(index) {
|
||||||
|
const data = { x: 0, y: 0 };
|
||||||
|
this.editModel.points.splice(index + 1, 0, data);
|
||||||
|
},
|
||||||
|
delPoint(index) {
|
||||||
|
this.editModel.points.splice(index, 1);
|
||||||
|
},
|
||||||
|
addPointAddModel(index) {
|
||||||
|
const data = { x: 0, y: 0};
|
||||||
|
this.addModel.points.splice(index + 1, 0, data);
|
||||||
|
},
|
||||||
|
delPointAddModel(index) {
|
||||||
|
this.addModel.points.splice(index, 1);
|
||||||
|
},
|
||||||
|
create() {
|
||||||
|
this.$refs['make'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (JSON.stringify(this.addModel.points[0]) !== JSON.stringify(this.addModel.points[this.addModel.points.length - 1])) {
|
||||||
|
const pointArr = JSON.stringify(this.addModel.points);
|
||||||
|
const model = {
|
||||||
|
_type: 'Power',
|
||||||
|
code: getUID('Power', this.powerList),
|
||||||
|
width: this.addModel.width,
|
||||||
|
leftTerminal: true,
|
||||||
|
rightTerminal: true,
|
||||||
|
showConditions: this.addModel.showConditions,
|
||||||
|
points: JSON.parse(pointArr)
|
||||||
|
};
|
||||||
|
this.$emit('updateMapModel', model);
|
||||||
|
this.$refs.make && this.$refs.make.resetFields();
|
||||||
|
} else {
|
||||||
|
this.$message.console.error(this.$t('tip.cannotCoincide'));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 修改对象
|
||||||
|
edit() {
|
||||||
|
this.$refs['form'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const data = Object.assign({_type: 'Line'}, this.editModel);
|
||||||
|
this.$emit('updateMapModel', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 删除对象
|
||||||
|
deleteObj() {
|
||||||
|
const selected = this.$store.getters['map/getDeviceByCode'](this.editModel.code);
|
||||||
|
if (selected && selected._type.toUpperCase() === 'Line'.toUpperCase()) {
|
||||||
|
this.$confirm(this.$t('tip.confirmDeletion'), this.$t('tip.hint'), {
|
||||||
|
confirmButtonText: this.$t('tip.confirm'),
|
||||||
|
cancelButtonText: this.$t('tip.cancel'),
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.$emit('updateMapModel', {...selected, _dispose: true});
|
||||||
|
this.$refs.form && this.$refs.form.resetFields();
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.info(this.$t('tip.cancelledDelete'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
@import "src/styles/mixin.scss";
|
||||||
|
.view-control{
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coordinate {
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
text-align: right;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 12px 0 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 28px;
|
||||||
|
width: 120px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-section {
|
||||||
|
/*float: left;*/
|
||||||
|
position: absolute;
|
||||||
|
left: 120px;
|
||||||
|
width: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-button {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
/deep/ {
|
||||||
|
.el-icon-plus,
|
||||||
|
.el-icon-minus {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input-number--mini {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
</style>
|
2339
static/model/path/path.obj
Normal file
2339
static/model/path/path.obj
Normal file
File diff suppressed because it is too large
Load Diff
25
static/workertest/passsimulation/passer.js
Normal file
25
static/workertest/passsimulation/passer.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var i=0;
|
||||||
|
var update = null;
|
||||||
|
function timedCount(){
|
||||||
|
|
||||||
|
onmessage = (e) => {
|
||||||
|
|
||||||
|
|
||||||
|
if(e.data == "on"){
|
||||||
|
|
||||||
|
update = setInterval("passerupdate()", 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(e.data == "off"){
|
||||||
|
clearInterval(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
function passerupdate(){
|
||||||
|
|
||||||
|
postMessage("up");
|
||||||
|
}
|
||||||
|
|
||||||
|
timedCount();
|
25
static/workertest/passsimulation/station.js
Normal file
25
static/workertest/passsimulation/station.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var i=0;
|
||||||
|
var update = null;
|
||||||
|
function timedCount(){
|
||||||
|
|
||||||
|
onmessage = (e) => {
|
||||||
|
|
||||||
|
|
||||||
|
if(e.data == "on"){
|
||||||
|
console.log("on");
|
||||||
|
update = setInterval("stationupdate()", 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(e.data == "off"){
|
||||||
|
clearInterval(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
function stationupdate(){
|
||||||
|
|
||||||
|
postMessage("up");
|
||||||
|
}
|
||||||
|
|
||||||
|
timedCount();
|
Loading…
Reference in New Issue
Block a user