'use strict';
var VJS = VJS || {};
VJS.geometries = VJS.geometries || {};
/*** Imports ***/
VJS.core = VJS.core || {};
VJS.core.intersections = VJS.core.intersections || require('../core/core.intersections');
/**
*
* It is typically used for creating an irregular 3D planar shape given a box and the cut-plane.
*
* Demo: {@link https://fnndsc.github.io/vjs#geometry_slice}
*
* @constructor
* @class
* @memberOf VJS.geometries
* @public
*
* @param {THREE.Vector3} halfDimensions - Half-dimensions of the box to be sliced.
* @param {THREE.Vector3} center - Center of the box to be sliced.
* @param {THREE.Vector3<THREE.Vector3>} orientation - Orientation of the box to be sliced. (might not be necessary..?)
* @param {THREE.Vector3} position - Position of the cutting plane.
* @param {THREE.Vector3} direction - Cross direction of the cutting plane.
*
* @example
* // Define box to be sliced
* var halfDimensions = new THREE.Vector(123, 45, 67);
* var center = new THREE.Vector3(0, 0, 0);
* var orientation = new THREE.Vector3(
* new THREE.Vector3(1, 0, 0),
* new THREE.Vector3(0, 1, 0),
* new THREE.Vector3(0, 0, 1)
* );
*
* // Define slice plane
* var position = center.clone();
* var direction = new THREE.Vector3(-0.2, 0.5, 0.3);
*
* // Create the slice geometry & materials
* var sliceGeometry = new VJS.geometries.slice(halfDimensions, center, orientation, position, direction);
* var sliceMaterial = new THREE.MeshBasicMaterial({
* 'side': THREE.DoubleSide,
* 'color': 0xFF5722
* });
*
* // Create mesh and add it to the scene
* var slice = new THREE.Mesh(sliceGeometry, sliceMaterial);
* scene.add(slice);
*/
VJS.geometries.slice = function(halfDimensions, center, orientation, position, direction) {
//
// prepare data for the shape!
//
var obb = {
'halfDimensions': halfDimensions,
'center': center,
'orientation': orientation,
'toOBBSpace': new THREE.Matrix4(), // not necessary
'toOBBSpaceInvert': new THREE.Matrix4() // not necessary
};
var plane = {
'position': position,
'direction': direction
};
// BOOM!
var intersections = VJS.core.intersections.obbPlane(obb, plane);
if (intersections.length < 3) {
window.console.log('WARNING: Less than 3 intersections between OBB and Plane.');
window.console.log('OBB');
window.console.log(obb);
window.console.log('Plane');
window.console.log(plane);
window.console.log('exiting...');
}
var centerOfMass = this.centerOfMass(intersections);
var orderedIntersections = this.orderIntersections(intersections, centerOfMass, direction);
// split for convenience
var formatIntersections = [];
var formatIntersectionsXY = [];
for (var k = 0; k < orderedIntersections.length; k++) {
formatIntersections.push(orderedIntersections[k].point);
formatIntersectionsXY.push(orderedIntersections[k].xy);
}
//
// Create Shape
//
var sliceShape = new THREE.Shape();
// move to first point!
sliceShape.moveTo(formatIntersectionsXY[0].x, formatIntersectionsXY[0].y);
// loop through all points!
for (var l = 1; l < formatIntersectionsXY.length; l++) {
// project each on plane!
sliceShape.lineTo(formatIntersectionsXY[l].x, formatIntersectionsXY[l].y);
}
// close the shape!
sliceShape.lineTo(formatIntersectionsXY[0].x, formatIntersectionsXY[0].y);
//
// Generate Geometry from shape
// It does triangulation for us!
//
THREE.ShapeGeometry.call(this, sliceShape);
this.type = 'SliceGeometry';
// update real position of each vertex! (not in 2d)
this.vertices = formatIntersections;
this.verticesNeedUpdate = true;
};
VJS.geometries.slice.prototype = Object.create(THREE.ShapeGeometry.prototype);
VJS.geometries.slice.prototype.constructor = VJS.geometries.slice;
/**
*
* Convenience function to extract center of mass from list of points.
*
* @private
*
* @param {Array<THREE.Vector3>} points - Set of points from which we want to extract the center of mass.
*
* @returns {THREE.Vector3} Center of mass from given points.
*/
VJS.geometries.slice.prototype.centerOfMass = function(points) {
var centerOfMass = new THREE.Vector3(0, 0, 0);
for (var i = 0; i < points.length; i++) {
centerOfMass.x += points[i].x;
centerOfMass.y += points[i].y;
centerOfMass.z += points[i].z;
}
centerOfMass.divideScalar(points.length);
return centerOfMass;
};
/**
*
* Order 3D planar points around a refence point.
*
* @private
*
* @param {Array<THREE.Vector3>} points - Set of planar 3D points to be ordered.
* @param {THREE.Vector3} reference - Reference point for ordering.
* @param {THREE.Vector3} direction - Direction of the plane in which points and reference are sitting.
*
* @returns {Array<Object>} Set of object representing the ordered points.
*/
VJS.geometries.slice.prototype.orderIntersections = function(points, reference, direction) {
var a0 = points[0].x;
var b0 = points[0].y;
var c0 = points[0].z;
var x0 = points[0].x - reference.x;
var y0 = points[0].y - reference.y;
var z0 = points[0].z - reference.z;
var l0 = {
origin: new THREE.Vector3(a0, b0, c0),
direction: new THREE.Vector3(x0, y0, z0).normalize()
};
var base = new THREE.Vector3(0, 0, 0)
.crossVectors(l0.direction, direction)
.normalize();
var orderedpoints = [];
// other lines // if inter, return location + angle
for (var j = 0; j < points.length; j++) {
var a1 = points[j].x;
var b1 = points[j].y;
var c1 = points[j].z;
var x1 = points[j].x - reference.x;
var y1 = points[j].y - reference.y;
var z1 = points[j].z - reference.z;
var l1 = {
origin: new THREE.Vector3(a1, b1, c1),
direction: new THREE.Vector3(x1, y1, z1).normalize()
};
var x = l0.direction.dot(l1.direction);
var y = base.dot(l1.direction);
var thetaAngle = Math.atan2(y, x);
var theta = thetaAngle * (180 / Math.PI);
orderedpoints.push({
'angle': theta,
'point': l1.origin,
'xy': {
'x': x,
'y': y
}
});
}
orderedpoints.sort(function(a, b) {
return a.angle - b.angle;
});
return orderedpoints;
};
/*** Exports ***/
var moduleType = typeof module;
if ((moduleType !== 'undefined') && module.exports) {
module.exports = VJS.geometries.slice;
}