poly-extrude 0.15.0 → 0.17.0
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/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/poly-extrude.js +4367 -4081
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +543 -259
- package/dist/poly-extrude.mjs.map +1 -1
- package/dist/polygon.d.ts +2 -0
- package/dist/polygon.js +56 -40
- package/dist/polygon.js.map +1 -1
- package/dist/polygonpath.d.ts +11 -0
- package/dist/polygonpath.js +262 -0
- package/dist/polygonpath.js.map +1 -0
- package/dist/util.d.ts +7 -1
- package/dist/util.js +63 -0
- package/dist/util.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +3 -1
- package/src/index.ts +5 -2
- package/src/polygon.ts +65 -40
- package/src/polygonpath.ts +315 -0
- package/src/util.ts +68 -1
package/readme.md
CHANGED
@@ -21,6 +21,8 @@ Extrude polygons/polylines. Born in [maptalks.three](https://github.com/maptalks
|
|
21
21
|
[](https://deyihu.github.io/poly-extrude/test/tube.html)<br>
|
22
22
|
[](https://deyihu.github.io/poly-extrude/test/terrain.html)<br>
|
23
23
|
|
24
|
+
[shape demo ](https://deyihu.github.io/poly-extrude/test/shape.html)<br>
|
25
|
+
|
24
26
|
## Install
|
25
27
|
|
26
28
|
### NPM
|
@@ -111,6 +113,7 @@ npm i poly-extrude
|
|
111
113
|
|
112
114
|
* `polygons`
|
113
115
|
* `options.depth`
|
116
|
+
* `options.top` Whether to display the top
|
114
117
|
|
115
118
|
```js
|
116
119
|
const result = extrudePolygons(polygons, {
|
@@ -216,7 +219,6 @@ const {
|
|
216
219
|
* `options.bottomStickGround` Is the bottom attached to the ground
|
217
220
|
* `options.pathUV` generate Path UV
|
218
221
|
|
219
|
-
|
220
222
|
[extrudeSlopes pathUV demo](https://deyihu.github.io/poly-extrude/test/slope-pathuv.html)
|
221
223
|
|
222
224
|
```js
|
package/src/index.ts
CHANGED
@@ -1,13 +1,16 @@
|
|
1
|
-
import { extrudePolygons } from './polygon';
|
1
|
+
import { extrudePolygons, polygons } from './polygon';
|
2
2
|
import { extrudePolylines, expandLine, leftOnLine, extrudeSlopes } from './polyline';
|
3
3
|
import { cylinder } from './cylinder';
|
4
4
|
import { expandPaths } from './path';
|
5
5
|
import { expandTubes } from './tube';
|
6
6
|
import { plane } from './plane';
|
7
|
+
import { extrudePolygonsOnPath } from './polygonpath';
|
7
8
|
import { isClockwise, merge } from './util';
|
8
9
|
export {
|
9
10
|
isClockwise, merge,
|
10
11
|
extrudePolygons, extrudePolylines,
|
11
12
|
extrudeSlopes, expandLine, leftOnLine,
|
12
|
-
cylinder, expandPaths, expandTubes, plane
|
13
|
+
cylinder, expandPaths, expandTubes, plane,
|
14
|
+
extrudePolygonsOnPath,
|
15
|
+
polygons
|
13
16
|
};
|
package/src/polygon.ts
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
|
2
2
|
import earcut from 'earcut';
|
3
|
-
import { generateNormal, generateSideWallUV, isClockwise, merge } from './util';
|
3
|
+
import { generateNormal, generateSideWallUV, isClockwise, merge, isClosedRing, validateRing, calPolygonPointsCount, validatePolygon } from './util';
|
4
4
|
import { PolylineType, PolygonType, ResultType } from './type';
|
5
5
|
|
6
6
|
type PolygonsOptions = {
|
7
|
-
depth?: number
|
7
|
+
depth?: number,
|
8
|
+
top?: boolean
|
8
9
|
}
|
9
10
|
|
10
11
|
type PolygonsResult = ResultType & {
|
@@ -13,26 +14,13 @@ type PolygonsResult = ResultType & {
|
|
13
14
|
|
14
15
|
|
15
16
|
export function extrudePolygons(polygons: Array<PolygonType>, options?: PolygonsOptions): PolygonsResult {
|
16
|
-
options = Object.assign({}, { depth: 2 }, options);
|
17
|
+
options = Object.assign({}, { depth: 2, top: true }, options);
|
17
18
|
const results = polygons.map(polygon => {
|
18
|
-
|
19
|
-
const ring = polygon[i];
|
20
|
-
validateRing(ring);
|
21
|
-
if (i === 0) {
|
22
|
-
if (!isClockwise(ring)) {
|
23
|
-
polygon[i] = ring.reverse();
|
24
|
-
}
|
25
|
-
} else if (isClockwise(ring)) {
|
26
|
-
polygon[i] = ring.reverse();
|
27
|
-
}
|
28
|
-
if (isClosedRing(ring)) {
|
29
|
-
ring.splice(ring.length - 1, 1);
|
30
|
-
}
|
31
|
-
}
|
19
|
+
validatePolygon(polygon);
|
32
20
|
const result = flatVertices(polygon, options) as Record<string, any>;
|
33
21
|
result.polygon = polygon;
|
34
22
|
const triangles = earcut(result.flatVertices, result.holes, 2);
|
35
|
-
generateTopAndBottom(result, triangles);
|
23
|
+
generateTopAndBottom(result, triangles, options);
|
36
24
|
generateSides(result, options);
|
37
25
|
result.position = new Float32Array(result.points);
|
38
26
|
result.indices = new Uint32Array(result.indices);
|
@@ -46,18 +34,24 @@ export function extrudePolygons(polygons: Array<PolygonType>, options?: Polygons
|
|
46
34
|
|
47
35
|
}
|
48
36
|
|
49
|
-
function generateTopAndBottom(result, triangles) {
|
37
|
+
function generateTopAndBottom(result, triangles, options: PolygonsOptions) {
|
50
38
|
const indices: number[] = [];
|
51
39
|
const { count } = result;
|
40
|
+
const top = options.top;
|
52
41
|
for (let i = 0, len = triangles.length; i < len; i += 3) {
|
53
42
|
// top
|
54
43
|
const a = triangles[i], b = triangles[i + 1], c = triangles[i + 2];
|
55
|
-
|
56
|
-
|
57
|
-
|
44
|
+
if (top) {
|
45
|
+
indices[i] = a;
|
46
|
+
indices[i + 1] = b;
|
47
|
+
indices[i + 2] = c;
|
48
|
+
}
|
58
49
|
// bottom
|
59
|
-
|
50
|
+
let idx = len + i;
|
60
51
|
const a1 = count + a, b1 = count + b, c1 = count + c;
|
52
|
+
if (!top) {
|
53
|
+
idx = i;
|
54
|
+
}
|
61
55
|
indices[idx] = a1;
|
62
56
|
indices[idx + 1] = b1;
|
63
57
|
indices[idx + 2] = c1;
|
@@ -112,16 +106,6 @@ function generateSides(result, options) {
|
|
112
106
|
}
|
113
107
|
}
|
114
108
|
|
115
|
-
function calPolygonPointsCount(polygon) {
|
116
|
-
let count = 0;
|
117
|
-
let i = 0;
|
118
|
-
const len = polygon.length;
|
119
|
-
while (i < len) {
|
120
|
-
count += (polygon[i].length);
|
121
|
-
i++;
|
122
|
-
}
|
123
|
-
return count;
|
124
|
-
}
|
125
109
|
|
126
110
|
function flatVertices(polygon, options) {
|
127
111
|
const count = calPolygonPointsCount(polygon);
|
@@ -176,14 +160,55 @@ function flatVertices(polygon, options) {
|
|
176
160
|
|
177
161
|
}
|
178
162
|
|
179
|
-
|
180
|
-
|
181
|
-
|
163
|
+
|
164
|
+
function simplePolygon(polygon, options = {}) {
|
165
|
+
const flatVertices = [], holes = [];
|
166
|
+
let pIndex = -1, aIndex = -1, uvIndex = -1;
|
167
|
+
const points = [], uv = [];
|
168
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
169
|
+
const ring = polygon[i];
|
170
|
+
if (i > 0) {
|
171
|
+
holes.push(flatVertices.length / 2);
|
172
|
+
}
|
173
|
+
for (let j = 0, len1 = ring.length; j < len1; j++) {
|
174
|
+
const c = ring[j];
|
175
|
+
flatVertices[++pIndex] = c[0];
|
176
|
+
flatVertices[++pIndex] = c[1];
|
177
|
+
|
178
|
+
points[++aIndex] = c[0];
|
179
|
+
points[++aIndex] = c[1];
|
180
|
+
points[++aIndex] = c[2] || 0;
|
181
|
+
|
182
|
+
uv[++uvIndex] = c[0];
|
183
|
+
uv[++uvIndex] = c[1];
|
184
|
+
}
|
185
|
+
}
|
186
|
+
const triangles = earcut(flatVertices, holes, 2);
|
187
|
+
const normal = generateNormal(triangles, points);
|
188
|
+
return {
|
189
|
+
normal,
|
190
|
+
uv,
|
191
|
+
points,
|
192
|
+
indices: triangles
|
182
193
|
}
|
183
194
|
}
|
184
195
|
|
185
|
-
function
|
186
|
-
const
|
187
|
-
|
188
|
-
|
196
|
+
export function polygons(polygons, options = {}): PolygonsResult {
|
197
|
+
const results = polygons.map(polygon => {
|
198
|
+
validatePolygon(polygon);
|
199
|
+
|
200
|
+
const result = simplePolygon(polygon, options) as Record<string, any>;
|
201
|
+
result.polygon = polygon;
|
202
|
+
result.position = new Float32Array(result.points);
|
203
|
+
result.indices = new Uint32Array(result.indices);
|
204
|
+
result.uv = new Float32Array(result.uv);
|
205
|
+
result.normal = new Float32Array(result.normal);
|
206
|
+
return result;
|
207
|
+
});
|
208
|
+
const result = merge(results as Array<ResultType>) as PolygonsResult;
|
209
|
+
result.polygons = polygons;
|
210
|
+
return result;
|
211
|
+
|
212
|
+
|
213
|
+
|
189
214
|
}
|
@@ -0,0 +1,315 @@
|
|
1
|
+
import { Vector3 } from './math/Vector3';
|
2
|
+
import { PathPoint } from './path/PathPoint';
|
3
|
+
import { PathPointList } from './path/PathPointList';
|
4
|
+
import { PolygonType, PolylineType, ResultType } from './type';
|
5
|
+
import { generateNormal, isClockwise, line2Vectors, merge, validateRing, isClosedRing, calPolygonPointsCount, getPolygonsBBOX, mergeArray } from './util';
|
6
|
+
import earcut from 'earcut';
|
7
|
+
const UP = new Vector3(0, 0, 1);
|
8
|
+
const normalDir = new Vector3();
|
9
|
+
|
10
|
+
type PolygonsOnPathOptions = {
|
11
|
+
extrudePath: PolylineType;
|
12
|
+
openEnd?: boolean;
|
13
|
+
openEndUV?: boolean;
|
14
|
+
|
15
|
+
}
|
16
|
+
|
17
|
+
type PolygonsOnPathResult = ResultType & {
|
18
|
+
polygons: Array<PolygonType>;
|
19
|
+
}
|
20
|
+
|
21
|
+
|
22
|
+
type Point = [number, number];
|
23
|
+
|
24
|
+
export function extrudePolygonsOnPath(polygons: Array<PolygonType>, options?: PolygonsOnPathOptions) {
|
25
|
+
options = Object.assign({}, { openEnd: false, openEndUV: true }, options);
|
26
|
+
const { extrudePath, openEnd } = options;
|
27
|
+
if (!extrudePath || !Array.isArray(extrudePath) || extrudePath.length < 2) {
|
28
|
+
console.error('extrudePath is error:', extrudePath);
|
29
|
+
return null;
|
30
|
+
}
|
31
|
+
const bbox = getPolygonsBBOX(polygons);
|
32
|
+
const [minx, miny, maxx, maxy] = bbox;
|
33
|
+
const center = [(minx + maxx) / 2, (miny + maxy) / 2] as Point;
|
34
|
+
|
35
|
+
const points = line2Vectors(extrudePath);
|
36
|
+
const pathPointList = new PathPointList();
|
37
|
+
//@ts-ignore
|
38
|
+
pathPointList.set(points, 0, options.cornerSplit, UP);
|
39
|
+
|
40
|
+
const results = polygons.map(polygon => {
|
41
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
42
|
+
const ring = polygon[i];
|
43
|
+
validateRing(ring);
|
44
|
+
if (i === 0) {
|
45
|
+
if (isClockwise(ring)) {
|
46
|
+
polygon[i] = ring.reverse();
|
47
|
+
}
|
48
|
+
} else if (!isClockwise(ring)) {
|
49
|
+
polygon[i] = ring.reverse();
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
const result = generatePolygonOnPathVertexData(pathPointList, polygon, center) as Record<string, any>;
|
54
|
+
if (!openEnd) {
|
55
|
+
generateStartAndEnd(result, polygon, options);
|
56
|
+
}
|
57
|
+
result.polygon = polygon;
|
58
|
+
result.position = new Float32Array(result.points);
|
59
|
+
result.indices = new Uint32Array(result.indices);
|
60
|
+
result.uv = new Float32Array(result.uv);
|
61
|
+
result.normal = new Float32Array(result.normal);
|
62
|
+
return result;
|
63
|
+
});
|
64
|
+
const result = merge(results as Array<ResultType>) as PolygonsOnPathResult;
|
65
|
+
result.polygons = polygons;
|
66
|
+
return result;
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
function getAngle(c1: Point, c2: Point) {
|
71
|
+
const [x1, y1] = c1;
|
72
|
+
const [x2, y2] = c2;
|
73
|
+
const dy = y2 - y1;
|
74
|
+
const dx = x2 - x1;
|
75
|
+
return Math.atan2(dy, dx);
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
function transformPolygon(polygon: PolygonType, center: Point) {
|
80
|
+
const [cx, cy] = center;
|
81
|
+
const list = [];
|
82
|
+
polygon.forEach((ring, rIndex) => {
|
83
|
+
const data = [];
|
84
|
+
let totalDistance = 0;
|
85
|
+
let tempPoint;
|
86
|
+
for (let i = 0, len = ring.length; i < len; i++) {
|
87
|
+
const p = ring[i];
|
88
|
+
const x1 = p[0], y1 = p[1];
|
89
|
+
const offsetx = x1 - cx, offsety = y1 - cy;
|
90
|
+
let distance = 0;
|
91
|
+
if (i > 0) {
|
92
|
+
const x2 = tempPoint[0], y2 = tempPoint[1];
|
93
|
+
const dx = x2 - x1, dy = y2 - y1;
|
94
|
+
distance = Math.sqrt(dx * dx + dy * dy) + totalDistance;
|
95
|
+
totalDistance = distance;
|
96
|
+
}
|
97
|
+
data[i] = {
|
98
|
+
// dx,
|
99
|
+
// dy,
|
100
|
+
// dz: 0,
|
101
|
+
distance,
|
102
|
+
radius: Math.sqrt(offsetx * offsetx + offsety * offsety),
|
103
|
+
angle: getAngle(center, p as Point)
|
104
|
+
}
|
105
|
+
tempPoint = p;
|
106
|
+
}
|
107
|
+
list[rIndex] = {
|
108
|
+
ring: data,
|
109
|
+
ringLen: totalDistance
|
110
|
+
};
|
111
|
+
});
|
112
|
+
return list;
|
113
|
+
}
|
114
|
+
|
115
|
+
const TEMP_VECTOR3 = new Vector3(0, 0, 0);
|
116
|
+
// Vertex Data Generate Functions
|
117
|
+
// code copy from https://github.com/shawn0326/three.path/blob/master/src/PathGeometry.js
|
118
|
+
function generatePolygonOnPathVertexData(pathPointList, polygon: PolygonType, center: Point) {
|
119
|
+
const tpolygon = transformPolygon(polygon, center);
|
120
|
+
// let count = 0;
|
121
|
+
// modify data
|
122
|
+
const points: number[] = [];
|
123
|
+
const normal: number[] = [];
|
124
|
+
const uv: number[] = [];
|
125
|
+
// const uv2 = [];
|
126
|
+
const indices: number[] = [];
|
127
|
+
let verticesCount = 0;
|
128
|
+
|
129
|
+
let pIndex = -1;
|
130
|
+
let nIndex = -1;
|
131
|
+
let uIndex = -1;
|
132
|
+
let iIndex = -1;
|
133
|
+
|
134
|
+
const startPoints = [], endPoints = [];
|
135
|
+
|
136
|
+
function addVertices(pathPoint, ring, ringLen, first, end) {
|
137
|
+
const uvDist = pathPoint.dist / ringLen;
|
138
|
+
const radialSegments = ring.length;
|
139
|
+
// const startRad = ring[0].angle;
|
140
|
+
|
141
|
+
for (let i = 0; i < radialSegments; i++) {
|
142
|
+
const item = ring[i];
|
143
|
+
if (!item) {
|
144
|
+
continue;
|
145
|
+
}
|
146
|
+
const isLast = i === radialSegments - 1;
|
147
|
+
const angle = item.angle;
|
148
|
+
const radius = item.radius;
|
149
|
+
const distance = item.distance;
|
150
|
+
normalDir.copy(pathPoint.up).applyAxisAngle(pathPoint.dir, angle).normalize();
|
151
|
+
const v = TEMP_VECTOR3.copy(pathPoint.up);
|
152
|
+
v.applyAxisAngle(pathPoint.dir, angle);
|
153
|
+
v.x *= radius;
|
154
|
+
v.y *= radius;
|
155
|
+
v.z *= radius;
|
156
|
+
|
157
|
+
points[++pIndex] = pathPoint.pos.x + v.x;
|
158
|
+
points[++pIndex] = pathPoint.pos.y + v.y;
|
159
|
+
points[++pIndex] = pathPoint.pos.z + v.z;
|
160
|
+
|
161
|
+
// if (i === 0 || i === radialSegments - 1) {
|
162
|
+
// console.log(i, radialSegments, v.x, v.y, v.z);
|
163
|
+
// }
|
164
|
+
|
165
|
+
|
166
|
+
normal[++nIndex] = normalDir.x;
|
167
|
+
normal[++nIndex] = normalDir.y;
|
168
|
+
normal[++nIndex] = normalDir.z;
|
169
|
+
|
170
|
+
uv[++uIndex] = uvDist;
|
171
|
+
uv[++uIndex] = distance / ringLen;
|
172
|
+
|
173
|
+
verticesCount++;
|
174
|
+
|
175
|
+
if (first && !isLast) {
|
176
|
+
let index = startPoints.length - 1;
|
177
|
+
startPoints[++index] = pathPoint.pos.x + v.x;
|
178
|
+
startPoints[++index] = pathPoint.pos.y + v.y;
|
179
|
+
startPoints[++index] = pathPoint.pos.z + v.z;
|
180
|
+
}
|
181
|
+
if (end && !isLast) {
|
182
|
+
let index = endPoints.length - 1;
|
183
|
+
endPoints[++index] = pathPoint.pos.x + v.x;
|
184
|
+
endPoints[++index] = pathPoint.pos.y + v.y;
|
185
|
+
endPoints[++index] = pathPoint.pos.z + v.z;
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
if (!first) {
|
190
|
+
const begin1 = verticesCount - (radialSegments) * 2;
|
191
|
+
const begin2 = verticesCount - (radialSegments);
|
192
|
+
|
193
|
+
for (let i = 0; i < radialSegments; i++) {
|
194
|
+
indices[++iIndex] = begin2 + i;
|
195
|
+
indices[++iIndex] = begin1 + i;
|
196
|
+
indices[++iIndex] = begin1 + i + 1;
|
197
|
+
indices[++iIndex] = begin2 + i;
|
198
|
+
indices[++iIndex] = begin1 + i + 1;
|
199
|
+
indices[++iIndex] = begin2 + i + 1;
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
const polygonLen = tpolygon[0].ringLen;
|
205
|
+
tpolygon.forEach(item => {
|
206
|
+
for (let i = 0; i < pathPointList.count; i++) {
|
207
|
+
const pathPoint = pathPointList.array[i];
|
208
|
+
const { ring, ringLen } = item;
|
209
|
+
addVertices(pathPoint, ring, ringLen, i === 0, i === pathPointList.count - 1);
|
210
|
+
|
211
|
+
}
|
212
|
+
});
|
213
|
+
|
214
|
+
|
215
|
+
return {
|
216
|
+
points,
|
217
|
+
normal,
|
218
|
+
uv,
|
219
|
+
// uv2,
|
220
|
+
indices,
|
221
|
+
startPoints,
|
222
|
+
endPoints,
|
223
|
+
polygonLen
|
224
|
+
// count
|
225
|
+
};
|
226
|
+
}
|
227
|
+
|
228
|
+
|
229
|
+
function generateStartAndEnd(result, polygon, options) {
|
230
|
+
const { openEndUV } = options;
|
231
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
232
|
+
const ring = polygon[i];
|
233
|
+
if (isClosedRing(ring)) {
|
234
|
+
ring.splice(ring.length - 1, 1);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
const pointCount = calPolygonPointsCount(polygon);
|
238
|
+
|
239
|
+
const flatVertices = [], holes = [];
|
240
|
+
let pIndex = -1;
|
241
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
242
|
+
const ring = polygon[i];
|
243
|
+
if (i > 0) {
|
244
|
+
holes.push(flatVertices.length / 2);
|
245
|
+
}
|
246
|
+
for (let j = 0, len1 = ring.length; j < len1; j++) {
|
247
|
+
const c = ring[j];
|
248
|
+
flatVertices[++pIndex] = c[0];
|
249
|
+
flatVertices[++pIndex] = c[1];
|
250
|
+
}
|
251
|
+
}
|
252
|
+
const triangles = earcut(flatVertices, holes, 2);
|
253
|
+
const { points, normal, uv, indices, startPoints, endPoints, polygonLen } = result;
|
254
|
+
|
255
|
+
pIndex = 0;
|
256
|
+
let uIndex = 0;
|
257
|
+
const aPoints1 = [], auv1 = [], aPoints2 = [], auv2 = [];
|
258
|
+
|
259
|
+
|
260
|
+
for (let i = 0; i < pointCount; i++) {
|
261
|
+
const idx = i * 3;
|
262
|
+
const x = startPoints[idx];
|
263
|
+
const y = startPoints[idx + 1];
|
264
|
+
const z = startPoints[idx + 2];
|
265
|
+
|
266
|
+
aPoints1[pIndex] = x;
|
267
|
+
aPoints1[pIndex + 1] = y;
|
268
|
+
aPoints1[pIndex + 2] = z;
|
269
|
+
if (openEndUV) {
|
270
|
+
auv1[uIndex] = y / polygonLen;
|
271
|
+
auv1[uIndex + 1] = z / polygonLen;
|
272
|
+
} else {
|
273
|
+
auv1[uIndex] = 0;
|
274
|
+
auv1[uIndex + 1] = 0;
|
275
|
+
}
|
276
|
+
|
277
|
+
const x1 = endPoints[idx];
|
278
|
+
const y1 = endPoints[idx + 1];
|
279
|
+
const z1 = endPoints[idx + 2];
|
280
|
+
|
281
|
+
aPoints2[pIndex] = x1;
|
282
|
+
aPoints2[pIndex + 1] = y1;
|
283
|
+
aPoints2[pIndex + 2] = z1;
|
284
|
+
if (openEndUV) {
|
285
|
+
auv2[uIndex] = y1 / polygonLen;
|
286
|
+
auv2[uIndex + 1] = z1 / polygonLen;
|
287
|
+
} else {
|
288
|
+
auv2[uIndex] = 0;
|
289
|
+
auv2[uIndex + 1] = 0;
|
290
|
+
}
|
291
|
+
|
292
|
+
pIndex += 3;
|
293
|
+
uIndex += 2;
|
294
|
+
|
295
|
+
}
|
296
|
+
|
297
|
+
const indexOffset = points.length / 3;
|
298
|
+
const indexs = [];
|
299
|
+
for (let i = 0, len = triangles.length; i < len; i++) {
|
300
|
+
indexs[i] = triangles[i] + indexOffset;
|
301
|
+
indexs[i + len] = triangles[i] + indexOffset + pointCount;
|
302
|
+
}
|
303
|
+
|
304
|
+
const anormal1 = generateNormal(triangles, aPoints1) as any;
|
305
|
+
const anormal2 = generateNormal(triangles, aPoints2) as any;
|
306
|
+
mergeArray(points, aPoints1);
|
307
|
+
mergeArray(points, aPoints2);
|
308
|
+
mergeArray(uv, auv1);
|
309
|
+
mergeArray(uv, auv2);
|
310
|
+
mergeArray(normal, anormal1);
|
311
|
+
mergeArray(normal, anormal2);
|
312
|
+
mergeArray(indices, indexs);
|
313
|
+
}
|
314
|
+
|
315
|
+
|
package/src/util.ts
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
import { Vector3 } from './math/Vector3';
|
2
|
-
import { PolylineType, ResultType } from './type';
|
2
|
+
import { PolygonType, PolylineType, ResultType } from './type';
|
3
3
|
|
4
|
+
export function mergeArray(array1, array2) {
|
5
|
+
let index = array1.length - 1;
|
6
|
+
for (let i = 0, len = array2.length; i < len; i++) {
|
7
|
+
array1[++index] = array2[i];
|
8
|
+
}
|
9
|
+
}
|
4
10
|
/**
|
5
11
|
* https://github.com/Turfjs/turf/blob/master/packages/turf-boolean-clockwise/index.ts
|
6
12
|
* @param {*} ring
|
@@ -22,6 +28,67 @@ export function isClockwise(ring: PolylineType) {
|
|
22
28
|
return sum > 0;
|
23
29
|
}
|
24
30
|
|
31
|
+
|
32
|
+
export function validateRing(ring: PolylineType) {
|
33
|
+
if (!isClosedRing(ring)) {
|
34
|
+
ring.push(ring[0]);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
export function isClosedRing(ring: PolylineType) {
|
39
|
+
const len = ring.length;
|
40
|
+
const [x1, y1] = ring[0], [x2, y2] = ring[len - 1];
|
41
|
+
return (x1 === x2 && y1 === y2);
|
42
|
+
}
|
43
|
+
|
44
|
+
export function calPolygonPointsCount(polygon: PolygonType) {
|
45
|
+
let count = 0;
|
46
|
+
let i = 0;
|
47
|
+
const len = polygon.length;
|
48
|
+
while (i < len) {
|
49
|
+
count += (polygon[i].length);
|
50
|
+
i++;
|
51
|
+
}
|
52
|
+
return count;
|
53
|
+
}
|
54
|
+
|
55
|
+
export function getPolygonsBBOX(polygons, bbox?) {
|
56
|
+
bbox = bbox || [Infinity, Infinity, -Infinity, -Infinity];
|
57
|
+
for (let i = 0, len = polygons.length; i < len; i++) {
|
58
|
+
const p = polygons[i];
|
59
|
+
if (Array.isArray(p[0][0])) {
|
60
|
+
getPolygonsBBOX(p, bbox);
|
61
|
+
} else {
|
62
|
+
for (let j = 0, len1 = p.length; j < len1; j++) {
|
63
|
+
const c = p[j];
|
64
|
+
const [x, y] = c;
|
65
|
+
bbox[0] = Math.min(bbox[0], x);
|
66
|
+
bbox[1] = Math.min(bbox[1], y);
|
67
|
+
bbox[2] = Math.max(bbox[2], x);
|
68
|
+
bbox[3] = Math.max(bbox[3], y);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
return bbox;
|
73
|
+
}
|
74
|
+
|
75
|
+
export function validatePolygon(polygon: PolygonType) {
|
76
|
+
for (let i = 0, len = polygon.length; i < len; i++) {
|
77
|
+
const ring = polygon[i];
|
78
|
+
validateRing(ring);
|
79
|
+
if (i === 0) {
|
80
|
+
if (!isClockwise(ring)) {
|
81
|
+
polygon[i] = ring.reverse();
|
82
|
+
}
|
83
|
+
} else if (isClockwise(ring)) {
|
84
|
+
polygon[i] = ring.reverse();
|
85
|
+
}
|
86
|
+
if (isClosedRing(ring)) {
|
87
|
+
ring.splice(ring.length - 1, 1);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
25
92
|
function v3Sub(out, v1, v2) {
|
26
93
|
out[0] = v1[0] - v2[0];
|
27
94
|
out[1] = v1[1] - v2[1];
|