[881] | 1 | "use strict"; |
---|
| 2 | import * as THREE from 'three'; |
---|
| 3 | import Transformations from './transformations'; |
---|
| 4 | |
---|
| 5 | /** |
---|
| 6 | * Helper class for creating meshes for joints in Framsticks-SDK. It combines |
---|
| 7 | * Framsticks-SDK logic with THREE.js logic. |
---|
| 8 | * |
---|
| 9 | * For now shape versions of joints are hard-coded. It may need redefinition in |
---|
| 10 | * the future. |
---|
| 11 | */ |
---|
| 12 | class JointMeshFactory { |
---|
| 13 | /** |
---|
| 14 | * Basic constructor that takes information of how joints should be drawn. |
---|
| 15 | * @param {object} config basic config for joints drawing |
---|
| 16 | * @param {boolean} physics determines if created objects should by Physijs based |
---|
| 17 | */ |
---|
| 18 | constructor(config, physics = false) { |
---|
| 19 | this.config = config; |
---|
| 20 | this.transformations = new Transformations(); |
---|
| 21 | this.jointShapes = this.transformations.getJointShapes(); |
---|
| 22 | this.physics = physics; |
---|
| 23 | } |
---|
| 24 | |
---|
| 25 | /** |
---|
| 26 | * Creates Mesh for a given Joint. |
---|
| 27 | * @param {Module.Joint} joint Framsticks-SDK Joint class object |
---|
| 28 | * @param {object} shapeConfig object holding following fields |
---|
| 29 | * @param {number} shapeConfig.radius radius of mesh |
---|
| 30 | * @param {number} shapeConfig.radiusSegments number of segments for mesh |
---|
| 31 | * @param {boolean} shapeConfig.isTransparent true if transparent, false otherwise |
---|
| 32 | * @param {number} shapeConfig.opacity opacity of mesh |
---|
| 33 | * @returns {Mesh} Mesh for a given joint |
---|
| 34 | */ |
---|
[911] | 35 | getNewJointMesh(joint, color, shapeConfig) { |
---|
[881] | 36 | let firstPartPosVec = new THREE.Vector3( |
---|
| 37 | joint.get_part1().get_p().get_x(), |
---|
| 38 | joint.get_part1().get_p().get_y(), |
---|
| 39 | joint.get_part1().get_p().get_z()); |
---|
| 40 | let secondPartPosVec = new THREE.Vector3( |
---|
| 41 | joint.get_part2().get_p().get_x(), |
---|
| 42 | joint.get_part2().get_p().get_y(), |
---|
| 43 | joint.get_part2().get_p().get_z()); |
---|
| 44 | |
---|
| 45 | let direction = new THREE.Vector3().subVectors(secondPartPosVec, firstPartPosVec); |
---|
[911] | 46 | let geometry = new THREE.CylinderGeometry(shapeConfig.radius, shapeConfig.radius, direction.length() - 2 * 0.18, shapeConfig.radiusSegments); |
---|
| 47 | let material = this.transformations.getNewMaterial(color); |
---|
[881] | 48 | let mesh = new THREE.Mesh( geometry, material ); //new Physijs.CylinderMesh( geometry, Physijs.createMaterial(material) ); //new THREE.Mesh( geometry, material ); |
---|
| 49 | |
---|
[911] | 50 | let orientation = new THREE.Matrix4(); |
---|
[881] | 51 | orientation.lookAt(firstPartPosVec, secondPartPosVec, new THREE.Object3D().up); |
---|
| 52 | orientation.multiply(new THREE.Matrix4().set( |
---|
| 53 | 1, 0, 0, 0, |
---|
| 54 | 0, 0, 1, 0, |
---|
| 55 | 0, -1, 0, 0, |
---|
| 56 | 0, 0, 0, 1 |
---|
| 57 | )); |
---|
| 58 | |
---|
| 59 | mesh.applyMatrix(orientation); |
---|
| 60 | mesh.position.x = (secondPartPosVec.x + firstPartPosVec.x) / 2; |
---|
| 61 | mesh.position.y = (secondPartPosVec.y + firstPartPosVec.y) / 2; |
---|
| 62 | mesh.position.z = (secondPartPosVec.z + firstPartPosVec.z) / 2; |
---|
| 63 | |
---|
| 64 | |
---|
| 65 | mesh.userData = { |
---|
| 66 | isBodyElement: true, |
---|
| 67 | type: 'j', |
---|
| 68 | data: joint, |
---|
| 69 | mesh: mesh, |
---|
| 70 | connectedParts: [], |
---|
[911] | 71 | showTransparent: true |
---|
[881] | 72 | }; |
---|
| 73 | return mesh; |
---|
| 74 | } |
---|
| 75 | |
---|
| 76 | /** |
---|
| 77 | * Method finds for a given jointMesh all attached partMeshes and updates |
---|
| 78 | * respectively for those objects their connectedParts and connectedJoints |
---|
| 79 | * fields. |
---|
| 80 | * @param {JointMesh} jointMesh joint for which attached parts will be searched |
---|
| 81 | * @param {PartMesh} partMeshes list of available parts |
---|
| 82 | */ |
---|
| 83 | addConnectionInfo(jointMesh, partMeshes) { |
---|
| 84 | let p1 = jointMesh.data.get_part1(); |
---|
| 85 | let p2 = jointMesh.data.get_part2(); |
---|
| 86 | let count = 0; |
---|
| 87 | for (let i = 0; i < partMeshes.length && count < 2; ++i) { |
---|
| 88 | if (partMeshes[i].data === p1 || partMeshes[i].data === p2) { |
---|
| 89 | jointMesh.connectedParts.push(partMeshes[i]); |
---|
| 90 | partMeshes[i].connectedJoints.push(jointMesh); |
---|
| 91 | ++count; |
---|
| 92 | } |
---|
| 93 | } |
---|
| 94 | } |
---|
| 95 | |
---|
| 96 | /** |
---|
| 97 | * Creates mesh for a given Joint. Additional parameter partMeshes is |
---|
| 98 | * provided to update both Joint and connected Parts with info about |
---|
| 99 | * their connectivity. |
---|
| 100 | * @param {Module.Joint} joint joint for which mesh is created |
---|
| 101 | * @param {PartMesh} partMeshes list of available parts |
---|
| 102 | * @returns {JointMesh} new joint mesh, for properties of Object look at addConnectionInfo jointMesh param documentation |
---|
| 103 | */ |
---|
[911] | 104 | create(joint, color, partMeshes) { |
---|
[881] | 105 | let result; |
---|
| 106 | let shape = joint.get_shape(); |
---|
| 107 | |
---|
| 108 | if (this.jointShapes['SHAPE_FIXED'].value == shape) { |
---|
[911] | 109 | result = this.getNewJointMesh(joint, color, this.config.linkShape); |
---|
[881] | 110 | } else { |
---|
[911] | 111 | result = this.getNewJointMesh(joint, color, this.config.cylinderShape); |
---|
[881] | 112 | } |
---|
| 113 | |
---|
| 114 | if (partMeshes) { |
---|
| 115 | this.addConnectionInfo(result.userData, partMeshes); |
---|
| 116 | } |
---|
| 117 | |
---|
| 118 | return result; |
---|
| 119 | } |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | export default JointMeshFactory; |
---|