[1 bit]完成 line 类型的轮廓和遮罩层的绘制

This commit is contained in:
锦恢 2024-04-18 01:12:21 +08:00
parent 0a36a28a57
commit 5481921722
26 changed files with 1563 additions and 263 deletions

93
backup/drawline.js Normal file
View File

@ -0,0 +1,93 @@
const bar = [
(f, t, a, b, c0, c1) => [].concat( // 0
(f === 1) ? [a, 2, c1] : [],
[a, 5, c0],
[b, 5, c0],
(t > 1) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 1
(f === 0) ? [a, 5, c0] :
(f > 1) ? [a, 0, c0] : [],
[a, 2, c1],
[b, 2, c1],
(t > 1) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [a, 0, c0, b, 0, c1] // 2 = Z
];
const brick = [
(f, t, a, b, c0, c1) => [].concat( // 0
(f === 0) ? [a, 5, c0] :
(f === 1) ? [a, 1, c1] : [],
[a, 6, c0],
(t === 0) ? [b, 5, c0] :
[b, 4, c0],
(t === 3) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 1
(f === 0) ? [a, 4, c0, a, 3, c1] :
(f === 1) ? [a, 2, c1] :
(f === 2) ? [a, 3, c1] :
[a, 0, c0, a, 3, c1],
(t === 1) ? [b, 3, c1] :
[b, 1, c1],
(t === 3) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 2
(f === 0) ? [a, 4, 0] :
(f === 1) ? [a, 1, 0] :
[a, 0, 0],
(t === 0) ? [b, 6, 0, b, 6, c0] :
(t === 1) ? [b, 3, 0, b, 3, c1, b, 4, c0] :
[b, 0, 0, b, 0, c0, b, 4, c0],
(f === 0) ? [a, 4, c0, a, 3, c1] :
(f === 1) ? [a, 6, c0, a, 1, c1] :
[a, 6, c0, a, 0, c0, a, 3, c1],
(t === 0) ? [b, 1, c1, b, 6, c0] :
(t === 1) ? [b, 3, c1] :
[b, 1, c1, b, 0, c0]
)
];
// switch (val) {
// case 0:
// if (i === 0) {
// if (y1 === y2) {
// vertices.push(
// t1, y1ShiftIndex, renderParam1.color, 0,
// t1, y1ShiftIndex, renderParam1.color, 4
// );
// }
// }
// break;
// case 1: // 0 1
// vertices.push(...bar[val](f[1], t[1], t1, t2, 2, 3));
// break;
// case 2: case 3: // x X
// vertices.push(...bar[2](f[1], t[1], t1, t2, 4, 4));
// break;
// case 4: case 5: // z Z
// vertices.push(...bar[2](f[1], t[1], t1, t2, 1, 1));
// break;
// case 6: case 7: // u U uninitialized
// vertices.push(...bar[2](f[1], t[1], t1, t2, 6, 6));
// break;
// case 8: case 9: // w W weak unknown
// vertices.push(...bar[2](f[1], t[1], t1, t2, 10, 10));
// break;
// case 10: case 11: // l L
// vertices.push(...bar[0](f[1], t[1], t1, t2, 8, 9));
// break;
// case 12: case 13: // h H
// vertices.push(...bar[1](f[1], t[1], t1, t2, 8, 9));
// break;
// default:
// vertices.push(...bar[2](f[1], t[1], t1, t2, 7, 7));
// }

View File

@ -7,6 +7,9 @@
--sidebar-width: 280px; --sidebar-width: 280px;
--right-nav-width: 60px; --right-nav-width: 60px;
--time-scale-height: 50px; --time-scale-height: 50px;
--sidebar-padding: 10px;
--vcd-render-padding: 24px;
/* 需要满足如下公式 --time-scale-height + --sidebar-padding = --vcd-render-padding + canvas预留 高度 */
--render-scale-x: 1; --render-scale-x: 1;
} }

View File

@ -58,6 +58,10 @@ export default {
document.body.style.setProperty('--el-bg-color-overlay', 'transplant'); document.body.style.setProperty('--el-bg-color-overlay', 'transplant');
// document.body.style.setProperty('--el-color-white', 'var(--background)'); // document.body.style.setProperty('--el-color-white', 'var(--background)');
//
document.body.style.setProperty('--time-scale-height', '50px');
document.body.style.setProperty('--sidebar-padding', '10px');
document.body.style.setProperty('--vcd-render-padding', '24px');
// signal height // signal height
document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px'); document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px');

View File

@ -59,7 +59,7 @@ export default {
* @param { PointerEvent } event * @param { PointerEvent } event
*/ */
function makeCursor(event) { function makeCursor(event) {
console.log(event.x); // console.log(event.x);
showFixedOne.value = true; showFixedOne.value = true;
fixedLeft.value = event.x - boxShift; fixedLeft.value = event.x - boxShift;
globalLookup.view.currentX = event.x - boxShift; globalLookup.view.currentX = event.x - boxShift;

View File

@ -60,20 +60,20 @@ export default {
.vcd-view { .vcd-view {
position: absolute; position: absolute;
top: 24px; top: var(--vcd-render-padding);
bottom: 24px; bottom: var(--vcd-render-padding);
} }
.vcd-values { .vcd-values {
position: absolute; position: absolute;
top: 24px; top: var(--vcd-render-padding);
bottom: 24px; bottom: var(--vcd-render-padding);
} }
.wd-waveql { .wd-waveql {
position: absolute; position: absolute;
top: 24px; top: var(--vcd-render-padding);
bottom: 24px; bottom: var(--vcd-render-padding);
width: 100%; width: 100%;
transition: width .3s ease-out; transition: width .3s ease-out;
} }

View File

@ -18,7 +18,7 @@
<div class="vcd-control-panel-wrapper" <div class="vcd-control-panel-wrapper"
v-for="(section, index) of controlPanel.sections" :key="index" v-for="(section, index) of controlPanel.sections" :key="index"
@click="controlPanel.click(index)" @click="controlPanel.click(index)"
> >
<div :class="controlPanel.currentIndex === index ? 'vcd-control-panel-active': ''"><span <div :class="controlPanel.currentIndex === index ? 'vcd-control-panel-active': ''"><span
class="vcd-control-panel-icon" class="vcd-control-panel-icon"
:class="section.iconClass" :class="section.iconClass"
@ -69,7 +69,7 @@ export default {
this.currentIndex = index; this.currentIndex = index;
} }
console.log(this.currentIndex); // console.log(this.currentIndex);
} }
}); });

View File

@ -132,7 +132,7 @@ export default {
} }
.display-signal-wrapper { .display-signal-wrapper {
padding: 10px; padding: var(--sidebar-padding);
background-color: var(--sidebar); background-color: var(--sidebar);
border: solid 1px var(--sidebar-border); border: solid 1px var(--sidebar-border);
min-width: var(--sidebar-width); min-width: var(--sidebar-width);
@ -173,6 +173,7 @@ export default {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
user-select: none;
} }
.signal-info-name { .signal-info-name {

View File

@ -76,9 +76,9 @@ function toggleRender(signal) {
} else { } else {
globalLookup.currentWires.add(signal); globalLookup.currentWires.add(signal);
const signalItem = globalLookup.chango[signal.link]; const signalItem = globalLookup.chango[signal.link];
const { wave } = signalItem; const { wave, kind } = signalItem;
const time = globalLookup.currentTime; const time = globalLookup.currentTime;
globalLookup.currentSignalValues[signal.link] = findCurrentSignalValue(wave, time); globalLookup.currentSignalValues[signal.link] = findCurrentSignalValue(kind, wave, time);
globalLookup.render(); globalLookup.render();
} }
} }

View File

