poly-extrude 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +12 -0
- package/.eslintrc.js +34 -0
- package/.vscode/settings.json +3 -0
- package/LICENSE +21 -0
- package/babel.config.js +12 -0
- package/dist/poly-extrude.js +1317 -0
- package/dist/poly-extrude.js.map +1 -0
- package/dist/poly-extrude.min.js +4 -0
- package/dist/poly-extrude.mjs +1305 -0
- package/index.js +3 -0
- package/package.json +42 -0
- package/pnpm-lock.yaml +3054 -0
- package/rollup.config.js +108 -0
- package/src/polygon.js +148 -0
- package/src/polyline.js +190 -0
- package/src/util.js +205 -0
- package/test/buildings.html +77 -0
- package/test/data/a.png +0 -0
- package/test/data/building-texture-dark.jpg +0 -0
- package/test/data/building.geojson +1118 -0
- package/test/data/buildings-ny.geojson +2845 -0
- package/test/data/buildings.geojson +1 -0
- package/test/data/free-line.geojson +1 -0
- package/test/data/line.geojson +1 -0
- package/test/data/polygon.geojson +1 -0
- package/test/data/simple-hole.geojson +1 -0
- package/test/data/simple-line.geojson +45 -0
- package/test/data/simple.geojson +1 -0
- package/test/data/street.geojson +1 -0
- package/test/data//345/244/252/346/271/226.geojson +8 -0
- package/test/data//350/210/237/345/261/261/345/270/202.geojson +1 -0
- package/test/data//350/213/217/345/267/236.geojson +1 -0
- package/test/data//351/204/261/351/230/263/346/271/226.geojson +1 -0
- package/test/line-draw.html +100 -0
- package/test/line-uv.html +69 -0
- package/test/line.html +56 -0
- package/test/multi-polygon.html +53 -0
- package/test/ny-building.html +67 -0
- package/test/simple.html +61 -0
- package/test/street.html +52 -0
- package/test/util.js +131 -0
- package/test/uv.html +77 -0
package/rollup.config.js
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
// Rollup plugins
|
2
|
+
|
3
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
4
|
+
import { babel } from '@rollup/plugin-babel';
|
5
|
+
import commonjs from '@rollup/plugin-commonjs';
|
6
|
+
import json from '@rollup/plugin-json';
|
7
|
+
import { terser } from 'rollup-plugin-terser';
|
8
|
+
// import swc from 'rollup-plugin-swc';
|
9
|
+
import pkg from './package.json';
|
10
|
+
const path = require('path');
|
11
|
+
|
12
|
+
const product = process.env.NODE_ENV.trim() === 'prd';
|
13
|
+
const FILEMANE = pkg.name;
|
14
|
+
const sourceMap = !product;
|
15
|
+
|
16
|
+
const banner = `/*!\n * ${pkg.name} v${pkg.version}\n */`;
|
17
|
+
let outro = pkg.name + ' v' + pkg.version;
|
18
|
+
outro = `typeof console !== 'undefined' && console.log('${outro}');`;
|
19
|
+
const plugins = [
|
20
|
+
json(),
|
21
|
+
nodeResolve(),
|
22
|
+
commonjs(),
|
23
|
+
// swc({
|
24
|
+
// // rollup: {
|
25
|
+
// // exclude: 'path/to/exclude/',
|
26
|
+
// // },
|
27
|
+
// jsc: {
|
28
|
+
// parser: {
|
29
|
+
// syntax: 'ecmascript'
|
30
|
+
// },
|
31
|
+
// target: 'es5'
|
32
|
+
// },
|
33
|
+
// 'sourceMaps': true
|
34
|
+
// })
|
35
|
+
babel({
|
36
|
+
babelHelpers: 'bundled'
|
37
|
+
// exclude: ['node_modules/**']
|
38
|
+
})
|
39
|
+
];
|
40
|
+
const external = [];
|
41
|
+
const globals = {
|
42
|
+
|
43
|
+
};
|
44
|
+
const name = 'polyextrude';
|
45
|
+
export default [
|
46
|
+
{
|
47
|
+
input: path.join(__dirname, './index.js'),
|
48
|
+
plugins: plugins,
|
49
|
+
// sourceMap: true,
|
50
|
+
external,
|
51
|
+
output:
|
52
|
+
{
|
53
|
+
'format': 'umd',
|
54
|
+
'name': name,
|
55
|
+
'file': `dist/${FILEMANE}.js`,
|
56
|
+
'sourcemap': sourceMap,
|
57
|
+
'extend': true,
|
58
|
+
'banner': banner,
|
59
|
+
'outro': outro,
|
60
|
+
'globals': globals
|
61
|
+
}
|
62
|
+
},
|
63
|
+
{
|
64
|
+
input: path.join(__dirname, './index.js'),
|
65
|
+
plugins: plugins.concat([terser()]),
|
66
|
+
// sourceMap: true,
|
67
|
+
external,
|
68
|
+
output:
|
69
|
+
{
|
70
|
+
'format': 'umd',
|
71
|
+
'name': name,
|
72
|
+
'file': `dist/${FILEMANE}.min.js`,
|
73
|
+
'sourcemap': false,
|
74
|
+
'extend': true,
|
75
|
+
'banner': banner,
|
76
|
+
'outro': outro,
|
77
|
+
'globals': globals
|
78
|
+
}
|
79
|
+
},
|
80
|
+
{
|
81
|
+
input: path.join(__dirname, './index.js'),
|
82
|
+
plugins: plugins,
|
83
|
+
// sourceMap: true,
|
84
|
+
external,
|
85
|
+
output:
|
86
|
+
{
|
87
|
+
'format': 'es',
|
88
|
+
'name': name,
|
89
|
+
'file': `dist/${FILEMANE}.mjs`,
|
90
|
+
'sourcemap': false,
|
91
|
+
'extend': true,
|
92
|
+
'banner': banner,
|
93
|
+
'outro': outro,
|
94
|
+
'globals': globals
|
95
|
+
}
|
96
|
+
}
|
97
|
+
// {
|
98
|
+
// 'sourcemap': false,
|
99
|
+
// 'format': 'es',
|
100
|
+
// // banner,
|
101
|
+
// 'file': `dist/${FILEMANE}.es.js`,
|
102
|
+
// 'extend': true,
|
103
|
+
// 'banner': banner,
|
104
|
+
// 'globals': {
|
105
|
+
// 'YY': 'YY'
|
106
|
+
// }
|
107
|
+
// }
|
108
|
+
];
|
package/src/polygon.js
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
|
2
|
+
import earcut from 'earcut';
|
3
|
+
import { generateNormal, generateSideWallUV, isClockwise, merge } from './util';
|
4
|
+
|
5
|
+
export function extrudePolygons(polygons, options) {
|
6
|
+
options = Object.assign({}, { depth: 2 }, options);
|
7
|
+
const results = polygons.map(polygon => {
|
8
|
+
if (!isClockwise(polygon[0])) {
|
9
|
+
polygon[0] = polygon[0].reverse();
|
10
|
+
}
|
11
|
+
polygon.slice(1, Infinity).forEach((coordinates, index) => {
|
12
|
+
if (isClockwise(coordinates)) {
|
13
|
+
polygon[index + 1] = coordinates.reverse();
|
14
|
+
}
|
15
|
+
});
|
16
|
+
polygon.forEach(ring => {
|
17
|
+
const len = ring.length;
|
18
|
+
const [x1, y1] = ring[0], [x2, y2] = ring[len - 1];
|
19
|
+
if (x1 === x2 && y1 === y2) {
|
20
|
+
ring.splice(len - 1, 1);
|
21
|
+
}
|
22
|
+
});
|
23
|
+
const result = flatVertices(polygon, options);
|
24
|
+
result.polygon = polygon;
|
25
|
+
const time = 'earcut';
|
26
|
+
console.time(time);
|
27
|
+
const triangles = earcut(result.flatVertices, result.holes, 2);
|
28
|
+
console.timeEnd(time);
|
29
|
+
generateTopAndBottom(result, triangles);
|
30
|
+
generateSides(result, options);
|
31
|
+
result.position = new Float32Array(result.points);
|
32
|
+
result.indices = new Uint32Array(result.index);
|
33
|
+
result.uv = new Float32Array(result.uvs);
|
34
|
+
result.normal = generateNormal(result.indices, result.position);
|
35
|
+
return result;
|
36
|
+
});
|
37
|
+
const result = merge(results);
|
38
|
+
result.polygons = polygons;
|
39
|
+
return result;
|
40
|
+
|
41
|
+
}
|
42
|
+
|
43
|
+
function generateTopAndBottom(result, triangles) {
|
44
|
+
const index = [];
|
45
|
+
const { count } = result;
|
46
|
+
for (let i = 0, len = triangles.length; i < len; i += 3) {
|
47
|
+
// top
|
48
|
+
const a = triangles[i], b = triangles[i + 1], c = triangles[i + 2];
|
49
|
+
index[i] = a;
|
50
|
+
index[i + 1] = b;
|
51
|
+
index[i + 2] = c;
|
52
|
+
// bottom
|
53
|
+
const idx = len + i;
|
54
|
+
const a1 = count + a, b1 = count + b, c1 = count + c;
|
55
|
+
index[idx] = a1;
|
56
|
+
index[idx + 1] = b1;
|
57
|
+
index[idx + 2] = c1;
|
58
|
+
}
|
59
|
+
result.index = index;
|
60
|
+
}
|
61
|
+
|
62
|
+
function generateSides(result, options) {
|
63
|
+
const { points, index, polygon, uvs } = result;
|
64
|
+
const z = options.depth;
|
65
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
66
|
+
const ring = polygon[i];
|
67
|
+
for (let j = 0, len1 = ring.length; j < len1; j++) {
|
68
|
+
const v1 = ring[j];
|
69
|
+
let v2 = ring[j + 1];
|
70
|
+
if (j === len1 - 1) {
|
71
|
+
v2 = ring[0];
|
72
|
+
}
|
73
|
+
// const p1 = [v1[0], v1[1], options.depth],
|
74
|
+
// p2 = [v2[0], v2[1], options.depth],
|
75
|
+
// p3 = [v1[0], v1[1], 0],
|
76
|
+
// p4 = [v2[0], v2[1], 0];
|
77
|
+
const idx = points.length / 3;
|
78
|
+
points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
|
79
|
+
const a = idx, b = idx + 1, c = idx + 2, d = idx + 3;
|
80
|
+
// points.push(p3, p4, p1, p2);
|
81
|
+
index.push(a, c, b);
|
82
|
+
index.push(c, d, b);
|
83
|
+
|
84
|
+
generateSideWallUV(uvs, points, a, b, c, d);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
function calPolygonPointsCount(polygon) {
|
90
|
+
let count = 0;
|
91
|
+
let i = 0;
|
92
|
+
const len = polygon.length;
|
93
|
+
while (i < len) {
|
94
|
+
count += (polygon[i].length);
|
95
|
+
i++;
|
96
|
+
}
|
97
|
+
return count;
|
98
|
+
}
|
99
|
+
|
100
|
+
function flatVertices(polygon, options) {
|
101
|
+
const count = calPolygonPointsCount(polygon);
|
102
|
+
const len = polygon.length;
|
103
|
+
const holes = [], flatVertices = new Float32Array(count * 2), points = [], uvs = [];
|
104
|
+
const pOffset = count * 3, uOffset = count * 2;
|
105
|
+
const z = options.depth;
|
106
|
+
|
107
|
+
let idx0 = 0, idx1 = 0, idx2 = 0;
|
108
|
+
for (let i = 0; i < len; i++) {
|
109
|
+
const ring = polygon[i];
|
110
|
+
if (i > 0) {
|
111
|
+
holes.push(idx0 / 2);
|
112
|
+
}
|
113
|
+
for (let j = 0, len1 = ring.length; j < len1; j++) {
|
114
|
+
const c = ring[j];
|
115
|
+
const x = c[0], y = c[1];
|
116
|
+
|
117
|
+
flatVertices[idx0++] = x;
|
118
|
+
flatVertices[idx0++] = y;
|
119
|
+
|
120
|
+
// top vertices
|
121
|
+
points[idx1] = x;
|
122
|
+
points[idx1 + 1] = y;
|
123
|
+
points[idx1 + 2] = z;
|
124
|
+
|
125
|
+
// bottom vertices
|
126
|
+
points[pOffset + idx1] = x;
|
127
|
+
points[pOffset + idx1 + 1] = y;
|
128
|
+
points[pOffset + idx1 + 2] = 0;
|
129
|
+
|
130
|
+
uvs[idx2] = x;
|
131
|
+
uvs[idx2 + 1] = y;
|
132
|
+
|
133
|
+
uvs[uOffset + idx2] = x;
|
134
|
+
uvs[uOffset + idx2 + 1] = y;
|
135
|
+
|
136
|
+
idx1 += 3;
|
137
|
+
idx2 += 2;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
return {
|
141
|
+
flatVertices,
|
142
|
+
holes,
|
143
|
+
points,
|
144
|
+
count,
|
145
|
+
uvs
|
146
|
+
};
|
147
|
+
|
148
|
+
}
|
package/src/polyline.js
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
import { degToRad, generateNormal, generateSideWallUV, merge, radToDeg } from './util';
|
2
|
+
|
3
|
+
export function extrudePolylines(lines, options) {
|
4
|
+
options = Object.assign({}, { depth: 2, lineWidth: 1 }, options);
|
5
|
+
const results = lines.map(line => {
|
6
|
+
const result = expandLine(line, options);
|
7
|
+
result.line = line;
|
8
|
+
generateTopAndBottom(result, options);
|
9
|
+
generateSides(result, options);
|
10
|
+
result.position = new Float32Array(result.points);
|
11
|
+
result.indices = new Uint32Array(result.index);
|
12
|
+
result.uv = new Float32Array(result.uvs);
|
13
|
+
result.normal = generateNormal(result.indices, result.position);
|
14
|
+
return result;
|
15
|
+
});
|
16
|
+
const result = merge(results);
|
17
|
+
result.lines = lines;
|
18
|
+
return result;
|
19
|
+
}
|
20
|
+
|
21
|
+
function generateTopAndBottom(result, options) {
|
22
|
+
const z = options.depth;
|
23
|
+
const points = [], index = [], uvs = [];
|
24
|
+
const { leftPoints, rightPoints } = result;
|
25
|
+
for (let i = 0, len = leftPoints.length; i < len; i++) {
|
26
|
+
// top left
|
27
|
+
const idx0 = i * 3;
|
28
|
+
const [x1, y1] = leftPoints[i];
|
29
|
+
points[idx0] = x1;
|
30
|
+
points[idx0 + 1] = y1;
|
31
|
+
points[idx0 + 2] = z;
|
32
|
+
|
33
|
+
// top right
|
34
|
+
const [x2, y2] = rightPoints[i];
|
35
|
+
const idx1 = len * 3 + idx0;
|
36
|
+
points[idx1] = x2;
|
37
|
+
points[idx1 + 1] = y2;
|
38
|
+
points[idx1 + 2] = z;
|
39
|
+
|
40
|
+
// bottom left
|
41
|
+
const idx2 = (len * 2) * 3 + idx0;
|
42
|
+
points[idx2] = x1;
|
43
|
+
points[idx2 + 1] = y1;
|
44
|
+
points[idx2 + 2] = 0;
|
45
|
+
|
46
|
+
// bottom right
|
47
|
+
const idx3 = (len * 2) * 3 + len * 3 + idx0;
|
48
|
+
points[idx3] = x2;
|
49
|
+
points[idx3 + 1] = y2;
|
50
|
+
points[idx3 + 2] = 0;
|
51
|
+
}
|
52
|
+
for (let i = 0, len = points.length; i < len; i += 3) {
|
53
|
+
const x = points[i], y = points[i + 1];
|
54
|
+
uvs.push(x, y);
|
55
|
+
}
|
56
|
+
for (let i = 0, len = leftPoints.length; i < len - 1; i++) {
|
57
|
+
// top
|
58
|
+
// left1 left2 right1,right2
|
59
|
+
const a1 = i, b1 = i + 1, c1 = a1 + len, d1 = b1 + len;
|
60
|
+
index.push(a1, c1, b1);
|
61
|
+
index.push(c1, d1, b1);
|
62
|
+
|
63
|
+
// bottom
|
64
|
+
// left1 left2 right1,right2
|
65
|
+
const len2 = len * 2;
|
66
|
+
const a2 = i + len2, b2 = a2 + 1, c2 = a2 + len, d2 = b2 + len;
|
67
|
+
index.push(a2, c2, b2);
|
68
|
+
index.push(c2, d2, b2);
|
69
|
+
}
|
70
|
+
result.index = index;
|
71
|
+
result.points = points;
|
72
|
+
result.uvs = uvs;
|
73
|
+
}
|
74
|
+
|
75
|
+
function generateSides(result, options) {
|
76
|
+
const { points, index, leftPoints, rightPoints, uvs } = result;
|
77
|
+
const z = options.depth;
|
78
|
+
const rings = [leftPoints, rightPoints];
|
79
|
+
function addOneSideIndex(v1, v2) {
|
80
|
+
const idx = points.length / 3;
|
81
|
+
points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
|
82
|
+
const a = idx, b = idx + 1, c = idx + 2, d = idx + 3;
|
83
|
+
// points.push(p3, p4, p1, p2);
|
84
|
+
index.push(a, c, b);
|
85
|
+
index.push(c, d, b);
|
86
|
+
generateSideWallUV(uvs, points, a, b, c, d);
|
87
|
+
}
|
88
|
+
|
89
|
+
for (let i = 0, len = rings.length; i < len; i++) {
|
90
|
+
let ring = rings[i];
|
91
|
+
if (i > 0) {
|
92
|
+
ring = ring.map(p => {
|
93
|
+
return p;
|
94
|
+
});
|
95
|
+
ring = ring.reverse();
|
96
|
+
}
|
97
|
+
for (let j = 0, len1 = ring.length - 1; j < len1; j++) {
|
98
|
+
const v1 = ring[j];
|
99
|
+
const v2 = ring[j + 1];
|
100
|
+
addOneSideIndex(v1, v2);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
const len = leftPoints.length;
|
104
|
+
const vs = [rightPoints[0], leftPoints[0], leftPoints[len - 1], rightPoints[len - 1]];
|
105
|
+
for (let i = 0; i < vs.length; i += 2) {
|
106
|
+
const v1 = vs[i], v2 = vs[i + 1];
|
107
|
+
addOneSideIndex(v1, v2);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
|
112
|
+
|
113
|
+
function expandLine(line, options) {
|
114
|
+
let preAngle = 0;
|
115
|
+
const radius = options.lineWidth / 2;
|
116
|
+
const points = [], leftPoints = [], rightPoints = [];
|
117
|
+
const len = line.length;
|
118
|
+
for (let i = 0; i < len - 1; i++) {
|
119
|
+
const p1 = line[i],
|
120
|
+
p2 = line[i + 1];
|
121
|
+
const dy = p2[1] - p1[1],
|
122
|
+
dx = p2[0] - p1[0];
|
123
|
+
let rAngle = 0;
|
124
|
+
const rad = Math.atan(dy / dx);
|
125
|
+
const angle = radToDeg(rad);
|
126
|
+
preAngle = angle;
|
127
|
+
if (i === 0) {
|
128
|
+
rAngle = angle;
|
129
|
+
rAngle -= 90;
|
130
|
+
} else {
|
131
|
+
const p0 = line[i - 1];
|
132
|
+
TEMPV1.x = p0[0] - p1[0];
|
133
|
+
TEMPV1.y = p0[1] - p1[1];
|
134
|
+
TEMPV2.x = p2[0] - p1[0];
|
135
|
+
TEMPV2.y = p2[1] - p1[1];
|
136
|
+
const vAngle = getAngle(TEMPV1, TEMPV2);
|
137
|
+
rAngle = angle - vAngle / 2;
|
138
|
+
}
|
139
|
+
const rRad = degToRad(rAngle);
|
140
|
+
const [op1, op2] = calOffsetPoint(rRad, radius, p1);
|
141
|
+
points.push(op1, op2);
|
142
|
+
if (leftOnLine(op1, p1, p2)) {
|
143
|
+
leftPoints.push(op1);
|
144
|
+
rightPoints.push(op2);
|
145
|
+
} else {
|
146
|
+
leftPoints.push(op2);
|
147
|
+
rightPoints.push(op1);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
let rAngle = preAngle;
|
151
|
+
rAngle -= 90;
|
152
|
+
const rRad = degToRad(rAngle);
|
153
|
+
const p1 = line[len - 2];
|
154
|
+
const p2 = line[len - 1];
|
155
|
+
const [op1, op2] = calOffsetPoint(rRad, radius, p2);
|
156
|
+
points.push(op1, op2);
|
157
|
+
if (leftOnLine(op1, p1, p2)) {
|
158
|
+
leftPoints.push(op1);
|
159
|
+
rightPoints.push(op2);
|
160
|
+
} else {
|
161
|
+
leftPoints.push(op2);
|
162
|
+
rightPoints.push(op1);
|
163
|
+
}
|
164
|
+
|
165
|
+
return { offsetPoints: points, leftPoints, rightPoints };
|
166
|
+
}
|
167
|
+
|
168
|
+
function calOffsetPoint(rad, radius, p) {
|
169
|
+
const [x, y] = p;
|
170
|
+
const x1 = Math.cos(rad) * radius, y1 = Math.sin(rad) * radius;
|
171
|
+
const p1 = [x + x1, y + y1];
|
172
|
+
const rad1 = rad += Math.PI;
|
173
|
+
const x2 = Math.cos(rad1) * radius, y2 = Math.sin(rad1) * radius;
|
174
|
+
const p2 = [x + x2, y + y2];
|
175
|
+
return [p1, p2];
|
176
|
+
}
|
177
|
+
|
178
|
+
const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
|
179
|
+
const dot = x1 * x2 + y1 * y2;
|
180
|
+
const det = x1 * y2 - y1 * x2;
|
181
|
+
const angle = Math.atan2(det, dot) / Math.PI * 180;
|
182
|
+
return (angle + 360) % 360;
|
183
|
+
};
|
184
|
+
|
185
|
+
function leftOnLine(p, p1, p2) {
|
186
|
+
const [x1, y1] = p1;
|
187
|
+
const [x2, y2] = p2;
|
188
|
+
const [x, y] = p;
|
189
|
+
return (y1 - y2) * x + (x2 - x1) * y + x1 * y2 - x2 * y1 > 0;
|
190
|
+
}
|
package/src/util.js
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
/**
|
2
|
+
* https://github.com/Turfjs/turf/blob/master/packages/turf-boolean-clockwise/index.ts
|
3
|
+
* @param {*} ring
|
4
|
+
* @returns
|
5
|
+
*/
|
6
|
+
export function isClockwise(ring) {
|
7
|
+
let sum = 0;
|
8
|
+
let i = 1;
|
9
|
+
let prev;
|
10
|
+
let cur;
|
11
|
+
const len = ring.length;
|
12
|
+
|
13
|
+
while (i < len) {
|
14
|
+
prev = cur || ring[0];
|
15
|
+
cur = ring[i];
|
16
|
+
sum += (cur[0] - prev[0]) * (cur[1] + prev[1]);
|
17
|
+
i++;
|
18
|
+
}
|
19
|
+
return sum > 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
function v3Sub(out, v1, v2) {
|
23
|
+
out[0] = v1[0] - v2[0];
|
24
|
+
out[1] = v1[1] - v2[1];
|
25
|
+
out[2] = v1[2] - v2[2];
|
26
|
+
return out;
|
27
|
+
}
|
28
|
+
|
29
|
+
function v3Normalize(out, v) {
|
30
|
+
const x = v[0];
|
31
|
+
const y = v[1];
|
32
|
+
const z = v[2];
|
33
|
+
const d = Math.sqrt(x * x + y * y + z * z) || 1;
|
34
|
+
out[0] = x / d;
|
35
|
+
out[1] = y / d;
|
36
|
+
out[2] = z / d;
|
37
|
+
return out;
|
38
|
+
}
|
39
|
+
|
40
|
+
function v3Cross(out, v1, v2) {
|
41
|
+
const ax = v1[0], ay = v1[1], az = v1[2],
|
42
|
+
bx = v2[0], by = v2[1], bz = v2[2];
|
43
|
+
|
44
|
+
out[0] = ay * bz - az * by;
|
45
|
+
out[1] = az * bx - ax * bz;
|
46
|
+
out[2] = ax * by - ay * bx;
|
47
|
+
return out;
|
48
|
+
}
|
49
|
+
|
50
|
+
export function generateNormal(indices, position) {
|
51
|
+
|
52
|
+
function v3Set(p, a, b, c) {
|
53
|
+
p[0] = a; p[1] = b; p[2] = c;
|
54
|
+
}
|
55
|
+
|
56
|
+
const p1 = [];
|
57
|
+
const p2 = [];
|
58
|
+
const p3 = [];
|
59
|
+
|
60
|
+
const v21 = [];
|
61
|
+
const v32 = [];
|
62
|
+
|
63
|
+
const n = [];
|
64
|
+
|
65
|
+
const len = indices.length;
|
66
|
+
const normals = new Float32Array(position.length);
|
67
|
+
|
68
|
+
for (let f = 0; f < len; f += 3) {
|
69
|
+
// const i1 = indices[f++] * 3;
|
70
|
+
// const i2 = indices[f++] * 3;
|
71
|
+
// const i3 = indices[f++] * 3;
|
72
|
+
// const i1 = indices[f];
|
73
|
+
// const i2 = indices[f + 1];
|
74
|
+
// const i3 = indices[f + 2];
|
75
|
+
const a = indices[f], b = indices[f + 1], c = indices[f + 2];
|
76
|
+
const i1 = a * 3, i2 = b * 3, i3 = c * 3;
|
77
|
+
|
78
|
+
v3Set(p1, position[i1], position[i1 + 1], position[i1 + 2]);
|
79
|
+
v3Set(p2, position[i2], position[i2 + 1], position[i2 + 2]);
|
80
|
+
v3Set(p3, position[i3], position[i3 + 1], position[i3 + 2]);
|
81
|
+
|
82
|
+
// pA.fromBufferAttribute(positionAttribute, vA);
|
83
|
+
// pB.fromBufferAttribute(positionAttribute, vB);
|
84
|
+
// pC.fromBufferAttribute(positionAttribute, vC);
|
85
|
+
|
86
|
+
// cb.subVectors(pC, pB);
|
87
|
+
// ab.subVectors(pA, pB);
|
88
|
+
// cb.cross(ab);
|
89
|
+
v3Sub(v32, p3, p2);
|
90
|
+
v3Sub(v21, p1, p2);
|
91
|
+
v3Cross(n, v32, v21);
|
92
|
+
// Already be weighted by the triangle area
|
93
|
+
for (let i = 0; i < 3; i++) {
|
94
|
+
normals[i1 + i] += n[i];
|
95
|
+
normals[i2 + i] += n[i];
|
96
|
+
normals[i3 + i] += n[i];
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
for (let i = 0; i < normals.length; i += 3) {
|
101
|
+
v3Set(n, normals[i], normals[i + 1], normals[i + 2]);
|
102
|
+
v3Normalize(n, n);
|
103
|
+
normals[i] = n[0] || 1;
|
104
|
+
normals[i + 1] = n[1] || 1;
|
105
|
+
normals[i + 2] = n[2] || 1;
|
106
|
+
|
107
|
+
}
|
108
|
+
|
109
|
+
return normals;
|
110
|
+
}
|
111
|
+
|
112
|
+
export function merge(results) {
|
113
|
+
if (results.length === 1) {
|
114
|
+
const result = {
|
115
|
+
position: results[0].position,
|
116
|
+
normal: results[0].normal,
|
117
|
+
uv: results[0].uv,
|
118
|
+
indices: results[0].indices,
|
119
|
+
results
|
120
|
+
};
|
121
|
+
return result;
|
122
|
+
}
|
123
|
+
let plen = 0, ilen = 0;
|
124
|
+
for (let i = 0, len = results.length; i < len; i++) {
|
125
|
+
const { position, indices } = results[i];
|
126
|
+
plen += position.length;
|
127
|
+
ilen += indices.length;
|
128
|
+
}
|
129
|
+
const result = {
|
130
|
+
position: new Float32Array(plen),
|
131
|
+
normal: new Float32Array(plen),
|
132
|
+
uv: new Float32Array(plen / 3 * 2),
|
133
|
+
indices: new Uint32Array(ilen),
|
134
|
+
results
|
135
|
+
};
|
136
|
+
let pOffset = 0, pCount = 0, iIdx = 0, uvOffset = 0;
|
137
|
+
for (let i = 0, len = results.length; i < len; i++) {
|
138
|
+
const { position, indices, normal, uv } = results[i];
|
139
|
+
result.position.set(position, pOffset);
|
140
|
+
result.normal.set(normal, pOffset);
|
141
|
+
result.uv.set(uv, uvOffset);
|
142
|
+
for (let j = 0, len1 = indices.length; j < len1; j++) {
|
143
|
+
const pIndex = indices[j] + pCount;
|
144
|
+
result.indices[iIdx] = pIndex;
|
145
|
+
iIdx++;
|
146
|
+
}
|
147
|
+
uvOffset += uv.length;
|
148
|
+
pOffset += position.length;
|
149
|
+
pCount += position.length / 3;
|
150
|
+
}
|
151
|
+
return result;
|
152
|
+
}
|
153
|
+
|
154
|
+
export function radToDeg(rad) {
|
155
|
+
return rad * 180 / Math.PI;
|
156
|
+
}
|
157
|
+
|
158
|
+
export function degToRad(angle) {
|
159
|
+
return angle / 180 * Math.PI;
|
160
|
+
}
|
161
|
+
|
162
|
+
// https://github.com/mrdoob/three.js/blob/16f13e3b07e31d0e9a00df7c3366bbe0e464588c/src/geometries/ExtrudeGeometry.js?_pjax=%23js-repo-pjax-container#L736
|
163
|
+
export function generateSideWallUV(uvs, vertices, indexA, indexB, indexC, indexD) {
|
164
|
+
|
165
|
+
const a_x = vertices[indexA * 3];
|
166
|
+
const a_y = vertices[indexA * 3 + 1];
|
167
|
+
const a_z = vertices[indexA * 3 + 2];
|
168
|
+
const b_x = vertices[indexB * 3];
|
169
|
+
const b_y = vertices[indexB * 3 + 1];
|
170
|
+
const b_z = vertices[indexB * 3 + 2];
|
171
|
+
const c_x = vertices[indexC * 3];
|
172
|
+
const c_y = vertices[indexC * 3 + 1];
|
173
|
+
const c_z = vertices[indexC * 3 + 2];
|
174
|
+
const d_x = vertices[indexD * 3];
|
175
|
+
const d_y = vertices[indexD * 3 + 1];
|
176
|
+
const d_z = vertices[indexD * 3 + 2];
|
177
|
+
|
178
|
+
if (Math.abs(a_y - b_y) < Math.abs(a_x - b_x)) {
|
179
|
+
|
180
|
+
uvs.push(a_x, 1 - a_z);
|
181
|
+
uvs.push(b_x, 1 - b_z);
|
182
|
+
uvs.push(c_x, 1 - c_z);
|
183
|
+
uvs.push(d_x, 1 - d_z);
|
184
|
+
// return [
|
185
|
+
// new Vector2(a_x, 1 - a_z),
|
186
|
+
// new Vector2(b_x, 1 - b_z),
|
187
|
+
// new Vector2(c_x, 1 - c_z),
|
188
|
+
// new Vector2(d_x, 1 - d_z)
|
189
|
+
// ];
|
190
|
+
|
191
|
+
} else {
|
192
|
+
uvs.push(a_y, 1 - a_z);
|
193
|
+
uvs.push(b_y, 1 - b_z);
|
194
|
+
uvs.push(c_y, 1 - c_z);
|
195
|
+
uvs.push(d_y, 1 - d_z);
|
196
|
+
// return [
|
197
|
+
// new Vector2(a_y, 1 - a_z),
|
198
|
+
// new Vector2(b_y, 1 - b_z),
|
199
|
+
// new Vector2(c_y, 1 - c_z),
|
200
|
+
// new Vector2(d_y, 1 - d_z)
|
201
|
+
// ];
|
202
|
+
|
203
|
+
}
|
204
|
+
|
205
|
+
}
|