From 8503aec729598f5737d3d3838ed1364b561f1bcb Mon Sep 17 00:00:00 2001 From: Tom Daff Date: Fri, 1 Nov 2024 14:58:32 +0000 Subject: [PATCH] New shape: Icosahedron --- src/buffer/icosahedron-buffer.ts | 68 ++++++++++++++++++++++++++++++++ src/controls/picking-proxy.ts | 6 +++ src/geometry/primitive.ts | 7 ++++ src/geometry/shape.ts | 24 ++++++++++- src/ngl.ts | 2 + src/utils/picker.ts | 9 ++++- 6 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 src/buffer/icosahedron-buffer.ts diff --git a/src/buffer/icosahedron-buffer.ts b/src/buffer/icosahedron-buffer.ts new file mode 100644 index 000000000..deaba34d2 --- /dev/null +++ b/src/buffer/icosahedron-buffer.ts @@ -0,0 +1,68 @@ +/** + * @file Icosahedron Buffer + * @private + */ + +import { IcosahedronGeometry, Vector3, Matrix4 } from 'three' + +import { BufferRegistry } from '../globals' +import GeometryBuffer from './geometry-buffer' +import { BufferData, BufferParameters } from './buffer' + +const scale = new Vector3() +const target = new Vector3() +const up = new Vector3() +const eye = new Vector3(0, 0, 0) + +export interface IcosahedronBufferData extends BufferData { + heightAxis: Float32Array + depthAxis: Float32Array + size: Float32Array +} + +/** + * Icosahedron buffer. Draws Icosahedrons. + * + * @example + * var icosahedronBuffer = new IcosahedronBuffer({ + * position: new Float32Array([ 0, 3, 0, -2, 0, 0 ]), + * color: new Float32Array([ 1, 0, 1, 0, 1, 0 ]), + * size: new Float32Array([ 2, 1.5 ]), + * heightAxis: new Float32Array([ 0, 1, 1, 0, 2, 0 ]), + * depthAxis: new Float32Array([ 1, 0, 1, 0, 0, 2 ]) + * }) + */ +class IcosahedronBuffer extends GeometryBuffer { + updateNormals = true + + _heightAxis: Float32Array + _depthAxis: Float32Array + _size: Float32Array + + constructor (data: IcosahedronBufferData, params: Partial = {}) { + super(data, params, new IcosahedronGeometry(1, 0)) + + this.setAttributes(data, true) + } + + applyPositionTransform (matrix: Matrix4, i: number, i3: number) { + target.fromArray(this._heightAxis as any, i3) + up.fromArray(this._depthAxis as any, i3) + matrix.lookAt(eye, target, up) + + scale.set(this._size[ i ], up.length(), target.length()) + matrix.scale(scale) + } + + setAttributes (data: Partial = {}, initNormals?: boolean) { + if (data.size) this._size = data.size + if (data.heightAxis) this._heightAxis = data.heightAxis + if (data.depthAxis) this._depthAxis = data.depthAxis + + super.setAttributes(data, initNormals) + } +} + +BufferRegistry.add('icosahedron', IcosahedronBuffer) + +export default IcosahedronBuffer diff --git a/src/controls/picking-proxy.ts b/src/controls/picking-proxy.ts index c4c53126e..3c9021546 100644 --- a/src/controls/picking-proxy.ts +++ b/src/controls/picking-proxy.ts @@ -248,6 +248,10 @@ class PickingProxy { * @type {Object} */ get ellipsoid () { return this._objectIfType('ellipsoid') as ShapePrimitive } + /** + * @type {Object} + */ + get icosahedron () { return this._objectIfType('icosahedron') as ShapePrimitive } /** * @type {Object} */ @@ -326,6 +330,8 @@ class PickingProxy { msg = `distance: ${this.distance.atom1.qualifiedName()} - ${this.distance.atom2.qualifiedName()} (${this.distance.structure.name})` } else if (this.ellipsoid) { msg = this.ellipsoid.name + } else if (this.icosahedron) { + msg = this.icosahedron.name } else if (this.octahedron) { msg = this.octahedron.name } else if (this.point) { diff --git a/src/geometry/primitive.ts b/src/geometry/primitive.ts index fdbcff07a..627c2cd24 100644 --- a/src/geometry/primitive.ts +++ b/src/geometry/primitive.ts @@ -181,6 +181,13 @@ export class TetrahedronPrimitive extends BoxPrimitive { static type = 'tetrahedron' } +/** + * Icosahedron geometry primitive + */ +export class IcosahedronPrimitive extends BoxPrimitive { + static type = 'icosahedron' +} + /** * Cylinder geometry primitive */ diff --git a/src/geometry/shape.ts b/src/geometry/shape.ts index 2a6280683..cbfd8964c 100644 --- a/src/geometry/shape.ts +++ b/src/geometry/shape.ts @@ -11,7 +11,7 @@ import { createParams, ensureFloat32Array, getUintArray } from '../utils' import { ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive, EllipsoidPrimitive, OctahedronPrimitive, SpherePrimitive, TetrahedronPrimitive, TextPrimitive, - TorusPrimitive, PointPrimitive, WidelinePrimitive + TorusPrimitive, PointPrimitive, WidelinePrimitive, IcosahedronPrimitive } from './primitive' import { MeshPicker } from '../utils/picker' import Buffer from '../buffer/buffer' @@ -23,7 +23,7 @@ const tmpBox = new Box3() const Primitives = [ ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive, EllipsoidPrimitive, OctahedronPrimitive, SpherePrimitive, TetrahedronPrimitive, - TextPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive + TextPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive, IcosahedronPrimitive ] export const ShapeDefaultParameters = { @@ -329,6 +329,26 @@ class Shape { return this } + /** + * Add an icosahedron + * @example + * shape.addIcosahedron([ 0, 3, 0 ], [ 1, 0, 1 ], 2, [ 0, 1, 1 ], [ 1, 0, 1 ]); + * + * @param {Vector3|Array} position - position vector or array + * @param {Color|Array} color - color object or array + * @param {Float} size - size value + * @param {Vector3|Array} heightAxis - height axis vector or array + * @param {Vector3|Array} depthAxis - depth axis vector or array + * @param {String} [name] - text + * @return {Shape} this object + */ + addIcosahedron (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, heightAxis: Vector3|[number, number, number], depthAxis: Vector3|[number, number, number], name: string) { + IcosahedronPrimitive.objectToShape( + this, { position, color, size, heightAxis, depthAxis, name } + ) + return this + } + /** * Add text * @example diff --git a/src/ngl.ts b/src/ngl.ts index ab941c511..77d682dfe 100644 --- a/src/ngl.ts +++ b/src/ngl.ts @@ -117,6 +117,7 @@ import BoxBuffer from './buffer/box-buffer' import ConeBuffer from './buffer/cone-buffer' import CylinderBuffer from './buffer/cylinder-buffer' import EllipsoidBuffer from './buffer/ellipsoid-buffer' +import IcosahedronBuffer from './buffer/icosahedron-buffer' import MeshBuffer from './buffer/mesh-buffer' import OctahedronBuffer from './buffer/octahedron-buffer' import PointBuffer from './buffer/point-buffer' @@ -298,6 +299,7 @@ export { ConeBuffer, CylinderBuffer, EllipsoidBuffer, + IcosahedronBuffer, MeshBuffer, OctahedronBuffer, PointBuffer, diff --git a/src/utils/picker.ts b/src/utils/picker.ts index 2aae4b3bd..61d7daa7d 100644 --- a/src/utils/picker.ts +++ b/src/utils/picker.ts @@ -12,7 +12,8 @@ import Selection from '../selection/selection' import { ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive, EllipsoidPrimitive, OctahedronPrimitive, SpherePrimitive, - TetrahedronPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive + TetrahedronPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive, + IcosahedronPrimitive } from '../geometry/primitive' import { contactTypeName, Contacts } from '../chemistry/interactions/contact' import { TypedArray } from '../types'; @@ -283,6 +284,10 @@ class EllipsoidPicker extends ShapePicker { get primitive () { return EllipsoidPrimitive } } +class IcosahedronPicker extends ShapePicker { + get primitive () { return IcosahedronPrimitive } +} + class OctahedronPicker extends ShapePicker { get primitive () { return OctahedronPrimitive } } @@ -442,6 +447,7 @@ PickerRegistry.add('box', BoxPicker) PickerRegistry.add('cone', ConePicker) PickerRegistry.add('cylinder', CylinderPicker) PickerRegistry.add('ellipsoid', EllipsoidPicker) +PickerRegistry.add('icosahedron', IcosahedronPicker) PickerRegistry.add('octahedron', OctahedronPicker) PickerRegistry.add('sphere', SpherePicker) PickerRegistry.add('tetrahedron', TetrahedronPicker) @@ -463,6 +469,7 @@ export { ClashPicker, DistancePicker, EllipsoidPicker, + IcosahedronPicker, IgnorePicker, OctahedronPicker, MeshPicker,