const THREE = require('three'); const Points = require('../three/Points').Points; const toBufferGeometry = require('../utilities').toBufferGeometry; const getCircularTexture = require('../utilities').getCircularTexture; const Label = require('./label').Label; /** * Provides an object which stores points and provides method which controls its position. * This is created when a valid json file containing point is read into a {@link Zinc.Scene} * object. * * @class * @author Alan Wu * @return {Pointset} */ const Pointset = function () { (require('./zincObject').ZincObject).call(this); this.isPointset = true; const labelSets = []; /** * Create the pointsets using geometry and material. * * @param {THREE.Geomtry} geometryIn - Geometry of points to be rendered. * @param {THREE.Material} materialIn - Material to be set for the lines. * @param {Object} options - Provide various options * @param {Boolean} options.localTimeEnabled - A flag to indicate either the lines is * time dependent. * @param {Boolean} options.localMorphColour - A flag to indicate either the colour is * time dependent. */ this.createMesh = (geometryIn, materialIn, options) => { if (geometryIn && materialIn) { let geometry = toBufferGeometry(geometryIn, options); const texture = getCircularTexture(); materialIn.map = texture; let point = new Points(geometry, materialIn); this.setMesh(point, options.localTimeEnabled, options.localMorphColour); } } const addLabel = (index, coord, labelText, colourHex) => { if (labelText) { const colour = new THREE.Color(colourHex); const label = new Label(labelText, colour); label.setPosition(coord[0], coord[1], coord[2]); const sprite = label.getSprite(); sprite.material.sizeAttenuation = false; sprite.material.alphaTest = 0.5; sprite.material.transparent = true; sprite.material.depthWrite = false; sprite.material.depthTest = false; this.group.add(sprite); labelSets[index] = label; } } /** * Add points to existing mesh if it exists, otherwise * create a new one and add to it. * @param {Array} coords -An array of three components coordinates. * @param {Array|String} labels - An array of strings, these are only added * if the number of coords equals to the number labels provided. * @param {Number} colour - A hex value of the colour for the points */ this.addPoints = (coords, labels, colour) => { if (coords && coords.length > 0) { let current = this.drawRange - 1; const geometry = this.addVertices(coords); let mesh = this.getMorph(); if (!mesh) { let material = new THREE.PointsMaterial({ alphaTest: 0.5, size: 10, color: colour, sizeAttenuation: false }); const options = { localTimeEnabled: false, localMorphColour: false}; geometry.colorsNeedUpdate = true; this.createMesh(geometry, material, options); } let end = current + coords.length; let index = 0; if ((Array.isArray(labels) && labels.length === coords.length) || (typeof labels === "string")) { for (current; current + index < end;) { const labelText = typeof labels === "string" ? labels : labels[index]; addLabel(index, coords[index], labelText, colour); index++; } } if (this.region) this.region.pickableUpdateRequired = true; } } /** * Set the size of the points. * * @param {Number} size - size to be set. */ this.setSize = size => { if (this.morph && this.morph.material) { this.morph.material.size = size; this.morph.material.needsUpdate = true; } } /** * Turn size attenuation on/off based on the flag. * * @param {Boolean} flag - Determin either size attenuation * should be on or off. */ this.setSizeAttenuation = flag => { if (this.morph && this.morph.material) { this.morph.material.sizeAttenuation = flag; this.morph.material.needsUpdate = true; } } /** * Get vertices at index */ this.getVerticesByIndex = function(index) { if (index >= 0 && this.drawRange > index) { const positionAttribute = this.getMorph().geometry.getAttribute( 'position' ); return [ positionAttribute.getX(index), positionAttribute.getY(index), positionAttribute.getZ(index) ]; } return undefined; } /** * Edit Vertice in index. */ this.editVertices = function(coords, i) { if (coords && coords.length) { let mesh = this.getMorph(); const maxIndex = i + coords.length - 1; if (!mesh || 0 > i || maxIndex >= this.drawRange) { return; } else { const positionAttribute = mesh.geometry.getAttribute( 'position' ); let index = i; coords.forEach(coord => { const label = labelSets[index]; if (label) { label.setPosition(coord[0], coord[1], coord[2]); } positionAttribute.setXYZ(index++, coord[0], coord[1], coord[2]); }); positionAttribute.needsUpdate = true; this.boundingBoxUpdateRequired = true; } } } /** * Turn size attenuation on/off based on the flag. * * @param {Boolean} flag - Determin either size attenuation * should be on or off. */ this.render = (delta, playAnimation, cameraControls, options) => { if (this.morph && cameraControls) { this.morph.sizePerPixel = cameraControls.pixelHeight; } Pointset.prototype.render.call(this, delta, playAnimation, cameraControls, options); } } Pointset.prototype = Object.create((require('./zincObject').ZincObject).prototype); exports.Pointset = Pointset;