vislite 0.8.0 → 0.8.1-alpha.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/CHANGELOG +212 -209
- package/README.md +136 -144
- package/lib/Buffer/index.umd.js +36 -36
- package/lib/Buffer/index.umd.min.js +2 -2
- package/lib/Canvas/index.umd.js +691 -691
- package/lib/Canvas/index.umd.min.js +2 -2
- package/lib/Cardinal/index.umd.js +91 -91
- package/lib/Cardinal/index.umd.min.js +2 -2
- package/lib/Eoap/index.umd.js +34 -34
- package/lib/Eoap/index.umd.min.js +2 -2
- package/lib/Geometry/index.umd.js +286 -286
- package/lib/Geometry/index.umd.min.js +2 -2
- package/lib/Hermite/index.umd.js +36 -36
- package/lib/Hermite/index.umd.min.js +2 -2
- package/lib/Matrix4/index.umd.js +125 -125
- package/lib/Matrix4/index.umd.min.js +2 -2
- package/lib/Mercator/index.umd.js +20 -20
- package/lib/Mercator/index.umd.min.js +2 -2
- package/lib/OralCanvas/index.es.js +634 -634
- package/lib/OralCanvas/index.es.min.js +2 -2
- package/lib/OralWebGL/index.es.js +552 -552
- package/lib/OralWebGL/index.es.min.js +2 -2
- package/lib/SVG/index.umd.js +471 -471
- package/lib/SVG/index.umd.min.js +2 -2
- package/lib/Shader/index.umd.js +61 -61
- package/lib/Shader/index.umd.min.js +2 -2
- package/lib/Texture/index.umd.js +54 -54
- package/lib/Texture/index.umd.min.js +2 -2
- package/lib/TreeLayout/index.umd.js +368 -368
- package/lib/TreeLayout/index.umd.min.js +2 -2
- package/lib/WebGL/index.umd.js +599 -599
- package/lib/WebGL/index.umd.min.js +2 -2
- package/lib/animation/index.umd.js +73 -73
- package/lib/animation/index.umd.min.js +2 -2
- package/lib/formatColor/index.umd.js +40 -40
- package/lib/formatColor/index.umd.min.js +2 -2
- package/lib/getLoopColors/index.umd.js +36 -36
- package/lib/getLoopColors/index.umd.min.js +2 -2
- package/lib/getWebGLContext/index.umd.js +63 -63
- package/lib/getWebGLContext/index.umd.min.js +2 -2
- package/lib/index.umd.js +2955 -2955
- package/lib/index.umd.min.js +2 -2
- package/lib/move/index.umd.js +8 -8
- package/lib/move/index.umd.min.js +2 -2
- package/lib/resizeObserver/index.umd.js +30 -30
- package/lib/resizeObserver/index.umd.min.js +2 -2
- package/lib/rotate/index.umd.js +8 -8
- package/lib/rotate/index.umd.min.js +2 -2
- package/lib/ruler/index.umd.js +138 -138
- package/lib/ruler/index.umd.min.js +2 -2
- package/lib/scale/index.umd.js +7 -7
- package/lib/scale/index.umd.min.js +2 -2
- package/lib/throttle/index.umd.js +49 -49
- package/lib/throttle/index.umd.min.js +2 -2
- package/lib/viewHandler/index.umd.js +120 -120
- package/lib/viewHandler/index.umd.min.js +2 -2
- package/miniprogram/ui-canvas/drawImage.js +34 -0
- package/miniprogram/ui-canvas/index.js +10 -2
- package/package/getWebGLContext/index.ts +40 -40
- package/package.json +70 -70
- package/src/Canvas.ts +72 -72
- package/src/Geometry.ts +210 -210
- package/src/WebGL.ts +66 -66
- package/src/common/canvas/index.ts +183 -183
- package/src/common/canvas/painter.ts +446 -446
- package/src/common/geometry/prism-horizontal.ts +50 -50
- package/src/common/geometry/prism-vertical.ts +55 -55
- package/src/common/geometry/tool/circle.ts +17 -17
- package/src/common/geometry/tool/rotateLine.ts +48 -48
- package/src/common/geometry/tool/triangles.ts +23 -23
- package/src/common/webgl/getWebGLContext.ts +45 -45
- package/src/common/webgl/index.ts +227 -227
- package/types/Canvas.d.ts +318 -318
- package/types/Geometry.d.ts +132 -132
- package/types/WebGLOption.d.ts +14 -14
- package/types/getWebGLContext.d.ts +4 -4
- package/types/ui-canvas.d.ts +4 -4
- package/uni-app/drawImage.js +17 -17
- package/uni-app/ui-canvas.vue +290 -290
package/src/Canvas.ts
CHANGED
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import type CanvasType from '../types/Canvas'
|
|
2
|
-
import type CanvasOptionType from '../types/CanvasOption'
|
|
3
|
-
|
|
4
|
-
import OralCanvas from './common/canvas/index'
|
|
5
|
-
import mergeOption from './common/mergeOption'
|
|
6
|
-
|
|
7
|
-
class Canvas extends OralCanvas implements CanvasType {
|
|
8
|
-
private __canvas: HTMLCanvasElement
|
|
9
|
-
constructor(el: HTMLElement | null, option: CanvasOptionType = {}) {
|
|
10
|
-
if (!el) {
|
|
11
|
-
throw new Error("VISLite Canvas:The mount point requires an HTMLElement type but encountered null.")
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
option = mergeOption(option, {
|
|
15
|
-
region: true,
|
|
16
|
-
willReadFrequently: false
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const width = el.clientWidth, height = el.clientHeight
|
|
20
|
-
|
|
21
|
-
let ViewCanvas: HTMLCanvasElement, RegionCanvas: HTMLCanvasElement | null = null
|
|
22
|
-
|
|
23
|
-
const _el = el as any
|
|
24
|
-
|
|
25
|
-
// 如果已经初始化过了
|
|
26
|
-
if (_el._vislite_canvas_) {
|
|
27
|
-
ViewCanvas = _el._vislite_canvas_[0]
|
|
28
|
-
RegionCanvas = _el._vislite_canvas_[1]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 否则就初始化
|
|
32
|
-
else {
|
|
33
|
-
ViewCanvas = document.createElement('canvas')
|
|
34
|
-
el.appendChild(ViewCanvas)
|
|
35
|
-
|
|
36
|
-
if (option.region) {
|
|
37
|
-
RegionCanvas = document.createElement('canvas')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
_el._vislite_canvas_ = [ViewCanvas, RegionCanvas]
|
|
41
|
-
|
|
42
|
-
el.setAttribute('vislite', 'Canvas')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 设置画布大小
|
|
46
|
-
const canvasArray = [RegionCanvas, ViewCanvas]
|
|
47
|
-
for (let index = 0; index < canvasArray.length; index++) {
|
|
48
|
-
const canvas = canvasArray[index]
|
|
49
|
-
if (canvas) {
|
|
50
|
-
canvas.style.width = width + "px"
|
|
51
|
-
canvas.setAttribute('width', (index * width + width) + "")
|
|
52
|
-
|
|
53
|
-
canvas.style.height = height + "px"
|
|
54
|
-
canvas.setAttribute('height', (index * height + height) + "")
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
super(ViewCanvas, RegionCanvas, {
|
|
59
|
-
willReadFrequently: option.willReadFrequently,
|
|
60
|
-
}, 2)
|
|
61
|
-
|
|
62
|
-
this.__canvas = ViewCanvas
|
|
63
|
-
this.painter.scale(2, 2)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
toDataURL(): Promise<string> {
|
|
67
|
-
return new Promise(resolve => {
|
|
68
|
-
resolve(this.__canvas.toDataURL())
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
1
|
+
import type CanvasType from '../types/Canvas'
|
|
2
|
+
import type CanvasOptionType from '../types/CanvasOption'
|
|
3
|
+
|
|
4
|
+
import OralCanvas from './common/canvas/index'
|
|
5
|
+
import mergeOption from './common/mergeOption'
|
|
6
|
+
|
|
7
|
+
class Canvas extends OralCanvas implements CanvasType {
|
|
8
|
+
private __canvas: HTMLCanvasElement
|
|
9
|
+
constructor(el: HTMLElement | null, option: CanvasOptionType = {}) {
|
|
10
|
+
if (!el) {
|
|
11
|
+
throw new Error("VISLite Canvas:The mount point requires an HTMLElement type but encountered null.")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
option = mergeOption(option, {
|
|
15
|
+
region: true,
|
|
16
|
+
willReadFrequently: false
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const width = el.clientWidth, height = el.clientHeight
|
|
20
|
+
|
|
21
|
+
let ViewCanvas: HTMLCanvasElement, RegionCanvas: HTMLCanvasElement | null = null
|
|
22
|
+
|
|
23
|
+
const _el = el as any
|
|
24
|
+
|
|
25
|
+
// 如果已经初始化过了
|
|
26
|
+
if (_el._vislite_canvas_) {
|
|
27
|
+
ViewCanvas = _el._vislite_canvas_[0]
|
|
28
|
+
RegionCanvas = _el._vislite_canvas_[1]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 否则就初始化
|
|
32
|
+
else {
|
|
33
|
+
ViewCanvas = document.createElement('canvas')
|
|
34
|
+
el.appendChild(ViewCanvas)
|
|
35
|
+
|
|
36
|
+
if (option.region) {
|
|
37
|
+
RegionCanvas = document.createElement('canvas')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_el._vislite_canvas_ = [ViewCanvas, RegionCanvas]
|
|
41
|
+
|
|
42
|
+
el.setAttribute('vislite', 'Canvas')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 设置画布大小
|
|
46
|
+
const canvasArray = [RegionCanvas, ViewCanvas]
|
|
47
|
+
for (let index = 0; index < canvasArray.length; index++) {
|
|
48
|
+
const canvas = canvasArray[index]
|
|
49
|
+
if (canvas) {
|
|
50
|
+
canvas.style.width = width + "px"
|
|
51
|
+
canvas.setAttribute('width', (index * width + width) + "")
|
|
52
|
+
|
|
53
|
+
canvas.style.height = height + "px"
|
|
54
|
+
canvas.setAttribute('height', (index * height + height) + "")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
super(ViewCanvas, RegionCanvas, {
|
|
59
|
+
willReadFrequently: option.willReadFrequently,
|
|
60
|
+
}, 2)
|
|
61
|
+
|
|
62
|
+
this.__canvas = ViewCanvas
|
|
63
|
+
this.painter.scale(2, 2)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
toDataURL(): Promise<string> {
|
|
67
|
+
return new Promise(resolve => {
|
|
68
|
+
resolve(this.__canvas.toDataURL())
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
73
|
export default Canvas
|
package/src/Geometry.ts
CHANGED
|
@@ -1,211 +1,211 @@
|
|
|
1
|
-
import type GeometryType from "../types/Geometry"
|
|
2
|
-
import type GeometryOptionType from "../types/GeometryOption"
|
|
3
|
-
import type GeometryResultType from "../types/GeometryResult"
|
|
4
|
-
|
|
5
|
-
type rotateLineType = (x0: number, y0: number, z0: number, isNormal: boolean) => Array<number>
|
|
6
|
-
|
|
7
|
-
import { splitNum } from './common/geometry/tool/circle'
|
|
8
|
-
import prismHorizontal from './common/geometry/prism-horizontal'
|
|
9
|
-
import prismVertical from './common/geometry/prism-vertical'
|
|
10
|
-
import sphereFragment from './common/geometry/sphere-fragment'
|
|
11
|
-
import mergeOption from './common/mergeOption'
|
|
12
|
-
import rotateLineFactory from "./common/geometry/tool/rotateLine"
|
|
13
|
-
import triangles from "./common/geometry/tool/triangles"
|
|
14
|
-
import rotate from "./rotate"
|
|
15
|
-
|
|
16
|
-
class Geometry implements GeometryType {
|
|
17
|
-
readonly name: string = 'Geometry'
|
|
18
|
-
|
|
19
|
-
private __option: GeometryOptionType
|
|
20
|
-
|
|
21
|
-
constructor(option: GeometryOptionType = {}) {
|
|
22
|
-
this.__option = mergeOption(option, {
|
|
23
|
-
precision: 0.1, // 精度
|
|
24
|
-
normal: false, // 是否需要法向量
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
config(option: GeometryOptionType) {
|
|
29
|
-
for (const key in option) {
|
|
30
|
-
this.__option[key] = option[key]
|
|
31
|
-
}
|
|
32
|
-
return this
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 【1】辅助方法
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
// 计算切割份数
|
|
40
|
-
splitNum(radius: number, deg?: number) {
|
|
41
|
-
return splitNum(this.__option.precision as number, radius, deg)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 物体方向转换
|
|
45
|
-
rotateLine(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) {
|
|
46
|
-
const rotateLine = rotateLineFactory(x1, y1, z1, x2, y2, z2)
|
|
47
|
-
return (x: number, y: number, z: number) => rotateLine(x, y, z, this.__option.normal as boolean)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 【2】立方片段
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
// 棱柱水平部分
|
|
55
|
-
prismHorizontal(x: number, y: number, z: number, radius: number, num: number, d: number, beginDeg?: number, deg?: number) {
|
|
56
|
-
return prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num, d, beginDeg, deg)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// 棱柱垂直部分
|
|
60
|
-
prismVertical(x: number, y: number, z: number, radius: number, height: number, num: number, beginDeg?: number, deg?: number) {
|
|
61
|
-
return prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num, beginDeg, deg)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 球体中的一瓣子
|
|
65
|
-
sphereFragment(cx: number, cy: number, cz: number, radius: number, num: number, index: number) {
|
|
66
|
-
return sphereFragment(this.__option.normal as boolean, cx, cy, cz, radius, num, index)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 【3】立方体
|
|
71
|
-
*/
|
|
72
|
-
|
|
73
|
-
// 饼柱体
|
|
74
|
-
pie(x: number, y: number, z: number, radius: number, height: number, beginDeg: number, deg: number): Array<GeometryResultType> {
|
|
75
|
-
|
|
76
|
-
// 求解出需要切割多少份比较合理
|
|
77
|
-
const num = splitNum(this.__option.precision as number, radius, deg)
|
|
78
|
-
|
|
79
|
-
const beginXZ = rotate(x, z, beginDeg, x + radius, z)
|
|
80
|
-
const endXZ = rotate(x, z, beginDeg + deg, x + radius, z)
|
|
81
|
-
|
|
82
|
-
const result = [{
|
|
83
|
-
name: "bottom",
|
|
84
|
-
points: prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num as number, height > 0 ? -1 : 1, beginDeg, deg),
|
|
85
|
-
length: 3 * num,
|
|
86
|
-
method: "TRIANGLES" as const
|
|
87
|
-
}, {
|
|
88
|
-
name: "top",
|
|
89
|
-
points: prismHorizontal(this.__option.normal as boolean, x, y + height, z, radius, num as number, height > 0 ? 1 : -1, beginDeg, deg),
|
|
90
|
-
length: 3 * num,
|
|
91
|
-
method: "TRIANGLES" as const
|
|
92
|
-
}, {
|
|
93
|
-
name: "side",
|
|
94
|
-
points: prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num as number, beginDeg, deg),
|
|
95
|
-
length: 6 * num,
|
|
96
|
-
method: "TRIANGLES" as const
|
|
97
|
-
}, {
|
|
98
|
-
name: "begin",
|
|
99
|
-
points: triangles(this.__option.normal as boolean, [
|
|
100
|
-
x, y, z, x, y + height, z, beginXZ[0], y, beginXZ[1],
|
|
101
|
-
beginXZ[0], y + height, beginXZ[1], beginXZ[0], y, beginXZ[1], x, y + height, z
|
|
102
|
-
]),
|
|
103
|
-
length: 6,
|
|
104
|
-
method: "TRIANGLES" as const
|
|
105
|
-
}, {
|
|
106
|
-
name: "end",
|
|
107
|
-
points: triangles(this.__option.normal as boolean, [
|
|
108
|
-
x, y, z, endXZ[0], y, endXZ[1], x, y + height, z,
|
|
109
|
-
endXZ[0], y + height, endXZ[1], x, y + height, z, endXZ[0], y, endXZ[1]
|
|
110
|
-
]),
|
|
111
|
-
length: 6,
|
|
112
|
-
method: "TRIANGLES" as const
|
|
113
|
-
}]
|
|
114
|
-
|
|
115
|
-
return result
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// 圆柱体
|
|
119
|
-
cylinder(x: number, y: number, z: number, radius: number, x2: number, y2?: number, z2?: number): Array<GeometryResultType> {
|
|
120
|
-
|
|
121
|
-
// 求解出需要切割多少份比较合理
|
|
122
|
-
const num = splitNum(this.__option.precision as number, radius)
|
|
123
|
-
|
|
124
|
-
if (arguments.length == 5) {
|
|
125
|
-
return this.prism(x, y, z, radius, x2, num)
|
|
126
|
-
} else {
|
|
127
|
-
return this.prism(x, y, z, radius, x2, y2 as number, z2, num)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 棱柱体
|
|
132
|
-
prism(x: number, y: number, z: number, radius: number, x2: number, y2: number, z2?: number, num?: number): Array<GeometryResultType> {
|
|
133
|
-
|
|
134
|
-
let height: number, rotateLine: rotateLineType | null = null
|
|
135
|
-
|
|
136
|
-
if (arguments.length == 6) {
|
|
137
|
-
height = x2
|
|
138
|
-
num = y2
|
|
139
|
-
} else {
|
|
140
|
-
height = (y > y2 ? -1 : 1) * Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 as number - z) * (z2 as number - z))
|
|
141
|
-
rotateLine = rotateLineFactory(x, y, z, x2, y2, z2 as number)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const result = [{
|
|
145
|
-
name: "bottom",
|
|
146
|
-
points: [],
|
|
147
|
-
length: 0,
|
|
148
|
-
method: "TRIANGLES" as const
|
|
149
|
-
}, {
|
|
150
|
-
name: "top",
|
|
151
|
-
points: [],
|
|
152
|
-
length: 0,
|
|
153
|
-
method: "TRIANGLES" as const
|
|
154
|
-
}, {
|
|
155
|
-
name: "side",
|
|
156
|
-
points: [],
|
|
157
|
-
length: 0,
|
|
158
|
-
method: "TRIANGLES" as const
|
|
159
|
-
}]
|
|
160
|
-
|
|
161
|
-
// 绘制底部的盖子
|
|
162
|
-
; (result[0].points as Array<number>).push(...prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num as number, height > 0 ? -1 : 1))
|
|
163
|
-
|
|
164
|
-
// 绘制顶部的盖子
|
|
165
|
-
; (result[1].points as Array<number>).push(...prismHorizontal(this.__option.normal as boolean, x, y + height, z, radius, num as number, height > 0 ? 1 : -1))
|
|
166
|
-
|
|
167
|
-
// 绘制侧边部分
|
|
168
|
-
; (result[2].points as Array<number>).push(...prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num as number))
|
|
169
|
-
|
|
170
|
-
for (let i = 0; i < result.length; i++) {
|
|
171
|
-
if (rotateLine) {
|
|
172
|
-
|
|
173
|
-
const points = []
|
|
174
|
-
let isNormal = false
|
|
175
|
-
for (let index = 0; index < result[i].points.length; index += 3) {
|
|
176
|
-
points.push(...rotateLine(result[i].points[index], result[i].points[index + 1], result[i].points[index + 2], (this.__option.normal as boolean) && isNormal))
|
|
177
|
-
isNormal = !isNormal
|
|
178
|
-
}
|
|
179
|
-
(result[i].points as Array<number>) = points
|
|
180
|
-
}
|
|
181
|
-
result[i].length = result[i].points.length / (this.__option.normal ? 6 : 3)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return result
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 球体
|
|
188
|
-
sphere(cx: number, cy: number, cz: number, radius: number): Array<GeometryResultType> {
|
|
189
|
-
|
|
190
|
-
// 求解出需要切割多少份比较合理
|
|
191
|
-
const num = splitNum(this.__option.precision as number, radius)
|
|
192
|
-
|
|
193
|
-
// 然后一瓣瓣的绘制
|
|
194
|
-
const result = [{
|
|
195
|
-
name: "surface",
|
|
196
|
-
points: [],
|
|
197
|
-
length: 0,
|
|
198
|
-
method: "TRIANGLES" as const
|
|
199
|
-
}]
|
|
200
|
-
for (let i = 0; i < num; i++) {
|
|
201
|
-
; (result[0].points as Array<number>).push(...sphereFragment(this.__option.normal as boolean, cx, cy, cz, radius, num, i))
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
result[0].length = result[0].points.length / (this.__option.normal ? 6 : 3)
|
|
205
|
-
|
|
206
|
-
return result
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
1
|
+
import type GeometryType from "../types/Geometry"
|
|
2
|
+
import type GeometryOptionType from "../types/GeometryOption"
|
|
3
|
+
import type GeometryResultType from "../types/GeometryResult"
|
|
4
|
+
|
|
5
|
+
type rotateLineType = (x0: number, y0: number, z0: number, isNormal: boolean) => Array<number>
|
|
6
|
+
|
|
7
|
+
import { splitNum } from './common/geometry/tool/circle'
|
|
8
|
+
import prismHorizontal from './common/geometry/prism-horizontal'
|
|
9
|
+
import prismVertical from './common/geometry/prism-vertical'
|
|
10
|
+
import sphereFragment from './common/geometry/sphere-fragment'
|
|
11
|
+
import mergeOption from './common/mergeOption'
|
|
12
|
+
import rotateLineFactory from "./common/geometry/tool/rotateLine"
|
|
13
|
+
import triangles from "./common/geometry/tool/triangles"
|
|
14
|
+
import rotate from "./rotate"
|
|
15
|
+
|
|
16
|
+
class Geometry implements GeometryType {
|
|
17
|
+
readonly name: string = 'Geometry'
|
|
18
|
+
|
|
19
|
+
private __option: GeometryOptionType
|
|
20
|
+
|
|
21
|
+
constructor(option: GeometryOptionType = {}) {
|
|
22
|
+
this.__option = mergeOption(option, {
|
|
23
|
+
precision: 0.1, // 精度
|
|
24
|
+
normal: false, // 是否需要法向量
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
config(option: GeometryOptionType) {
|
|
29
|
+
for (const key in option) {
|
|
30
|
+
this.__option[key] = option[key]
|
|
31
|
+
}
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 【1】辅助方法
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
// 计算切割份数
|
|
40
|
+
splitNum(radius: number, deg?: number) {
|
|
41
|
+
return splitNum(this.__option.precision as number, radius, deg)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 物体方向转换
|
|
45
|
+
rotateLine(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) {
|
|
46
|
+
const rotateLine = rotateLineFactory(x1, y1, z1, x2, y2, z2)
|
|
47
|
+
return (x: number, y: number, z: number) => rotateLine(x, y, z, this.__option.normal as boolean)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 【2】立方片段
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
// 棱柱水平部分
|
|
55
|
+
prismHorizontal(x: number, y: number, z: number, radius: number, num: number, d: number, beginDeg?: number, deg?: number) {
|
|
56
|
+
return prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num, d, beginDeg, deg)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 棱柱垂直部分
|
|
60
|
+
prismVertical(x: number, y: number, z: number, radius: number, height: number, num: number, beginDeg?: number, deg?: number) {
|
|
61
|
+
return prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num, beginDeg, deg)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 球体中的一瓣子
|
|
65
|
+
sphereFragment(cx: number, cy: number, cz: number, radius: number, num: number, index: number) {
|
|
66
|
+
return sphereFragment(this.__option.normal as boolean, cx, cy, cz, radius, num, index)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 【3】立方体
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
// 饼柱体
|
|
74
|
+
pie(x: number, y: number, z: number, radius: number, height: number, beginDeg: number, deg: number): Array<GeometryResultType> {
|
|
75
|
+
|
|
76
|
+
// 求解出需要切割多少份比较合理
|
|
77
|
+
const num = splitNum(this.__option.precision as number, radius, deg)
|
|
78
|
+
|
|
79
|
+
const beginXZ = rotate(x, z, beginDeg, x + radius, z)
|
|
80
|
+
const endXZ = rotate(x, z, beginDeg + deg, x + radius, z)
|
|
81
|
+
|
|
82
|
+
const result = [{
|
|
83
|
+
name: "bottom",
|
|
84
|
+
points: prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num as number, height > 0 ? -1 : 1, beginDeg, deg),
|
|
85
|
+
length: 3 * num,
|
|
86
|
+
method: "TRIANGLES" as const
|
|
87
|
+
}, {
|
|
88
|
+
name: "top",
|
|
89
|
+
points: prismHorizontal(this.__option.normal as boolean, x, y + height, z, radius, num as number, height > 0 ? 1 : -1, beginDeg, deg),
|
|
90
|
+
length: 3 * num,
|
|
91
|
+
method: "TRIANGLES" as const
|
|
92
|
+
}, {
|
|
93
|
+
name: "side",
|
|
94
|
+
points: prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num as number, beginDeg, deg),
|
|
95
|
+
length: 6 * num,
|
|
96
|
+
method: "TRIANGLES" as const
|
|
97
|
+
}, {
|
|
98
|
+
name: "begin",
|
|
99
|
+
points: triangles(this.__option.normal as boolean, [
|
|
100
|
+
x, y, z, x, y + height, z, beginXZ[0], y, beginXZ[1],
|
|
101
|
+
beginXZ[0], y + height, beginXZ[1], beginXZ[0], y, beginXZ[1], x, y + height, z
|
|
102
|
+
]),
|
|
103
|
+
length: 6,
|
|
104
|
+
method: "TRIANGLES" as const
|
|
105
|
+
}, {
|
|
106
|
+
name: "end",
|
|
107
|
+
points: triangles(this.__option.normal as boolean, [
|
|
108
|
+
x, y, z, endXZ[0], y, endXZ[1], x, y + height, z,
|
|
109
|
+
endXZ[0], y + height, endXZ[1], x, y + height, z, endXZ[0], y, endXZ[1]
|
|
110
|
+
]),
|
|
111
|
+
length: 6,
|
|
112
|
+
method: "TRIANGLES" as const
|
|
113
|
+
}]
|
|
114
|
+
|
|
115
|
+
return result
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 圆柱体
|
|
119
|
+
cylinder(x: number, y: number, z: number, radius: number, x2: number, y2?: number, z2?: number): Array<GeometryResultType> {
|
|
120
|
+
|
|
121
|
+
// 求解出需要切割多少份比较合理
|
|
122
|
+
const num = splitNum(this.__option.precision as number, radius)
|
|
123
|
+
|
|
124
|
+
if (arguments.length == 5) {
|
|
125
|
+
return this.prism(x, y, z, radius, x2, num)
|
|
126
|
+
} else {
|
|
127
|
+
return this.prism(x, y, z, radius, x2, y2 as number, z2, num)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 棱柱体
|
|
132
|
+
prism(x: number, y: number, z: number, radius: number, x2: number, y2: number, z2?: number, num?: number): Array<GeometryResultType> {
|
|
133
|
+
|
|
134
|
+
let height: number, rotateLine: rotateLineType | null = null
|
|
135
|
+
|
|
136
|
+
if (arguments.length == 6) {
|
|
137
|
+
height = x2
|
|
138
|
+
num = y2
|
|
139
|
+
} else {
|
|
140
|
+
height = (y > y2 ? -1 : 1) * Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 as number - z) * (z2 as number - z))
|
|
141
|
+
rotateLine = rotateLineFactory(x, y, z, x2, y2, z2 as number)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = [{
|
|
145
|
+
name: "bottom",
|
|
146
|
+
points: [],
|
|
147
|
+
length: 0,
|
|
148
|
+
method: "TRIANGLES" as const
|
|
149
|
+
}, {
|
|
150
|
+
name: "top",
|
|
151
|
+
points: [],
|
|
152
|
+
length: 0,
|
|
153
|
+
method: "TRIANGLES" as const
|
|
154
|
+
}, {
|
|
155
|
+
name: "side",
|
|
156
|
+
points: [],
|
|
157
|
+
length: 0,
|
|
158
|
+
method: "TRIANGLES" as const
|
|
159
|
+
}]
|
|
160
|
+
|
|
161
|
+
// 绘制底部的盖子
|
|
162
|
+
; (result[0].points as Array<number>).push(...prismHorizontal(this.__option.normal as boolean, x, y, z, radius, num as number, height > 0 ? -1 : 1))
|
|
163
|
+
|
|
164
|
+
// 绘制顶部的盖子
|
|
165
|
+
; (result[1].points as Array<number>).push(...prismHorizontal(this.__option.normal as boolean, x, y + height, z, radius, num as number, height > 0 ? 1 : -1))
|
|
166
|
+
|
|
167
|
+
// 绘制侧边部分
|
|
168
|
+
; (result[2].points as Array<number>).push(...prismVertical(this.__option.normal as boolean, x, y, z, radius, height, num as number))
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < result.length; i++) {
|
|
171
|
+
if (rotateLine) {
|
|
172
|
+
|
|
173
|
+
const points = []
|
|
174
|
+
let isNormal = false
|
|
175
|
+
for (let index = 0; index < result[i].points.length; index += 3) {
|
|
176
|
+
points.push(...rotateLine(result[i].points[index], result[i].points[index + 1], result[i].points[index + 2], (this.__option.normal as boolean) && isNormal))
|
|
177
|
+
isNormal = !isNormal
|
|
178
|
+
}
|
|
179
|
+
(result[i].points as Array<number>) = points
|
|
180
|
+
}
|
|
181
|
+
result[i].length = result[i].points.length / (this.__option.normal ? 6 : 3)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 球体
|
|
188
|
+
sphere(cx: number, cy: number, cz: number, radius: number): Array<GeometryResultType> {
|
|
189
|
+
|
|
190
|
+
// 求解出需要切割多少份比较合理
|
|
191
|
+
const num = splitNum(this.__option.precision as number, radius)
|
|
192
|
+
|
|
193
|
+
// 然后一瓣瓣的绘制
|
|
194
|
+
const result = [{
|
|
195
|
+
name: "surface",
|
|
196
|
+
points: [],
|
|
197
|
+
length: 0,
|
|
198
|
+
method: "TRIANGLES" as const
|
|
199
|
+
}]
|
|
200
|
+
for (let i = 0; i < num; i++) {
|
|
201
|
+
; (result[0].points as Array<number>).push(...sphereFragment(this.__option.normal as boolean, cx, cy, cz, radius, num, i))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
result[0].length = result[0].points.length / (this.__option.normal ? 6 : 3)
|
|
205
|
+
|
|
206
|
+
return result
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
211
|
export default Geometry
|