@ -135,20 +135,29 @@ function makeSearchResultItem(searchString, module, searchScope, caseSensitivity
/** /**
* *
* @param {'bit' | 'vec'} kind
* @param {BigInt} value * @param {BigInt} value
* @param {BigInt} mask * @param {BigInt} mask
* @returns {number | string} * @returns {number | string}
*/ */
function getWireValueCaption(value, mask) { function getWireValueCaption(kind, value, mask) {
if (!mask) { if (kind === 'bit') {
if (value === 2) {
return 'x';
}
return value; return value;
} else if (kind === 'vec') {
if (!mask) {
return value;
}
// mask 不为空,代表存在问题
if (value) {
return '?';
} else {
return 'x';
}
} }
// mask 不为空,代表存在问题
if (value) {
return '?';
} else {
return 'x';
}
} }
async function updateWireCurrentValue() { async function updateWireCurrentValue() {
@ -158,13 +167,14 @@ async function updateWireCurrentValue() {
for (const signal of globalLookup.currentWires) { for (const signal of globalLookup.currentWires) {
const signalItem = chango[signal.link]; const signalItem = chango[signal.link];
const { wave } = signalItem; const { wave, kind } = signalItem;
// console.log(signalItem);
if (wave === undefined || wave.length === 0) { if (wave === undefined || wave.length === 0) {
currentSignalValues[signal.link] = 'x'; currentSignalValues[signal.link] = 'x';
} else if (wave.length === 1) { } else if (wave.length === 1) {
currentSignalValues[signal.link] = getWireValueCaption(wave[0][1], wave[0][2]); currentSignalValues[signal.link] = getWireValueCaption(kind, wave[0][1], wave[0][2]);
} else { } else {
currentSignalValues[signal.link] = findCurrentSignalValue(wave, time); currentSignalValues[signal.link] = findCurrentSignalValue(kind, wave, time);
} }
// console.log(signal.name, currentSignalValues[signal.link]); // console.log(signal.name, currentSignalValues[signal.link]);
@ -172,11 +182,11 @@ async function updateWireCurrentValue() {
} }
/** /**
* * @param {'bit' | 'vec'} kind
* @param {Array<Array<string | number>>} wave * @param {Array<Array<string | number>>} wave
* @param {number} time * @param {number} time
*/ */
function findCurrentSignalValue(wave, time) { function findCurrentSignalValue(kind, wave, time) {
const times = wave.map(p => p[0]); const times = wave.map(p => p[0]);
// 二分查找,并将结果存入 i // 二分查找,并将结果存入 i
@ -185,7 +195,7 @@ function findCurrentSignalValue(wave, time) {
if (times[i] === time) { if (times[i] === time) {
break; break;
} }
if (times[j] === time) { if (times[j] <= time) {
i = j; i = j;
break; break;
} }
@ -200,8 +210,7 @@ function findCurrentSignalValue(wave, time) {
} }
} }
const value = getWireValueCaption(wave[i][1], wave[i][2]); const value = getWireValueCaption(kind, wave[i][1], wave[i][2]);
console.log(wave[i][1], wave[i][2]);
return value; return value;
} }

View File

@ -31,7 +31,7 @@ const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
const getFullView = desc => { const getFullView = desc => {
console.log(desc); // console.log(desc);
if (desc.waveql) { if (desc.waveql) {
return; return;
} }

View File

@ -1,30 +1,38 @@
'use strict'; 'use strict';
const genOnWheel = (element, pstate, deso, keyBindo, plugins) => const genOnWheel = (element, pstate, deso, keyBindo, plugins) =>
event => { event => {
const {deltaY} = event; const { deltaX, deltaY } = event;
if (event.ctrlKey) { if (event.ctrlKey) {
const key = (deltaY < 0) const key = (deltaY < 0)
? 'Ctrl+icon:scrollUp' ? 'Ctrl+icon:scrollUp'
: ((deltaY > 0) ? 'Ctrl+icon:scrollDown' : 'nop'); : ((deltaY > 0) ? 'Ctrl+icon:scrollDown' : 'nop');
if (keyBindo[key].fn(pstate)) { if (keyBindo[key].fn(pstate)) {
if (plugins != undefined) { if (plugins != undefined) {
plugins.map(fn => fn(key, event)); plugins.map(fn => fn(key, event));
}
deso.render();
}
event.preventDefault();
} else if (event.shiftKey) {
const key = (deltaY < 0) ? 'Shift+icon:scrollUp' : ((deltaY > 0) ? 'Shift+icon:scrollDown' : 'nop');
if (keyBindo[key].fn(pstate)) {
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
}
event.preventDefault();
} else if (deltaX !== 0 && deltaY === 0) {
const key = (deltaX < 0) ? 'icon:scrollLeft': 'icon:scrollRight';
if (keyBindo[key].fn(pstate)) {
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
}
event.preventDefault();
} }
deso.render(); };
}
event.preventDefault();
} else
if (event.shiftKey) {
const key = (deltaY < 0) ? 'Shift+icon:scrollUp' : ((deltaY > 0) ? 'Shift+icon:scrollDown' : 'nop');
if (keyBindo[key].fn(pstate)) {
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
}
event.preventDefault();
}
};
module.exports = genOnWheel; module.exports = genOnWheel;

View File

@ -1,29 +1,32 @@
'use strict'; 'use strict';
const cColors = new Float32Array([ // 控制颜色
0, 0, 0, 0, // 0: const gl_Colors = new Float32Array([
0, 0, 1, 1, // 1: (Z) high impedance 0, 0, 0, 0, // 0: 空
0.2, 0.847, 0.1, 1, // 2: strong 0 0, 0, 1, 1, // 1: 高阻态 Z
0.2, 0.847, 0.1, 1, // 3: strong 1 0.2, 0.847, 0.1, 1, // 2: value = 0 用于 width = 1 的信号
0.9, 0.2, 0.2, 1, // 4: (x X) strong unknown 0.2, 0.847, 0.1, 1, // 3: value = 1 用于 width = 1 的信号
0.9, 0.2, 0.2, 1, // 4: 未知态 X
.5, 1, 1, 1, // 5: vec 用于 width > 1 的信号
.5, 1, 1, 1, // 5: vec 1, 1, 0, 1, // 6: yellow
1, 1, 0, 1, // 6: yellow 1, 0, 1, 1, // 7: strange purple
1, 0, 1, 1, // 7: strange purple
0, 1, 0, .5, // 8: (l L) weak 0 0, 1, 0, .5, // 8: (l L) weak 0
0, 1, 1, .5, // 9: (h H) weak 1 0, 1, 1, .5, // 9: (h H) weak 1
1, 0, 0, .5, // 10: (w W) weak unknown 1, 0, 0, .5, // 10: (w W) weak unknown
0, 0, 0, 0, // 11: 0, 0, 1, 0.1, // 11: 高阻态 Z 遮罩
0, 0, 0, 0, // 12: 0.2, 0.847, 0.1, 0.1, // 12: value = 0 遮罩
0, 0, 0, 0, // 13: 0.2, 0.847, 0.1, 0.1, // 13: value = 1 遮罩
0, 0, 0, 0, // 14: 0.9, 0.2, 0.2, 0.1, // 14: 未知态 X 遮罩
0, 0, 0, 0 // 15: .5, 1, 1, 0.1 // 15: vec 遮罩
]); ]);
const cTilts = new Float32Array([ // 14
// 控制方向
const gl_Shifts = new Float32Array([ // 14
0, 0, // 0 0, 0, // 0
1, -1, // 1 1, -1, // 1
1, 0, // 2 1, 0, // 2
@ -33,92 +36,79 @@ const cTilts = new Float32Array([ // 14
-1, 1 // 6 -1, 1 // 6
]); ]);
const shaderer = (kind, src) => webgl2 => { const gl_Shifts_map = new Map();
const vShader = webgl2.createShader(webgl2[kind]); gl_Shifts_map.set(-1, 4);
webgl2.shaderSource(vShader, src); gl_Shifts_map.set(0, 0);
webgl2.compileShader(vShader); gl_Shifts_map.set(1, 1);
return vShader;
};
const vertexShaderScalar = shaderer('VERTEX_SHADER', `#version 300 es const lineWidth = 0.004; // 不能写为 0.0045 这样会因为插值造成不同线段的宽度不一致的问题
in uvec3 pos; const widthShift = lineWidth / 2;
const gl_WidthShifts = new Float32Array([
0, widthShift, // 0
- widthShift, widthShift, // 1
- widthShift, 0, // 2
- widthShift, - widthShift, // 3
0, - widthShift, // 4
widthShift, - widthShift, // 5
widthShift, 0, // 6
widthShift, widthShift // 7
]);
class ShaderMaker {
/**
*
* @param {'VERTEX_SHADER' | 'FRAGMENT_SHADER'} type
* @param {string} source
*/
constructor(type, source) {
this.type = type;
this.source = source;
}
/**
* @param {WebGL2RenderingContext} gl
* @return {WebGLShader}
*/
make(gl) {
const shader = gl.createShader(gl[this.type]);
gl.shaderSource(shader, this.source);
gl.compileShader(shader);
const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!ok) {
console.log('创建类型为 ' + type + ' 的着色器失败!');
}
return shader;
}
}
const vertexShaderScalar = new ShaderMaker('VERTEX_SHADER', `#version 300 es
in uvec4 pos;
out vec4 v_color; out vec4 v_color;
uniform vec2 scale; uniform vec2 scale;
uniform vec2 offset; uniform vec2 offset;
uniform vec4 colors[16]; uniform vec4 colors[16];
uniform vec2 tilts[7]; uniform vec2 shifts[7]; // 基础八位图偏移量为了性能pos 只传入整数,需要的坐标负数由该值提供
uniform float tilt; uniform vec2 widthShifts[8]; // 用于构造线宽的偏移
void main() { void main() {
v_color = colors[pos.z]; v_color = colors[pos.z];
vec2 node = tilts[pos.y]; vec2 shift = shifts[pos.y];
vec2 widthShift = widthShifts[pos.w];
gl_Position = vec4( gl_Position = vec4(
float(pos.x) * scale.x + offset.x + node[1] * tilt, float(pos.x) * scale.x + offset.x + float(widthShift.x),
float(node[0]) * scale.y + offset.y, float(shift.x) * scale.y + offset.y + float(widthShift.y),
1, 1 1, 1
); );
} }`);
`);
const fragmentShader = shaderer('FRAGMENT_SHADER', `#version 300 es const fragmentShader = new ShaderMaker('FRAGMENT_SHADER', `#version 300 es
precision mediump float; precision mediump float;
in vec4 v_color; in vec4 v_color;
out vec4 myOutputColor; out vec4 outColor;
void main() { void main() {
myOutputColor = v_color; outColor = v_color;
} }`);
`);
const bar = [
(f, t, a, b, c0, c1) => [].concat( // 0
(f === 1) ? [a, 2, c1] : [],
[a, 5, c0],
[b, 5, c0],
(t > 1) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 1
(f === 0) ? [a, 5, c0] :
(f > 1) ? [a, 0, c0] : [],
[a, 2, c1],
[b, 2, c1],
(t > 1) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [a, 0, c0, b, 0, c1] // 2 = Z
];
const brick = [
(f, t, a, b, c0, c1) => [].concat( // 0
(f === 0) ? [a, 5, c0] :
(f === 1) ? [a, 1, c1] : [],
[a, 6, c0],
(t === 0) ? [b, 5, c0] :
[b, 4, c0],
(t === 3) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 1
(f === 0) ? [a, 4, c0, a, 3, c1] :
(f === 1) ? [a, 2, c1] :
(f === 2) ? [a, 3, c1] :
[a, 0, c0, a, 3, c1],
(t === 1) ? [b, 3, c1] :
[b, 1, c1],
(t === 3) ? [b, 0, c0] : []
),
(f, t, a, b, c0, c1) => [].concat( // 2
(f === 0) ? [a, 4, 0] :
(f === 1) ? [a, 1, 0] :
[a, 0, 0],
(t === 0) ? [b, 6, 0, b, 6, c0] :
(t === 1) ? [b, 3, 0, b, 3, c1, b, 4, c0] :
[b, 0, 0, b, 0, c0, b, 4, c0],
(f === 0) ? [a, 4, c0, a, 3, c1] :
(f === 1) ? [a, 6, c0, a, 1, c1] :
[a, 6, c0, a, 0, c0, a, 3, c1],
(t === 0) ? [b, 1, c1, b, 6, c0] :
(t === 1) ? [b, 3, c1] :
[b, 1, c1, b, 0, c0]
)
];
class WebGL2WaveRender { class WebGL2WaveRender {
@ -133,7 +123,8 @@ class WebGL2WaveRender {
* chango: Record<string, { * chango: Record<string, {
* kind: string, * kind: string,
* wave: Array<number | string>, * wave: Array<number | string>,
* vao: WebGLVertexArrayObject * lineVao: WebGLVertexArrayObject
* maskVao: WebGLVertexArrayObject
* }> * }>
* view: Array<{ ref: string }>, * view: Array<{ ref: string }>,
* currentWires: Set<{ * currentWires: Set<{
@ -167,47 +158,49 @@ class WebGL2WaveRender {
this.pstate = pstate; this.pstate = pstate;
this.plugins = plugins; this.plugins = plugins;
const webgl2 = canvas.getContext('webgl2', { const gl = canvas.getContext('webgl2', {
premultipliedAlpha: false, premultipliedAlpha: false,
alpha: true, alpha: true,
antialias: false, antialias: false,
depth: false depth: false
}); });
this.webglLocation = this.initProgram(webgl2); this.webglLocation = this.initProgram(gl);
this.verticesMap = this.makeVertex(); const { lineVerticesMap, maskVerticesMap } = this.makeVertex();
this.initData(); this.lineVerticesMap = lineVerticesMap;
this.maskVerticesMap = maskVerticesMap;
this.initData();
this.animationHandler = undefined; this.animationHandler = undefined;
} }
/** /**
* *
* @param {WebGL2RenderingContext} webgl2 * @param {WebGL2RenderingContext} gl
* @returns {{ * @returns {{
* colors: WebGLUniformLocation, * colors: WebGLUniformLocation,
* tilts: WebGLUniformLocation, * shifts: WebGLUniformLocation,
* scale: WebGLUniformLocation, * scale: WebGLUniformLocation,
* offset: WebGLUniformLocation, * offset: WebGLUniformLocation,
* tilt: WebGLUniformLocation,
* pos: number, * pos: number,
* webgl2: WebGL2RenderingContext * widthShifts: WebGLUniformLocation,
* gl: WebGL2RenderingContext
* }} * }}
*/ */
initProgram(webgl2) { initProgram(gl) {
const program = webgl2.createProgram(); const program = gl.createProgram();
webgl2.attachShader(program, vertexShaderScalar(webgl2)); gl.attachShader(program, vertexShaderScalar.make(gl));
webgl2.attachShader(program, fragmentShader(webgl2)); gl.attachShader(program, fragmentShader.make(gl));
webgl2.linkProgram(program); gl.linkProgram(program);
webgl2.useProgram(program); gl.useProgram(program);
const webglLocation = { const webglLocation = {
colors: webgl2.getUniformLocation(program, 'colors'), colors: gl.getUniformLocation(program, 'colors'),
tilts: webgl2.getUniformLocation(program, 'tilts'), shifts: gl.getUniformLocation(program, 'shifts'),
scale: webgl2.getUniformLocation(program, 'scale'), scale: gl.getUniformLocation(program, 'scale'),
offset: webgl2.getUniformLocation(program, 'offset'), offset: gl.getUniformLocation(program, 'offset'),
tilt: webgl2.getUniformLocation(program, 'tilt'), pos: gl.getAttribLocation(program, 'pos'),
pos: webgl2.getAttribLocation(program, 'pos'), widthShifts: gl.getUniformLocation(program, 'widthShifts'),
webgl2 gl
}; };
return webglLocation; return webglLocation;
@ -215,68 +208,215 @@ class WebGL2WaveRender {
/** /**
* *
* @returns {Map<string, Uint32Array>} * @returns {{
* lineVerticesMap: Map<string, Uint32Array>,
* maskVerticesMap: Map<string, Uint32Array>
* }}
*/ */
makeVertex() { makeVertex() {
const globalLookup = this.globalLookup; const globalLookup = this.globalLookup;
const time = globalLookup.time; const time = globalLookup.time;
const verticesMap = new Map(); const lineVerticesMap = new Map();
const maskVerticesMap = new Map();
for (const id of Reflect.ownKeys(globalLookup.chango)) { for (const id of Reflect.ownKeys(globalLookup.chango)) {
const signalItem = globalLookup.chango[id]; const signalItem = globalLookup.chango[id];
const { kind, wave } = signalItem; const { kind, wave } = signalItem;
if (kind === 'bit') { if (kind === 'bit') {
const vertices = this.makeBitVertex(wave, time); const { lineVertices, maskVertices } = this.makeBitVertex(wave, time);
verticesMap.set(id, vertices); lineVerticesMap.set(id, lineVertices);
maskVerticesMap.set(id, maskVertices);
} else if (kind === 'vec') { } else if (kind === 'vec') {
const vertices = this.makeVecVertex(wave, time); // const vertices = this.makeVecVertex(wave, time);
verticesMap.set(id, vertices); // lineVerticesMap.set(id, vertices);
}
}
return { lineVerticesMap, maskVerticesMap };
}
/**
* @description 将wave 的值转化为渲染需要用到的值
* @param {*} value
* @return {{
* y: number // 裁剪空间的纵坐标
* color: number // 颜色的索引 颜色rgb = gl_Colors[color]
* }}
*/
translateValue2RenderParameter(value) {
switch (value) {
case 0: return { y: -1, color: 2 }; // 0 value
case 1: return { y: 1, color: 3 }; // 1 value
case 2: case 3: return { y: -1, color: 4 }; // 不定态 x
case 4: case 5: return { y: 0, color: 2 }; // 高阻态 z
default: return { y: -1, color: 7 }; // 其他,我也不知道还有啥
}
}
/**
*
* @param {{x: number, y: number, color: number} | undefined} p0 前一个点
* @param {{x: number, y: number, color: number} | undefined} p1 当前的点
* @param {{x: number, y: number, color: number} | undefined} p2 后一个点
* @returns {number} 这是 widthshift 的索引只需要 + 4 % 8 就能得到另一个
*/
makeWidthShiftIndexByPoints(p0, p1, p2) {
if (p0 === undefined) {
if (p1.y === p2.y) {
return 0;
} else if (p1.x === p2.x) {
return 6;
}
} else if (p2 === undefined) {
if (p1.y === p0.y) {
return 0;
} else if (p1.x === p0.x) {
return 6;
}
} else {
if (p0.x !== p1.x && p0.y === p1.y && p1.x === p2.x && p1.y !== p2.y) {
if (p2.y > p1.y) {
return 1;
} else {
return 7;
}
} else if (p0.x === p1.x && p0.y !== p1.y && p1.x !== p2.x && p1.y === p2.y) {
if (p1.y > p0.y) {
return 1;
} else {
return 7;
}
} }
} }
return verticesMap;
} }
/** /**
* *
* @param {Array<string | number>} wave * @param {Array<string | number>} wave
* @param { number } time * @param { number } time
* @returns {Uint32Array} * @returns {{
* lineVertices: Uint32Array
* maskVertices: Uint32Array
* }}
*/ */
makeBitVertex(wave, time) { makeBitVertex(wave, time, debug = false) {
const vertices = []; const length = wave.length;
const ilen = wave.length; // 先将节点数据转化为裁剪空间的坐标
for (let i = 0; i < ilen; i++) { const perspectivePoints = [];
const f = wave[(i === 0) ? 0 : (i - 1)];
const [tim, val] = wave[i]; for (let i = 0; i < length; ++ i) {
const t = wave[(i === (ilen - 1)) ? i : (i + 1)]; // const currentWave = wave[(i === 0) ? 0 : (i - 1)];
const tt = (i === (ilen - 1)) ? time : wave[i + 1][0]; const currentWave = wave[i];
switch (val) { const nextWave = (i === (length - 1)) ? wave[i] : wave[i + 1];
case 0: case 1: // 0 1
vertices.push(...bar[val](f[1], t[1], tim, tt, 2, 3)); const t1 = currentWave[0];
break; const t2 = (i === (length - 1)) ? time : wave[i + 1][0];
case 2: case 3: // x X const value1 = currentWave[1];
vertices.push(...bar[2](f[1], t[1], tim, tt, 4, 4)); const value2 = nextWave[1];
break;
case 4: case 5: // z Z const renderParam1 = this.translateValue2RenderParameter(value1);
vertices.push(...bar[2](f[1], t[1], tim, tt, 1, 1)); const renderParam2 = this.translateValue2RenderParameter(value2);
break;
case 6: case 7: // u U uninitialized if (i === 0) {
vertices.push(...bar[2](f[1], t[1], tim, tt, 6, 6)); perspectivePoints.push({ x: t1, y: renderParam1.y, color: renderParam1.color });
break; perspectivePoints.push({ x: t2, y: renderParam1.y, color: renderParam1.color });
case 8: case 9: // w W weak unknown } else {
vertices.push(...bar[2](f[1], t[1], tim, tt, 10, 10)); const lastPoint = perspectivePoints.at(-1);
break; if ((lastPoint.y !== renderParam1.y) || (lastPoint.color !== renderParam1.color)) {
case 10: case 11: // l L perspectivePoints.push({ x: t1, y: renderParam1.y, color: renderParam1.color });
vertices.push(...bar[0](f[1], t[1], tim, tt, 8, 9)); }
break; if ((renderParam1.y !== renderParam2.y) || (renderParam1.color !== renderParam2.color)) {
case 12: case 13: // h H perspectivePoints.push({ x: t2, y: renderParam1.y, color: renderParam1.color });
vertices.push(...bar[1](f[1], t[1], tim, tt, 8, 9)); }
break;
default:
vertices.push(...bar[2](f[1], t[1], tim, tt, 7, 7));
} }
} }
return new Uint32Array(vertices); // 确保最后一个点延申到了 time
const lastPoint = perspectivePoints.at(-1);
if (lastPoint.x < time) {
perspectivePoints.push({ x: time, y: lastPoint.y, color: lastPoint.color });
}
// 计算出传入 shader 四元组数组
// 四元组: (x, yshift_index, color_index, width_shift_index)
const pointNum = perspectivePoints.length;
const lineVertices = [];
const maskVertices = [];
// const lineVertices = [
// 0, 0, 2, 0,
// 10, 0, 2, 0,
// 10, 4, 2, 0,
// 20, 4, 2, 0,
// 20, 0, 2, 0,
// 30, 0, 2, 0,
// 30, 4, 2, 0
// ];
// return new Uint32Array(lineVertices);
// 制作 lineVertices
for (let i = 0; i < pointNum; ++ i) {
// p0: 上一个点
// p1: 当前的点
// p2: 下一个点
const p0 = perspectivePoints[i - 1];
const p1 = perspectivePoints[i];
const p2 = perspectivePoints[i + 1];
// p1.x, y1Index, p1.color, 0,
const y1Index = gl_Shifts_map.get(p1.y);
const wsIndex = this.makeWidthShiftIndexByPoints(p0, p1, p2);
lineVertices.push(
p1.x, y1Index, p1.color, wsIndex,
p1.x, y1Index, p1.color, (wsIndex + 4) % 8
);
// 防止颜色不同导致单个图元内出现两个颜色这会引发shader的渐变
if (p2 !== undefined && p1.color !== p2.color) {
lineVertices.push(
p1.x, y1Index, p2.color, wsIndex,
p1.x, y1Index, p2.color, (wsIndex + 4) % 8
);
}
}
// 制作 maskVertices
for (let i = 0; i < pointNum; ++ i) {
const p1 = perspectivePoints[i];
const p2 = perspectivePoints[i + 1];
const p3 = perspectivePoints[i + 2];
if (p1 === undefined || p2 === undefined || p3 === undefined) {
continue;
}
if (p2.y > p1.y) {
// 矩形的四个点
// 四元组: (x, yshift_index, color_index, width_shift_index)
const r1 = [p1.x, gl_Shifts_map.get(p1.y), p2.color + 10, 4];
const r2 = [p2.x, gl_Shifts_map.get(p2.y), p2.color + 10, 4];
const r3 = [p3.x, gl_Shifts_map.get(p3.y), p2.color + 10, 4];
const r4 = [p3.x, gl_Shifts_map.get(p1.y), p2.color + 10, 4];
// 三角图元画矩形
maskVertices.push(
...r1, ...r2, ...r3,
...r1, ...r3, ...r4,
);
}
}
if (debug) {
console.log(perspectivePoints);
console.log(pointNum);
console.log(lineVertices);
}
const Uint32lineVertices = new Uint32Array(lineVertices);
const Uint32maskVertices = new Uint32Array(maskVertices);
return {
lineVertices : Uint32lineVertices,
maskVertices : Uint32maskVertices
};
} }
/** /**
@ -287,13 +427,24 @@ class WebGL2WaveRender {
*/ */
makeVecVertex(wave, time) { makeVecVertex(wave, time) {
const vertices = []; const vertices = [];
const ilen = wave.length; const length = wave.length;
for (let i = 0; i < ilen; i++) { for (let i = 0; i < length; ++ i) {
const [t1, val, msk] = wave[i]; const [t1, val, msk] = wave[i];
const t2 = (i === (ilen - 1)) ? time : wave[i + 1][0]; const t2 = (i === (length - 1)) ? time : wave[i + 1][0];
// t1(val) --- t2(val)
if (msk) { if (msk) {
vertices.push(...brick[2](2, 2, t1, t2, 4, 4)); // x,z? vertices.push(
t1, 0, 0,
t2, 0, 0,
t2, 0, 4,
t2, 4, 4,
t1, 6, 4,
t1, 0, 4,
t1, 3, 4,
t2, 1, 4,
t2, 0, 4
);
} else { } else {
vertices.push( vertices.push(
t1, 0, 0, t1, 0, 0,
@ -315,26 +466,48 @@ class WebGL2WaveRender {
initData() { initData() {
const webglLocation = this.webglLocation; const webglLocation = this.webglLocation;
const webgl2 = webglLocation.webgl2; const gl = webglLocation.gl;
const globalLookup = this.globalLookup; const globalLookup = this.globalLookup;
const verticesMap = this.verticesMap; const lineVerticesMap = this.lineVerticesMap;
const maskVerticesMap = this.maskVerticesMap;
for (const id of Reflect.ownKeys(globalLookup.chango)) { for (const id of Reflect.ownKeys(globalLookup.chango)) {
const signalItem = globalLookup.chango[id]; const signalItem = globalLookup.chango[id];
const vertices = verticesMap.get(id);
const vertexBuffer = webgl2.createBuffer(); const lineVertices = lineVerticesMap.get(id);
webgl2.bindBuffer(webgl2.ARRAY_BUFFER, vertexBuffer); if (lineVertices === undefined) {
// 将初始化的顶点数据复制到 buffer 区域 // console.warn(`无法找到 link 为 ${id} 的顶点数据`);
webgl2.bufferData(webgl2.ARRAY_BUFFER, vertices, webgl2.STATIC_DRAW); continue;
}
signalItem.vao = webgl2.createVertexArray(); // 创建并设置 绘制wave轮廓 主体轮廓的 缓冲区、vao、顶点设置
webgl2.bindVertexArray(signalItem.vao); const lineVertexBuffer = gl.createBuffer();
webgl2.vertexAttribIPointer(webglLocation.pos, 3, webgl2.UNSIGNED_INT, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexBuffer);
webgl2.enableVertexAttribArray(webglLocation.pos); gl.bufferData(gl.ARRAY_BUFFER, lineVertices, gl.STATIC_DRAW);
webgl2.uniform4fv(webglLocation.colors, cColors); signalItem.lineVao = gl.createVertexArray();
webgl2.uniform2fv(webglLocation.tilts, cTilts); gl.bindVertexArray(signalItem.lineVao);
gl.vertexAttribIPointer(webglLocation.pos, 4, gl.UNSIGNED_INT, 0, 0);
gl.enableVertexAttribArray(webglLocation.pos);
const maskVertices = maskVerticesMap.get(id);
if (maskVertices === undefined) {
continue;
}
// 创建并设置 绘制wave半透明遮罩层 主体轮廓的 缓冲区、vao、顶点设置
const maskVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, maskVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, maskVertices, gl.STATIC_DRAW);
signalItem.maskVao = gl.createVertexArray();
gl.bindVertexArray(signalItem.maskVao);
gl.vertexAttribIPointer(webglLocation.pos, 4, gl.UNSIGNED_INT, 0, 0);
gl.enableVertexAttribArray(webglLocation.pos);
} }
gl.uniform4fv(webglLocation.colors, gl_Colors);
gl.uniform2fv(webglLocation.widthShifts, gl_WidthShifts);
gl.uniform2fv(webglLocation.shifts, gl_Shifts);
} }
render() { render() {
@ -344,42 +517,74 @@ class WebGL2WaveRender {
const canvas = this.canvas; const canvas = this.canvas;
const webglLocation = this.webglLocation; const webglLocation = this.webglLocation;
const webgl2 = webglLocation.webgl2; const gl = webglLocation.gl;
const globalLookup = this.globalLookup; const globalLookup = this.globalLookup;
const verticesMap = this.verticesMap; const lineVerticesMap = this.lineVerticesMap;
const maskVerticesMap = this.maskVerticesMap;
const elements = this.elements; const elements = this.elements;
const timeScaleHeight = parseInt(document.body.style.getPropertyValue('--time-scale-height').match(/\d+/)[0]);
const sidebarPadding = parseInt(document.body.style.getPropertyValue('--sidebar-padding').match(/\d+/)[0]);
const vcdRenderPadding = parseInt(document.body.style.getPropertyValue('--vcd-render-padding').match(/\d+/)[0]);
const canvasPaddingTop = timeScaleHeight + sidebarPadding - vcdRenderPadding;
this.animationHandler = window.requestAnimationFrame(() => { this.animationHandler = window.requestAnimationFrame(() => {
const { width, height, xScale, xOffset, yOffset, yStep, yDuty } = this.pstate; const { width, height, xScale, xOffset, yOffset, yStep, yDuty } = this.pstate;
const canvasHeight = height - 40; const canvasHeight = height - canvasPaddingTop;
canvas.width = width; const canvasWidth = width;
// 默认 1594
canvas.width = canvasWidth;
// 默认 1260
canvas.height = canvasHeight; canvas.height = canvasHeight;
// 设置 glsl 变量 // 设置 glsl 变量
webgl2.uniform1f(webglLocation.tilt, 3 / width); gl.uniform2f(webglLocation.scale,
webgl2.uniform2f(webglLocation.scale, 2 * xScale / width, yStep * yDuty / canvasHeight); 2 * xScale / canvasWidth,
yStep * yDuty / canvasHeight
);
console.log(yStep, yDuty, canvasHeight);
// 设置 webgl 和 canvas 大小位置一致 // 设置 webgl 和 canvas 大小位置一致
webgl2.viewport(0, 0, width, canvasHeight); gl.viewport(0, 0, canvasWidth, canvasHeight);
// 清楚颜色缓冲区,也就是删除上一次的渲染结果 // 清楚颜色缓冲区,也就是删除上一次的渲染结果
webgl2.clear(webgl2.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
// 根据 globalLookup 当前激活的需要渲染的信号进行渲染 // 根据 globalLookup 当前激活的需要渲染的信号进行渲染
let index = 0; let index = 0;
for (const signal of globalLookup.currentWires) { for (const signal of globalLookup.currentWires) {
const wave = globalLookup.chango[signal.link].wave;
// this.makeBitVertex(wave, globalLookup.time, true);
const signalItem = globalLookup.chango[signal.link]; const signalItem = globalLookup.chango[signal.link];
if (!signalItem) { if (!signalItem) {
return; return;
} }
webgl2.bindVertexArray(signalItem.vao); // TODO: 将此处的 offset 计算中的参数和 globalSetting 的数字形成关联
webgl2.uniform2f(webglLocation.offset, gl.uniform2f(webglLocation.offset,
(2 * xOffset / width) - 1, (2 * xOffset / width) - 1,
(2 * yOffset - 2 * yStep * (index + .7)) / canvasHeight + 1 (2 * yOffset - 2 * yStep * (index + .7)) / canvasHeight + 1
); );
// 根据 vao 进行绘制
const vertices = verticesMap.get(signal.link);
// console.log(vertices); console.log('offset y', (2 * yOffset - 2 * yStep * (index + .7)) / canvasHeight + 1);
webgl2.drawArrays(webgl2.LINE_STRIP, 0, vertices.length / 3);
// 根据 lineVao 进行绘制
const lineVertices = lineVerticesMap.get(signal.link);
const maskVertices = maskVerticesMap.get(signal.link);
if (signal.size === 1) {
// 如果是 width 为 1 的
gl.bindVertexArray(signalItem.lineVao);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, lineVertices.length / 4);
``
gl.bindVertexArray(signalItem.maskVao);
gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / 4);
} else {
// 如果是 width 大于 1 的
gl.drawArrays(gl.LINE_STRIP, 0, lineVertices.length / 4);
}
index ++; index ++;
} }

View File

@ -18,12 +18,8 @@ const genResizeHandler = pstate =>
yOffset = yOffsetMax; yOffset = yOffsetMax;
} }
pstate.yOffset = yOffset; pstate.yOffset = yOffset;
// console.log('resize handler', pstate);
// X
// const xScaleMin = pstate.xScaleMin = (width - sidebarWidth) / time;
const xScaleMin = pstate.xScaleMin = 0.001; const xScaleMin = pstate.xScaleMin = 0.001;
console.log(width, sidebarWidth);
console.log('xScaleMin', xScaleMin);
pstate.xScale = (xScale < xScaleMin) ? xScaleMin : xScale; pstate.xScale = (xScale < xScaleMin) ? xScaleMin : xScale;
xOffsetUpdate(pstate, xOffset); xOffsetUpdate(pstate, xOffset);
}; };

View File

@ -11,7 +11,6 @@ const getLabel = (lane) => {
const formatter = format(fmt, width); const formatter = format(fmt, width);
return (value, mask, x, w) => { return (value, mask, x, w) => {
console.log(value, mask, x, w);
if (mask) { if (mask) {
if (value) { if (value) {

View File

@ -52,9 +52,8 @@ const editable = {
module.exports = { module.exports = {
// Alt + <, >. left / right // Alt + <, >. left / right
'Alt+,': scroll.left, 'Shift+icon:scrollUp': scroll.left, 'Alt+,': scroll.left,
'Alt+.': scroll.right,
'Alt+.': scroll.right, 'Shift+icon:scrollDown': scroll.right,
// Alt + [ ] home / end // Alt + [ ] home / end
'Alt+[': { desc: 'Jump to beginning of time', fn: pstate => xOffsetUpdate(pstate, pstate.sidebarWidth) }, // Home 'Alt+[': { desc: 'Jump to beginning of time', fn: pstate => xOffsetUpdate(pstate, pstate.sidebarWidth) }, // Home
@ -63,15 +62,18 @@ module.exports = {
// ALT + - + // ALT + - +
'Alt+=': pluso, // '+': pluso, '=': pluso, 'Alt+=': pluso, // '+': pluso, '=': pluso,
'Ctrl+icon:scrollUp': pluso,
'Alt+-': minuso, // '-': minuso, '_': minuso, 'Alt+-': minuso, // '-': minuso, '_': minuso,
'Ctrl+icon:scrollDown': minuso,
'Alt+0': fullo, // 'Shift+f': fullo, F: fullo, 'Shift+F': fullo, 'Alt+0': fullo, // 'Shift+f': fullo, F: fullo, 'Shift+F': fullo,
'Alt+/': editable, 'Alt+/': editable,
// wheel
'icon:scrollLeft': scroll.left,
'icon:scrollRight': scroll.right,
'Shift+icon:scrollUp': scroll.left,
'Shift+icon:scrollDown': scroll.right,
'Ctrl+icon:scrollUp': pluso,
'Ctrl+icon:scrollDown': minuso,
// CAN'T DO: Alt + e, d, f, l // CAN'T DO: Alt + e, d, f, l
// ArrowUp: scroll.up, 'Shift+ArrowUp': scroll.up, // ArrowUp: scroll.up, 'Shift+ArrowUp': scroll.up,

View File

@ -91,7 +91,7 @@ function* renderValues(desc, pstate) {
const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]); const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]);
const xCur = getX(pstate, tCur); const xCur = getX(pstate, tCur);
console.log(mark, vPre, mPre, vCur, mCur); // console.log(mark, vPre, mPre, vCur, mCur);
if (vPre !== undefined || mPre !== undefined) { if (vPre !== undefined || mPre !== undefined) {
if (xPre > width && xCur > width) { // both time stamps to the right if (xPre > width && xCur > width) { // both time stamps to the right
@ -111,9 +111,7 @@ function* renderValues(desc, pstate) {
} }
xPre = xCur; xPre = xCur;
vPre = vCur; vPre = vCur;
console.log(mPre, mCur);
mPre = mCur; mPre = mCur;
console.log(mPre, mCur);
} }
} }
ml.push(mLane); ml.push(mLane);

View File

@ -33,7 +33,7 @@ const progress = (lane, desc, pstate) => {
if (desc.chango[clock.ref] === undefined) { if (desc.chango[clock.ref] === undefined) {
console.log(desc.chango, clock, clock.ref); // console.log(desc.chango, clock, clock.ref);
return pco; return pco;
} }
const clockWave = desc.chango[clock.ref].wave; const clockWave = desc.chango[clock.ref].wave;

View File

@ -6,6 +6,7 @@ import zh from './zh.json';
const i18n = createI18n({ const i18n = createI18n({
legacy: false, legacy: false,
locale: 'en', locale: 'en',
warnHtmlMessage: false,
messages: { en, zh } messages: { en, zh }
}); });

1
test/render-line/delaunator.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
#version 300 es
precision mediump float;
uniform vec4 a_color;
out vec4 outColor;
void main(){
outColor = a_color;
}

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="canvas" height="500", width="500"></canvas>
</body>
</html>
<script src="./main.js"></script>
<style>
body {
background-color: var(--vscode-editor-background);
color: white;
}
#canvas {
top: 20px;
position: absolute;
}
</style>

278
test/render-line/main.js Normal file
View File

@ -0,0 +1,278 @@
/**
* @description 创建着色器对象
* @param {WebGL2RenderingContext} gl
* @param {'VERTEX_SHADER' | 'FRAGMENT_SHADER'} type
* @param {string} source
* @return { WebGLShader | undefined }
*/
function makeShader(gl, type, source) {
// 创建 shader
const shader = gl.createShader(gl[type]);
// 给 shader 提供 glsl 代码
gl.shaderSource(shader, source);
// 编译 glsl 生成 shader
gl.compileShader(shader);
const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
// 如果成功,则返回 shader否则返回 undefined
return ok ? shader : gl.deleteShader(shader);
}
/**
*
* @param {string} path
* @return {string}
*/
async function getSource(path) {
const response = await fetch(path);
const source = await response.text();
return source;
}
window.onload = async () => {
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
if (!(gl instanceof WebGL2RenderingContext)) {
console.log('浏览器不支持 webgl2');
return;
}
const vertexSource = await getSource('./vertex.shader.glsl');
const fragementSource = await getSource('./fragment.shader.glsl');
const vertexShader = makeShader(gl, 'VERTEX_SHADER', vertexSource);
const fragmentShader = makeShader(gl, 'FRAGMENT_SHADER', fragementSource);
if (!vertexShader || !fragmentShader) {
console.log('着色器创建失败');
return;
}
const program = createProgram(gl, vertexShader, fragmentShader);
if (!program) {
console.log('着色程序创建失败');
return;
}
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
const points = [
0, -0.5,
0.5, -0.5,
];
drawMask(gl, program, points, { width: 0.06 });
drawLine2D(gl, program, points, { width: 0.06 });
}
function onTheSameLine(x0, y0, x1, y1, x2, y2) {
const slope1 = (x1 - x0) !== 0 ? (y1 - y0) / (x1 - x0) : Infinity;
const slope2 = (x2 - x0) !== 0 ? (y2 - y0) / (x2 - x0) : Infinity;
return slope1 === slope2;
}
function sgn(value) {
if (value === 0) return 0;
return value > 0 ? 1 : -1;
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} points
* @param {{
* width: number
* color: string
* }} config
*/
function drawLine2D(gl, program, points, config) {
const pointNum = points.length >> 1;
const w = config.width;
const shift = w / 2;
const positions = [];
for (let i = 0; i < pointNum; ++ i) {
const x1 = points[(i << 1)];
const y1 = points[(i << 1) + 1];
if (i === 0) {
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (y1 === y2) {
// console.log('enter i = 0');
positions.push(
x1, y1 + shift, // v0
x1, y1 - shift // v1
);
} else if (x1 === x2) {
positions.push(
x1 + shift, y1, // v1
x1 - shift, y1, // v0
);
}
} else if (i === pointNum - 1) {
const x0 = points[((i - 1) << 1)];
const y0 = points[((i - 1) << 1) + 1];
if (y1 === y0) {
// console.log('enter i = pointNum - 1');
positions.push(
x1, y1 + shift, // v0
x1, y1 - shift // v1
);
} else if (x1 === x0) {
positions.push(
x1 + shift, y1, // v1
x1 - shift, y1, // v0
);
}
} else {
const x0 = points[((i - 1) << 1)];
const y0 = points[((i - 1) << 1) + 1];
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (x0 !== x1 && y0 === y1 && x1 === x2 && y1 !== y2) {
const d = sgn(y2 - y1);
if (y2 > y1) {
positions.push(
x1 - shift, y1 + shift,
x1 + shift, y1 - shift
);
} else {
positions.push(
x1 + shift, y1 + shift,
x1 - shift, y1 - shift,
);
}
} else if (x0 === x1 && y0 !== y1 && x1 !== x2 && y1 === y2) {
const d = sgn(y1 - y0);
if (y1 > y0) {
positions.push(
x1 - shift, y1 + shift,
x1 + shift, y1 - shift,
);
} else {
positions.push(
x1 + shift, y1 + shift,
x1 - shift, y1 - shift,
);
}
}
}
}
const positionFloat32 = new Float32Array(positions);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW);
gl.useProgram(program);
const positionLocation = gl.getAttribLocation(program, 'a_position');
const colorLocation = gl.getUniformLocation(program, 'a_color');
gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 1.0);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, positionFloat32.length >> 1);
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} times
* @param {{
* width: number
* color: string
* }} config
* @param {number} yshift
*/
function drawBlock(gl, program, times, config, yshift) {
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} points
* @param {{
* width: number
* color: string
* }} config
*/
function drawMask(gl, program, points, config) {
const positions = [];
const pointNum = points.length >> 1;
const w = config.width;
const shift = w / 2;
for (let i = 0; i < pointNum; ++ i) {
const x1 = points[(i << 1)];
const y1 = points[(i << 1) + 1];
if (i + 1 < pointNum) {
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (y2 > y1 && i + 2 < pointNum) {
const x3 = points[((i + 2) << 1)];
const y3 = points[((i + 2) << 1) + 1];
const p1 = [x1, y1 - shift];
const p2 = [x2, y2 - shift];
const p3 = [x3, y3 - shift];
const p4 = [x3, y1 - shift];
positions.push(
...p1,
...p2,
...p3,
...p1,
...p3,
...p4
);
}
}
}
const positionFloat32 = new Float32Array(positions);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW);
gl.useProgram(program);
const aPostionLocation = gl.getAttribLocation(program, 'a_position');
const colorLocation = gl.getUniformLocation(program, 'a_color');
gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 0.2);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enableVertexAttribArray(aPostionLocation);
gl.vertexAttribPointer(aPostionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, positionFloat32.length >> 1);
}
/**
* @description 创建着色器
* @param {WebGL2RenderingContext} gl
* @param {WebGLShader} vertexShader
* @param {WebGLShader} fragmentShader
* @return { WebGLProgram | undefined }
*/
function createProgram(gl, vertexShader, fragmentShader) {
// 创建着色程序
const program = gl.createProgram();
// 加载着色器到着色程序
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 连接着色程序
gl.linkProgram(program);
const ok = gl.getProgramParameter(program, gl.LINK_STATUS);
return ok ? program : gl.deleteProgram(program);
}

View File

@ -0,0 +1,7 @@
#version 300 es
in vec4 a_position;
void main() {
gl_Position = a_position;
}

View File

@ -0,0 +1,655 @@
<mxfile host="65bd71144e">
<diagram id="fareUikBvdjO0hJmng89" name="第 1 页">
<mxGraphModel dx="1683" dy="929" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="101" value="\[p_1\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1340" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="94" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f0a30a;fontColor=#000000;strokeColor=#BD7000;opacity=30;" vertex="1" parent="1">
<mxGeometry x="1090" y="802.5" width="150" height="267.5" as="geometry"/>
</mxCell>
<mxCell id="2" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="345" y="545" as="sourcePoint"/>
<mxPoint x="345" y="385" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="3" value="\[p_2=(x_2,y_2)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="290" y="350" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="4" value="\[p_0=(x_0,y_0)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="50" y="540" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="5" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="105" y="545" as="sourcePoint"/>
<mxPoint x="345" y="545" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="6" value="\[p_1=(x_1,y_1)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="290" y="540" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="95" y="600" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="390" y="600" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="9" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="95" y="480" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="10" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="270" y="480" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="11" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="270" y="380" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="14" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="390" y="380" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="16" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="584" y="360" as="sourcePoint"/>
<mxPoint x="914" y="360" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="17" value="\[p_2=(x_2,y_2)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="890" y="350" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="18" value="\[p_0=(x_0,y_0)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="530" y="545" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="19" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="585" y="550" as="sourcePoint"/>
<mxPoint x="585" y="360" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="20" value="\[p_1=(x_1,y_1)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="480" y="340" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="21" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="620" y="545" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="22" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="900" y="310" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="23" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="525" y="545" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="24" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="620" y="390" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="25" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="525" y="310" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="26" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="900" y="390" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="28" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="360.0000000000001" y="875.0000000000001" as="sourcePoint"/>
<mxPoint x="360" y="1050" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="29" value="\[p_2=(x_2,y_2)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="320" y="1060" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="30" value="\[p_0=(x_0,y_0)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="50" y="870" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="31" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="105" y="875.0000000000001" as="sourcePoint"/>
<mxPoint x="360" y="875" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="32" value="\[p_1=(x_1,y_1)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="290" y="830" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="33" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="95" y="930" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="34" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="290" y="1030" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="35" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="95" y="810" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="36" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="400" y="810" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="37" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="290" y="930" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="38" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" parent="1" vertex="1">
<mxGeometry x="400" y="1030" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="W18mgVVtD26MayaxvlpH-38" value="" style="endArrow=none;dashed=1;html=1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint y="490" as="sourcePoint"/>
<mxPoint x="80" y="490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="W18mgVVtD26MayaxvlpH-39" value="" style="endArrow=none;dashed=1;html=1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint y="609.58" as="sourcePoint"/>
<mxPoint x="80" y="609.58" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="W18mgVVtD26MayaxvlpH-40" value="" style="endArrow=classic;startArrow=classic;html=1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="40" y="610" as="sourcePoint"/>
<mxPoint x="40" y="490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="W18mgVVtD26MayaxvlpH-41" value="\[w&lt;br style=&quot;font-size: 18px;&quot;&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#FFFFFF;fontSize=18;" parent="1" vertex="1">
<mxGeometry x="-10" y="520" width="50" height="60" as="geometry"/>
</mxCell>
<mxCell id="40" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1" source="126">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="825" y="1070" as="sourcePoint"/>
<mxPoint x="1090" y="1070" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="44" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1" target="42">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="824.9999999999998" y="1070" as="sourcePoint"/>
<mxPoint x="1094.9999999999998" y="1070" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="47" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="42" target="46">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="49" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="42" target="48">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="51" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="42" target="50">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="54" style="edgeStyle=none;html=1;exitX=0;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="42" target="56">
<mxGeometry relative="1" as="geometry">
<mxPoint x="764.9999999999998" y="1010" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="55" style="edgeStyle=none;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="42" target="57">
<mxGeometry relative="1" as="geometry">
<mxPoint x="764.9999999999998" y="1130" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="90" style="edgeStyle=none;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="42" target="89">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="42" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="815" y="1060" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="46" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="815" y="960" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="48" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="715" y="1060" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="50" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="815" y="1160" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="56" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="715" y="960" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="57" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="715" y="1160" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="58" value="\[(0, \frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="770" y="925" width="110" height="30" as="geometry"/>
</mxCell>
<mxCell id="59" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="870" y="1450" as="sourcePoint"/>
<mxPoint x="670" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="60" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="670" y="1530" as="sourcePoint"/>
<mxPoint x="670" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="61" value="\[p_0\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="640" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="62" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="670" y="1490" as="sourcePoint"/>
<mxPoint x="910" y="1490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="63" value="\[p_1\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="880" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="64" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="910" y="1490" as="sourcePoint"/>
<mxPoint x="910" y="1330" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="65" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1070" y="1330" as="sourcePoint"/>
<mxPoint x="910" y="1330" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="66" value="\[p_2\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="880" y="1300" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="67" value="\[p_3\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1040" y="1300" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="68" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="870" y="1450" as="sourcePoint"/>
<mxPoint x="670" y="1530" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="69" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="910" y="1530" as="sourcePoint"/>
<mxPoint x="670" y="1530" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="70" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="910" y="1530" as="sourcePoint"/>
<mxPoint x="870" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="71" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="910" y="1530" as="sourcePoint"/>
<mxPoint x="950" y="1490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="72" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="870" y="1450" as="sourcePoint"/>
<mxPoint x="870" y="1330" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="73" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="870" y="1330" as="sourcePoint"/>
<mxPoint x="910" y="1290" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="74" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1490" as="sourcePoint"/>
<mxPoint x="950" y="1370" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="75" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1070" y="1370" as="sourcePoint"/>
<mxPoint x="950" y="1370" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="76" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1070" y="1290" as="sourcePoint"/>
<mxPoint x="904" y="1290" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="77" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1070" y="1370" as="sourcePoint"/>
<mxPoint x="1070" y="1290" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="78" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1490" as="sourcePoint"/>
<mxPoint x="870" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="79" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1370" as="sourcePoint"/>
<mxPoint x="870" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="80" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1370" as="sourcePoint"/>
<mxPoint x="870" y="1330" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="81" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1370" as="sourcePoint"/>
<mxPoint x="910" y="1290" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="82" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="950" y="1370" as="sourcePoint"/>
<mxPoint x="1070" y="1290" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="83" value="\[p_0\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="640" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="84" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="670" y="1490" as="sourcePoint"/>
<mxPoint x="910" y="1490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="85" value="\[(-\frac{w}{2}&lt;br&gt;, \frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="635" y="920" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="86" value="\[(-\frac{w}{2}, 0&lt;br&gt;)\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="620" y="1050" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="87" value="\[(-\frac{w}{2}&lt;br&gt;, -\frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="630" y="1175" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="88" value="\[(0, -\frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="765" y="1190" width="120" height="30" as="geometry"/>
</mxCell>
<mxCell id="89" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="905" y="1160" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="91" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1089.999999999967" y="1069.6599999999999" as="sourcePoint"/>
<mxPoint x="1090" y="800" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="92" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1240" y="800" as="sourcePoint"/>
<mxPoint x="1090" y="800" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="93" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1240" y="1070" as="sourcePoint"/>
<mxPoint x="1240" y="800" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="95" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1370" y="1070" as="sourcePoint"/>
<mxPoint x="1240" y="1070" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="96" value="\[(\frac{w}{2}&lt;br&gt;, -\frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="930" y="1175" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="97" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1329.9999999999998" y="1449.9999999999998" as="sourcePoint"/>
<mxPoint x="1129.9999999999998" y="1449.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="98" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1129.9999999999998" y="1530" as="sourcePoint"/>
<mxPoint x="1129.9999999999998" y="1449.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="99" value="\[p_0\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1100" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="100" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1129.9999999999998" y="1490" as="sourcePoint"/>
<mxPoint x="1369.9999999999998" y="1490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="102" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1369.9999999999998" y="1490" as="sourcePoint"/>
<mxPoint x="1369.9999999999998" y="1329.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="103" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1530" y="1329.9999999999998" as="sourcePoint"/>
<mxPoint x="1369.9999999999998" y="1329.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="104" value="\[p_2\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1340" y="1300" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="105" value="\[p_3\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1500" y="1300" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="106" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1329.9999999999998" y="1449.9999999999998" as="sourcePoint"/>
<mxPoint x="1129.9999999999998" y="1530" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="107" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1410" y="1530" as="sourcePoint"/>
<mxPoint x="1129.9999999999998" y="1530" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="110" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1329.9999999999998" y="1449.9999999999998" as="sourcePoint"/>
<mxPoint x="1330" y="1270" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="111" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1410" y="1530" as="sourcePoint"/>
<mxPoint x="1409.9999999999998" y="1369.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="112" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1530" y="1369.9999999999998" as="sourcePoint"/>
<mxPoint x="1409.9999999999998" y="1369.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="115" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1410" y="1530" as="sourcePoint"/>
<mxPoint x="1329.9999999999998" y="1449.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="117" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1129.9999999999998" y="1490" as="sourcePoint"/>
<mxPoint x="1369.9999999999998" y="1490" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="118" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1530" y="1280" as="sourcePoint"/>
<mxPoint x="1330" y="1279.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="119" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1530" y="1370" as="sourcePoint"/>
<mxPoint x="1530" y="1279.5799999999997" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="120" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1410" y="1370" as="sourcePoint"/>
<mxPoint x="1330" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="121" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1410" y="1369.9999999999998" as="sourcePoint"/>
<mxPoint x="1330" y="1280" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="122" value="" style="endArrow=none;html=1;strokeColor=#FFFFFF;strokeWidth=2;fontColor=#F0B102;dashed=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1530" y="1280" as="sourcePoint"/>
<mxPoint x="1410" y="1369.9999999999998" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="116" value="\[p_0\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="1100" y="1490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="123" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="905" y="960" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="124" value="" style="edgeStyle=none;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="42" target="123">
<mxGeometry relative="1" as="geometry">
<mxPoint x="970" y="1070" as="sourcePoint"/>
<mxPoint x="970" y="990" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="125" value="\[(\frac{w}{2}&lt;br&gt;, \frac{w}{2})\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="920" y="915" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="127" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;startArrow=none;" edge="1" parent="1" source="42" target="126">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="835" y="1070" as="sourcePoint"/>
<mxPoint x="1090" y="1070" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="126" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#000000;fillColor=#f0a30a;strokeColor=#BD7000;" vertex="1" parent="1">
<mxGeometry x="905" y="1060" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="128" value="\[(\frac{w}{2}, 0)\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="925" y="1035" width="110" height="30" as="geometry"/>
</mxCell>
<mxCell id="129" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="540" y="969.42" as="sourcePoint"/>
<mxPoint x="620" y="969.42" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="130" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="540" y="1174" as="sourcePoint"/>
<mxPoint x="620" y="1174" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="131" value="" style="endArrow=classic;startArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="580" y="1170" as="sourcePoint"/>
<mxPoint x="580" y="969.42" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="132" value="\[w&lt;br style=&quot;font-size: 18px;&quot;&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#FFFFFF;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="520" y="1040" width="50" height="60" as="geometry"/>
</mxCell>
<mxCell id="133" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="570" y="1450" as="sourcePoint"/>
<mxPoint x="650" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="134" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="570" y="1530" as="sourcePoint"/>
<mxPoint x="650" y="1530" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="135" value="" style="endArrow=classic;startArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="610" y="1530" as="sourcePoint"/>
<mxPoint x="610" y="1450" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="136" value="\[w&lt;br style=&quot;font-size: 18px;&quot;&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#FFFFFF;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="550" y="1460" width="50" height="60" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="ldzhMOmdS79g5s7hsVNb" name="第 2 页">
<mxGraphModel dx="1345" dy="451" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="0KlvA6460LBpeT4quUVe-1" value="\[p_0=(x_0,y_0)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="120" y="500" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-2" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="120" y="520" as="sourcePoint"/>
<mxPoint x="160" y="400" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-3" value="\[p_1=(x_1,y_1)&lt;br&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="440" y="500" width="110" height="40" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-4" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="100" y="810" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-5" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="485" y="810" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-6" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="100" y="690" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontColor=#F0B102;" vertex="1" parent="1">
<mxGeometry x="485" y="690" width="20" height="20" as="geometry"/>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-8" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="120" y="520" as="sourcePoint"/>
<mxPoint x="160" y="640" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-9" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="160" y="400" as="sourcePoint"/>
<mxPoint x="400" y="400" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-10" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="160" y="640" as="sourcePoint"/>
<mxPoint x="400" y="640" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="0KlvA6460LBpeT4quUVe-11" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="400" y="400" as="sourcePoint"/>
<mxPoint x="440" y="520" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="YzxP9u1fmLVgk9Jru_4W-1" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="-40" y="400" as="sourcePoint"/>
<mxPoint x="140" y="400" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="YzxP9u1fmLVgk9Jru_4W-2" value="" style="endArrow=none;dashed=1;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="-40" y="640" as="sourcePoint"/>
<mxPoint x="120" y="639.9999999999999" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="YzxP9u1fmLVgk9Jru_4W-3" value="" style="endArrow=classic;startArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="80" y="640" as="sourcePoint"/>
<mxPoint x="80" y="400" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="YzxP9u1fmLVgk9Jru_4W-4" value="\[w&lt;br style=&quot;font-size: 18px;&quot;&gt;\]" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#FFFFFF;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="20" y="480" width="50" height="60" as="geometry"/>
</mxCell>
<mxCell id="YzxP9u1fmLVgk9Jru_4W-6" value="" style="endArrow=none;html=1;strokeWidth=2;fillColor=#f0a30a;strokeColor=#F0B102;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="400" y="640.0000000000001" as="sourcePoint"/>
<mxPoint x="440" y="520" as="targetPoint"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@ -0,0 +1,7 @@
#version 300 es
precision mediump float;
in vec4 v_color;
out vec4 outColor;
void main() {
outColor = v_color;
}

View File

@ -7,11 +7,11 @@ uniform vec4 colors[16];
uniform vec2 tilts[7]; uniform vec2 tilts[7];
uniform float tilt; uniform float tilt;
void main() { void main() {
v_color = colors[pos.z]; v_color = colors[pos.z];
vec2 node = tilts[pos.y]; vec2 node = tilts[pos.y];
gl_Position = vec4( gl_Position = vec4(
float(pos.x) * scale.x + offset.x + node[1] * tilt, float(pos.x) * scale.x + offset.x + node[1] * tilt,
float(node[0]) * scale.y + offset.y, float(node[0]) * scale.y + offset.y,
1, 1 1, 1
); );
} }