原文链接及内容

运行界面

topolis库是一个实现二维平面拓扑表示和操作的JavaScript库。

该示例演示了如何在OpenLayers中使用topolis库的示例。从而能够创建和编辑拓扑几何体。如上图,首先绘制边,(将鼠标放置于绘制的图形可以)捕捉到现有边,然后通过绘制与要删除的边交叉的新边来删除边。

main.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import Feature from 'ol/Feature.js';
import Map from 'ol/Map.js';
import MousePosition from 'ol/control/MousePosition.js';
import View from 'ol/View.js';
import {
Circle as CircleStyle,
Fill,
Stroke,
Style,
Text,
} from 'ol/style.js';
import {Draw, Snap} from 'ol/interaction.js';
import {LineString, Point, Polygon} from 'ol/geom.js';
import {OSM, Vector as VectorSource} from 'ol/source.js';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer.js';

const raster = new TileLayer({
source: new OSM(),
});

const nodes = new VectorSource({wrapX: false});
const nodesLayer = new VectorLayer({
source: nodes,
style: function (f) {
const style = new Style({
image: new CircleStyle({
radius: 8,
fill: new Fill({color: 'rgba(255, 0, 0, 0.2)'}),
stroke: new Stroke({color: 'red', width: 1}),
}),
text: new Text({
text: f.get('node').id.toString(),
fill: new Fill({color: 'red'}),
stroke: new Stroke({
color: 'white',
width: 3,
}),
}),
});
return [style];
},
});

const edges = new VectorSource({wrapX: false});
const edgesLayer = new VectorLayer({
source: edges,
style: function (f) {
const style = new Style({
stroke: new Stroke({
color: 'blue',
width: 1,
}),
text: new Text({
text: f.get('edge').id.toString(),
fill: new Fill({color: 'blue'}),
stroke: new Stroke({
color: 'white',
width: 2,
}),
}),
});
return [style];
},
});

const faces = new VectorSource({wrapX: false});
const facesLayer = new VectorLayer({
source: faces,
style: function (f) {
const style = new Style({
stroke: new Stroke({
color: 'black',
width: 1,
}),
fill: new Fill({
color: 'rgba(0, 255, 0, 0.2)',
}),
text: new Text({
font: 'bold 12px sans-serif',
text: f.get('face').id.toString(),
fill: new Fill({color: 'green'}),
stroke: new Stroke({
color: 'white',
width: 2,
}),
}),
});
return [style];
},
});

const map = new Map({
layers: [raster, facesLayer, edgesLayer, nodesLayer],
target: 'map',
view: new View({
center: [-11000000, 4600000],
zoom: 16,
}),
});

const topo = topolis.createTopology();

topo.on('addnode', nodeToFeature);
topo.on('removenode', function (e) {
removeElementFeature(nodes, e);
});
topo.on('addedge', edgeToFeature);
topo.on('modedge', function (e) {
const feature = edges.getFeatureById(e.id);
feature.setGeometry(new LineString(e.coordinates));
});
topo.on('removeedge', function (e) {
removeElementFeature(edges, e);
});
topo.on('addface', faceToFeature);
topo.on('removeface', function (e) {
removeElementFeature(faces, e);
});

function removeElementFeature(source, element) {
const feature = source.getFeatureById(element.id);
source.removeFeature(feature);
}

function nodeToFeature(node) {
const feature = new Feature({
geometry: new Point(node.coordinate),
node: node,
});
feature.setId(node.id);
nodes.addFeature(feature);
}

function edgeToFeature(edge) {
const feature = new Feature({
geometry: new LineString(edge.coordinates),
edge: edge,
});
feature.setId(edge.id);
edges.addFeature(feature);
}

function faceToFeature(face) {
const coordinates = topo.getFaceGeometry(face);
const feature = new Feature({
geometry: new Polygon(coordinates),
face: face,
});
feature.setId(face.id);
faces.addFeature(feature);
}

function createNode(topo, coord) {
let node;
const existingEdge = topo.getEdgeByPoint(coord, 5)[0];
if (existingEdge) {
node = topo.modEdgeSplit(existingEdge, coord);
} else {
node = topo.addIsoNode(coord);
}
return node;
}

function onDrawend(e) {
const edgeGeom = e.feature.getGeometry().getCoordinates();
const startCoord = edgeGeom[0];
const endCoord = edgeGeom[edgeGeom.length - 1];
let start, end;
try {
start = topo.getNodeByPoint(startCoord);
end = topo.getNodeByPoint(endCoord);
const edgesAtStart = topo.getEdgeByPoint(startCoord, 5);
const edgesAtEnd = topo.getEdgeByPoint(endCoord, 5);
const crossing = topo.getEdgesByLine(edgeGeom);
if (
crossing.length === 1 &&
!start &&
!end &&
edgesAtStart.length === 0 &&
edgesAtEnd.length === 0
) {
topo.remEdgeNewFace(crossing[0]);
start = crossing[0].start;
if (start.face) {
topo.removeIsoNode(start);
}
end = crossing[0].end;
if (end.face) {
topo.removeIsoNode(end);
}
return;
}
if (!start) {
start = createNode(topo, startCoord);
edgeGeom[0] = start.coordinate;
}
if (!end) {
end = createNode(topo, endCoord);
edgeGeom[edgeGeom.length - 1] = end.coordinate;
}
topo.addEdgeNewFaces(start, end, edgeGeom);
} catch (e) {
toastr.warning(e.toString());
}
}

const draw = new Draw({
type: 'LineString',
});
draw.on('drawend', onDrawend);
map.addInteraction(draw);
const snap = new Snap({
source: edges,
});
map.addInteraction(snap);
map.addControl(new MousePosition());

界面布局文件index.html代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>topolis integration</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css">
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://cdn.jsdelivr.net/npm/elm-pep@1.0.6/dist/elm-pep.js"></script>
<script src="https://cdn.jsdelivr.net/npm/topolis@0.2.5/dist/topolis.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>