1 | /*global Module*/ |
---|
2 | "use strict"; |
---|
3 | |
---|
4 | import * as THREE from 'three'; |
---|
5 | import PartMeshFactory from './partmeshfactory'; |
---|
6 | import JointMeshFactory from './jointmeshfactory'; |
---|
7 | import GenotypeParser from '../utils/genotypeparser'; |
---|
8 | import { geometry } from './transformations'; |
---|
9 | |
---|
10 | |
---|
11 | /** |
---|
12 | * @file Framstick Object |
---|
13 | * @author Patryk Gliszczynski |
---|
14 | * @version 1.2 |
---|
15 | */ |
---|
16 | class Framstick { |
---|
17 | |
---|
18 | /** |
---|
19 | * |
---|
20 | * @param {Genotype} genotype genotype of creating framstick |
---|
21 | */ |
---|
22 | constructor(genotype, viewer) { |
---|
23 | this.viewer = viewer; |
---|
24 | this.genotype = genotype; |
---|
25 | this.parts = []; |
---|
26 | this.joints = []; |
---|
27 | this.meshes = []; |
---|
28 | |
---|
29 | this.positions = []; |
---|
30 | this.color = 'white'; |
---|
31 | this.avgPosition = new THREE.Vector3(0, 0, 0); |
---|
32 | |
---|
33 | this.partfactory = new PartMeshFactory(geometry.part); |
---|
34 | this.jointfactory = new JointMeshFactory(geometry.joint); |
---|
35 | |
---|
36 | this.mesh = new THREE.Group(); |
---|
37 | this.loadFromGenotype(); |
---|
38 | |
---|
39 | for (let i = 0; i < this.mesh.children.length; i++) { |
---|
40 | this.avgPosition.add(this.mesh.children[i].position.clone()); |
---|
41 | } |
---|
42 | |
---|
43 | this.avgPosition.divideScalar(this.mesh.children.length); |
---|
44 | |
---|
45 | for (let i = 0; i < this.mesh.children.length; i++) { |
---|
46 | this.mesh.children[i].position.sub(this.avgPosition); |
---|
47 | } |
---|
48 | |
---|
49 | this.viewer.scene.add(this.mesh); |
---|
50 | this.mesh.rotation.set(Math.random()*Math.PI*2, Math.random()*Math.PI*2, Math.random()*Math.PI*2, this.mesh.rotation.order ); |
---|
51 | } |
---|
52 | |
---|
53 | /** |
---|
54 | * Change Framstick's color on click |
---|
55 | */ |
---|
56 | setColor(color) { |
---|
57 | if (this.color != color) { |
---|
58 | let colorTemp = this.color; |
---|
59 | this.color = color; |
---|
60 | |
---|
61 | let position = this.mesh.position.clone(); |
---|
62 | let rotation = this.mesh.rotation.clone(); |
---|
63 | this.viewer.scene.remove(this.mesh); |
---|
64 | |
---|
65 | this.loadFromGenotype(); |
---|
66 | |
---|
67 | this.mesh.position.set( position.x, position.y, position.z ); |
---|
68 | this.mesh.rotation.set(rotation.x, rotation.y, rotation.z, rotation.order ); |
---|
69 | |
---|
70 | |
---|
71 | if (this.color == 'red' || colorTemp == 'red') { |
---|
72 | for (let i = 0; i < this.meshes.length; i++) { |
---|
73 | this.viewer.meshes.shift(); |
---|
74 | } |
---|
75 | for (let i = 0; i < this.parts.length; i++) { |
---|
76 | this.viewer.parts.shift(); |
---|
77 | } |
---|
78 | for (let i = this.meshes.length - 1; i >= 0; i--) { |
---|
79 | this.viewer.meshes.unshift(this.meshes[i]); |
---|
80 | } |
---|
81 | for (let i = this.parts.length - 1; i >= 0; i--) { |
---|
82 | this.viewer.parts.unshift(this.parts[i]); |
---|
83 | } |
---|
84 | } else { |
---|
85 | for (let i = 0; i < this.meshes.length; i++) { |
---|
86 | this.viewer.meshes.pop(); |
---|
87 | } |
---|
88 | for (let i = 0; i < this.parts.length; i++) { |
---|
89 | this.viewer.parts.pop(); |
---|
90 | } |
---|
91 | for (let i = 0; i < this.meshes.length; i++) { |
---|
92 | this.viewer.meshes.push(this.meshes[i]); |
---|
93 | } |
---|
94 | for (let i = 0; i < this.parts.length; i++) { |
---|
95 | this.viewer.parts.push(this.parts[i]); |
---|
96 | } |
---|
97 | } |
---|
98 | |
---|
99 | this.viewer.scene.add(this.mesh); |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | addText(nr) { |
---|
104 | for (let i = 0; i < this.positions.length; i++) { |
---|
105 | let div = document.createElement("div"); |
---|
106 | div.className = "label"; |
---|
107 | div.style.position = 'absolute'; |
---|
108 | div.style.color = 'white'; |
---|
109 | div.style.textAlign = 'center'; |
---|
110 | div.style.display = ''; |
---|
111 | div.style.fontFamily = "'Fira Mono', Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace"; |
---|
112 | //div.style.margin = '-5px 0 0 15px'; |
---|
113 | div.style.pointerEvents = 'none'; |
---|
114 | div.style.webkitUserSelect = 'none'; |
---|
115 | div.style.mozUserSelect = 'none'; |
---|
116 | div.style.msUserSelect = 'none'; |
---|
117 | div.style.userSelect = 'none'; |
---|
118 | |
---|
119 | if (nr == 1) { |
---|
120 | div.textContent = (i+1).toString(); |
---|
121 | } else { |
---|
122 | let label = ''; |
---|
123 | if (i + 1 + 64 > 90) { |
---|
124 | label = String.fromCharCode(i + 1 + 70); |
---|
125 | } else { |
---|
126 | label = String.fromCharCode(i + 1 + 64); |
---|
127 | } |
---|
128 | div.textContent = label; |
---|
129 | } |
---|
130 | |
---|
131 | let pos = new THREE.Vector3().copy(this.positions[i]).applyEuler(this.mesh.rotation).add(this.mesh.position); |
---|
132 | let dis = pos.distanceTo(this.viewer.camera.perspectiveCamera.position); |
---|
133 | pos.project(this.viewer.camera.perspectiveCamera); |
---|
134 | |
---|
135 | this.viewer.raycaster.setFromCamera(pos, this.viewer.camera.perspectiveCamera); |
---|
136 | |
---|
137 | let intersectedObjects = this.viewer.raycaster.intersectObjects(this.viewer.parts); |
---|
138 | let show = intersectedObjects.length && this.parts[i] === intersectedObjects[0].object; |
---|
139 | |
---|
140 | |
---|
141 | if (Math.abs(pos.z) > 1 || pos.x < -0.96 || pos.y < -0.96 || pos.x > 0.96 || pos.y > 0.96) { |
---|
142 | div.style.display = 'none'; |
---|
143 | } else { |
---|
144 | div.style.fontSize = (150.0 / dis).toString() + 'px'; |
---|
145 | div.style.display = ''; |
---|
146 | |
---|
147 | if ((150.0 / dis)/(2*this.viewer.container.clientHeight) + pos.y > 1.0 || |
---|
148 | pos.y - (150.0 / dis)/(2*this.viewer.container.clientHeight) < -1.0 || |
---|
149 | (150.0 / dis)/(2*this.viewer.container.clientWidth) + pos.x > 1.0 || |
---|
150 | pos.x - (150.0 / dis)/(2*this.viewer.container.clientWidth) < -1.0) { |
---|
151 | div.style.display = 'none'; |
---|
152 | } |
---|
153 | div.style.zIndex = (-pos.z * .5 + .5) * 100000 | 0; |
---|
154 | |
---|
155 | if (!show) { |
---|
156 | //div.style.margin = '-5px 0 0 15px'; |
---|
157 | div.style.display = 'none'; |
---|
158 | } |
---|
159 | |
---|
160 | let x = (pos.x * .5 + .5) * this.viewer.container.clientWidth; |
---|
161 | let y = (pos.y * -.5 + .5) * this.viewer.container.clientHeight; |
---|
162 | div.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`; |
---|
163 | this.viewer.container.appendChild(div); |
---|
164 | } |
---|
165 | |
---|
166 | } |
---|
167 | } |
---|
168 | |
---|
169 | /** |
---|
170 | * Return framstick position in the world |
---|
171 | */ |
---|
172 | setPositions() { |
---|
173 | this.positions = []; |
---|
174 | let tempV = new THREE.Vector3(); |
---|
175 | |
---|
176 | for (let i = 0; i < this.parts.length; i++) { |
---|
177 | let mesh = this.parts[i]; |
---|
178 | |
---|
179 | this.viewer.camera.perspectiveCamera.updateMatrixWorld(true, false); |
---|
180 | mesh.getWorldPosition(tempV); |
---|
181 | this.positions.push(tempV.clone()); |
---|
182 | } |
---|
183 | } |
---|
184 | |
---|
185 | /** |
---|
186 | * Code below was taken from: http://fugue.synology.me:30000/grzegorzlatosinski/framsticks-js |
---|
187 | * @author Grzegorz Latosiński |
---|
188 | * @pull_date 22.01.2018 |
---|
189 | */ |
---|
190 | loadFromGenotype() { |
---|
191 | this.mesh = new THREE.Group(); |
---|
192 | |
---|
193 | let model = GenotypeParser.getModelFromGenotype(this.genotype); |
---|
194 | |
---|
195 | if (typeof model !== 'undefined') { |
---|
196 | let partsforjoints = []; |
---|
197 | this.meshes = []; |
---|
198 | this.parts = []; |
---|
199 | this.joints = []; |
---|
200 | |
---|
201 | for (let i = 0; i < model.getPartCount(); i++) { |
---|
202 | let m = this.partfactory.create(model.getPart(i), this.color); |
---|
203 | partsforjoints.push(m.userData); |
---|
204 | this.mesh.add(m) |
---|
205 | this.parts.push(m); |
---|
206 | this.meshes.push(m); |
---|
207 | } |
---|
208 | |
---|
209 | for (let i = 0; i < model.getJointCount(); i++) { |
---|
210 | let m = this.jointfactory.create(model.getJoint(i), this.color, partsforjoints); |
---|
211 | |
---|
212 | this.mesh.add(m); |
---|
213 | this.joints.push(m); |
---|
214 | this.meshes.push(m); |
---|
215 | } |
---|
216 | |
---|
217 | new THREE.Box3().setFromObject(this.mesh).getCenter(this.mesh.position).multiplyScalar(-1); |
---|
218 | |
---|
219 | for (let i = 0; i < this.mesh.children.length; i++) { |
---|
220 | this.mesh.children[i].position.sub(this.avgPosition); |
---|
221 | } |
---|
222 | } |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | export default Framstick; |
---|