@magikcraft/mct1
Version:
Minecraft for Type 1 Diabetes
612 lines (588 loc) • 19.6 kB
text/typescript
import { Vector3, Direction } from '@magikcraft/mct1/vector3'
import * as util from 'utils'
interface iRegion {
vectorA: Vector3
vectorB: Vector3
world: string
name: string
constructor(vectorA: Vector3, vectorB: Vector3, name?: string)
toArray(): Array<number[]>
toString(): string
xArray(): Array<number>
yArray(): Array<number>
zArray(): Array<number>
contains(sampleVector): boolean
getSmallestPoint(): Vector3
getLargestPoint(): Vector3
getCenterPoint(): Vector3
getSize(): Vector3
randomPoint(): Vector3
randomPoints(amount: number): Array<Vector3>
closestPoint(location: Vector3): Vector3
distToClosestPoint(location: Vector3): number
AreOverlaping(regionA: iRegion, regionB): Boolean
Alter(
region: Region,
amount: number,
direction?: Direction | Array<Direction>
): Region
Expand(
region: Region,
amount?: number,
direction?: Direction | Array<Direction>
): Region
Contract(
region: Region,
amount?: number,
direction?: Direction | Array<Direction>
): Region
}
/**
* Region
* @constructor
* @param {Vector3} vectorA - First Vector
* @param {Vector3} vectorB - Second Vector
* @param {string} [name] - Optional Name/ID
*
* Creates and instance of a region
*/
export class Region {
vectorA: Vector3 = new Vector3(0, 0, 0, '')
vectorB: Vector3 = new Vector3(0, 0, 0, '')
world: string = ''
name: string = ''
constructor(vectorA, vectorB, world = '', name = '') {
this.vectorA = vectorA || Vector3.zero
this.vectorB = vectorB || Vector3.zero
this.world = world
this.name = name
}
/**
* ToArray
* @return {Array} - Array Region Object
*
* Will create an array from the region object
* >> array -> [ [0,0,0], [0,0,0] ];
*/
toArray(): Array<any> {
return [this.vectorA.toArray(), this.vectorB.toArray()]
}
/**
* FromArray
* @param {Array} array - Given Array
*
* Will return a region object based on the array
*/
FromArray(array: Array<number | string>): Region {
var region = new Region(
new Vector3(array[0][0], array[0][1], array[0][2]),
new Vector3(array[1][0], array[1][1], array[1][2])
)
if (array[0][4]) {
// World in vectorA exists
region.vectorA.world = array[0][4]
}
if (array[0][4]) {
// World in vectorA exists
region.vectorB.world = array[1][4]
}
return region
}
/**
* toString
* @return {string} - String version of region
*
* Will return a string version of the region
*/
toString(): string {
if (this.world == '' && this.name == '') {
// Only vectors given
return (
'[' +
this.vectorA.toString() +
',' +
this.vectorB.toString() +
']'
)
} else if (this.name == '' && this.world != '') {
// No ID given
return (
'[' +
this.vectorA.toString() +
',' +
this.vectorB.toString() +
', ' +
this.world +
']'
)
} else if (this.name != '' && this.world == '') {
// All args where given
return (
'[' +
this.vectorA.toString() +
',' +
this.vectorB.toString() +
', (Name)' +
this.world +
']'
)
} else {
return (
'[' +
this.vectorA.toString() +
',' +
this.vectorB.toString() +
', ' +
this.world +
', ' +
this.name +
']'
)
}
}
/**
* xArray
* @returns {Array} - X real space array
*
* Returns an array with all points that the array
* exists in on the x axis
* >> [ 201, 202, 203... ]
*/
xArray(): Array<number> {
var smallestBounds = this.getSmallestPoint()
var regionSize = this.getSize()
var returnable: Array<number> = []
for (var i = 0; i < regionSize.x; i++) {
returnable.push(smallestBounds.x + i)
}
return returnable
}
/**
* yArray
* @returns {Array} - Y real space array
*
* Returns an array with all points that the array
* exists in on the y axis
* >> [ 201, 202, 203... ]
*/
yArray(): Array<number> {
var smallestBounds = this.getSmallestPoint()
var regionSize = this.getSize()
var returnable: Array<number> = []
for (var i = 0; i < (regionSize.y || 1); i++) {
returnable.push(smallestBounds.y + i)
}
return returnable
}
/**
* xArray
* @returns {Array} - X real space array
*
* Returns an array with all points that the array
* exists in on the x axis
* >> [ 201, 202, 203... ]
*/
zArray(): Array<number> {
var smallestBounds = this.getSmallestPoint()
var regionSize = this.getSize()
var returnable: Array<number> = []
for (var i = 0; i < (regionSize.z || 1); i++) {
returnable.push(smallestBounds.z + i)
}
return returnable
}
/**
* xLength
* @returns {number} - The length of the region in the x axis
*
* Will calculate the length of the the x axis of the region
*/
xLength(): number {
return Math.abs(this.vectorA.x - this.vectorB.x)
}
/**
* yLength
* @returns {number} - The length of the region in the y axis
*
* Will calculate the length of the the y axis of the region
*/
yLength(): number {
return Math.abs(this.vectorA.y - this.vectorB.y)
}
/**
* zLength
* @returns {number} - The length of the region in the z axis
*
* Will calculate the length of the the z axis of the region
*/
zLength(): number {
return Math.abs(this.vectorA.z - this.vectorB.z)
}
/**
* contains
* @param {Vector3} sampleVector - Point to compare against the region
* @returns {boolean} - True of False if the point is in the region
*
* Sample the region to see if the vector is in the region
*/
contains(sampleVector: Vector3): boolean {
if (this.world == sampleVector.world) {
if (
(sampleVector.x || 0) < Math.min(this.vectorA.x, this.vectorB.x)
) {
return false
} else if (
(sampleVector.x || 0) > Math.max(this.vectorA.x, this.vectorB.x)
) {
return false
} else if (
(sampleVector.y || 0) < Math.min(this.vectorA.y, this.vectorB.y)
) {
return false
} else if (
(sampleVector.y || 0) > Math.max(this.vectorA.y, this.vectorB.y)
) {
return false
} else if (
(sampleVector.z || 0) < Math.min(this.vectorA.z, this.vectorB.z)
) {
return false
} else if (
(sampleVector.z || 0) > Math.max(this.vectorA.z, this.vectorB.z)
) {
return false
} else {
return true
}
} else {
return false
}
}
/**
* getSmallestPoint
* @return {Vector3} - Smallest Point
*
* This will get the smallest component point of the region
* >> [[26,43,78], [12,42,25]] => [12,42,25]
*/
getSmallestPoint(): Vector3 {
return new Vector3(
Math.min(this.vectorA.x, this.vectorB.x),
Math.min(this.vectorA.y, this.vectorB.y),
Math.min(this.vectorA.z, this.vectorB.z),
this.world
)
}
/**
* getLargestPoint
* @return {Vector3} - Largest Point
*
* This will get the largest component point of the region
* >> [[26,43,78], [12,42,25]] => [26,43,78]
*/
getLargestPoint(): Vector3 {
return new Vector3(
Math.max(this.vectorA.x, this.vectorB.x),
Math.max(this.vectorA.y, this.vectorB.y),
Math.max(this.vectorA.z, this.vectorB.z),
this.world
)
}
/**
* getCenterPoint
* @return {Vector3} - Center point of the region
*
* Returns the center point of the region as a vector3
*/
getCenterPoint(): Vector3 {
var smallestPoint = this.getSmallestPoint()
var size = this.getSize()
return new Vector3(
smallestPoint.x + size.x / 2,
smallestPoint.y + size.y / 2,
smallestPoint.z + size.z / 2,
this.world
)
}
/**
* getWorld
* @param {boolean} [worldObj] - Optional bool to export world name
*/
getWorld(worldObj?: boolean): string | any {
this._unifyWorldNames()
worldObj = worldObj || false
if (worldObj) {
return util.world(this.world)
} else {
return this.world
}
}
/**
* getSize
* @return {Vector3} - Size as vector
*
* Will return the size of the region as a vector
*/
getSize() {
return new Vector3(
Math.abs(this.vectorA.x - this.vectorB.x),
Math.abs(this.vectorA.y - this.vectorB.y),
Math.abs(this.vectorA.z - this.vectorB.z),
this.world
)
}
/**
* randomPoint
* @return {Vector3} - Point in region space
*
* Will get a random point inside the region
*/
randomPoint() {
var regionSize = this.getSize() // << Returns Vector3
var smallestPoint = this.getSmallestPoint()
var vec = new Vector3(
Math.round(smallestPoint.x + Math.random() * (regionSize.x || 0)),
Math.round(smallestPoint.y + Math.random() * (regionSize.y || 0)),
Math.round(smallestPoint.z + Math.random() * (regionSize.z || 0)),
this.world
)
return vec
}
/**
* randomPoints
* @param {number} [amount] - Number of coords to return
* @return {Array} - Points in region space (Vector3 Array)
*
* Will create an array of Vector3 points within the region
*/
randomPoints(amount): Array<Vector3> {
amount = amount || 1
if (amount == 0) {
return [this.randomPoint()]
} else {
var coords: Array<Vector3> = []
for (var i = 0; i < amount; i++) {
coords.push(this.randomPoint())
}
return coords
}
}
/**
* closestPoint
* @param {Vector3} location - Given location as vector3
* @return {Vector3} - Closest point in region to location
*
* Will return the closest position to the location
* within the region.
*
* Location: [24,18,36]
* Region: [[62,632,2], [23,63,10]]
* >> Closest Point: [24,63,10]
*/
closestPoint(location: Vector3): Vector3 {
// Test to see if the location is in the region first
// Less computation for the engine to do
if (this.contains(location)) {
// The location is in the region
return location
} else {
// Get all of the closet points in panes
var locationArray = location.toArray()
var greatestBounds = this.getLargestPoint().toArray // << Vector3 Returns
var smallestBounds = this.getSmallestPoint().toArray // << Vector3 Returns
var arrayPositions: Array<number[]> = []
for (var a = 0; a < 3; a++) {
// Check through all axis's
// If the location is greater than the greatest bounds
if (location[a] > greatestBounds[a]) {
arrayPositions.push([greatestBounds[a]])
// If the location is smaller than the smallest bounds
} else if (location[a] < smallestBounds[a]) {
arrayPositions.push([smallestBounds[a]])
// The location must be within the bounds.
} else {
// Depending on the iteration, get the appropiate axis's array
switch (a) {
case 0:
arrayPositions.push(this.xArray())
break
case 1:
arrayPositions.push(this.yArray())
break
case 2:
arrayPositions.push(this.zArray())
break
default:
break
}
}
}
// Test for the closest point
var closestPoint: Vector3 = new Vector3(
Infinity,
Infinity,
Infinity,
this.world
)
var closestDist: number = Infinity
for (var x = 0; x < arrayPositions[0].length; x++) {
for (var y = 0; y < arrayPositions[1].length; y++) {
for (var z = 0; z < arrayPositions[2].length; z++) {
// If the distance between the two points is the least
// so far, replace the closest point
var testPoint = new Vector3(
arrayPositions[0][x],
arrayPositions[1][y],
arrayPositions[2][z],
this.world
)
var testDist = Vector3.Distance(testPoint, location)
if (testDist < closestDist) {
closestDist = testDist
closestPoint = testPoint
}
}
}
}
return closestPoint
}
}
/**
* distToClosestPoint
* @param {Vector3} location - Given location as vector3
* @return {number} - Distance to point
*
* Will return the distance to the closest point in the region
* Refer to closestPoint
*/
distToClosestPoint(location: Vector3): number {
return Vector3.Distance(this.closestPoint(location), location)
}
/**
* AreOverlaping
* @param {Region} regionA - First Region
* @param {Region} regionB - Second Region
* @return {boolean} - True if the regions overlap
*
* Will return true if the regions overlap
*/
AreOverlaping(regionA: Region, regionB): Boolean {
var centerB = regionB.getCenterPoint()
var queryPoint = regionA.closestPoint(centerB)
return regionB.isIn(queryPoint) ? true : false
}
Alter(region: Region, amount: number, direction?: any): Region {
if (!direction) {
// Change in all directions
var smallestVector: Vector3 = region.getSmallestPoint()
var largestVector: Vector3 = region.getLargestPoint()
var alterVector: Vector3 = new Vector3(
1 * amount,
1 * amount,
1 * amount
)
var vectorA = Vector3.Minus(smallestVector, alterVector)
var vectorB = Vector3.Add(largestVector, alterVector)
return new Region(vectorA, vectorB)
} else if (!direction[0]) {
// Not array, but direction given
var smallestVector: Vector3 = region.getSmallestPoint()
var largestVector: Vector3 = region.getLargestPoint()
if (direction == Direction.UP) {
smallestVector.y = Math.max(
0,
Math.min(largestVector.y + amount, 128)
)
} else if (direction == Direction.EAST) {
largestVector.x += amount
return new Region(smallestVector, largestVector)
} else if (direction == Direction.NORTH) {
largestVector.z += amount
return new Region(smallestVector, largestVector)
} else if (direction == Direction.DOWN) {
smallestVector.y = Math.max(
0,
Math.min(smallestVector.y - amount, 128)
)
return new Region(smallestVector, largestVector)
} else if (direction == Direction.SOUTH) {
smallestVector.x -= amount
return new Region(smallestVector, largestVector)
} else if (direction == Direction.WEST) {
smallestVector.z -= amount
return new Region(smallestVector, largestVector)
} else {
return this.Alter(region, amount)
}
} else {
// Has to be array
// Do the operation[0],
// If last, return, else remove [0] and try again
var _region = this.Alter(
region,
amount,
direction[direction.length - 1]
)
if (direction.length == 1) {
return _region
} else {
return this.Alter(_region, amount, direction.pop())
}
}
return region
}
Expand(
region: Region,
amount?: number,
direction?: Direction | Array<Direction>
): Region {
amount = Math.abs(amount || 1)
return this.Alter(region, amount, direction)
}
Contract(
region: Region,
amount?: number,
direction?: Direction | Array<Direction>
): Region {
amount = -Math.abs(amount || 1)
return this.Alter(region, amount, direction)
}
/**
* _unifyWorldNames
*
* Fixes and unifies the names for regions
* Criticaly important
*/
private _unifyWorldNames() {
if (this.world == '') {
var worldA = this.vectorA.world || ''
var worldB = this.vectorA.world || ''
if (worldA == '' && worldB == '') {
// No world is given in the regions
// Just give it a null world
this.vectorA.world = ''
this.vectorB.world = ''
this.world = ''
} else if (worldA == '') {
// World B as the given world
// Assign the region and vectorA worlds to vectorB's world
this.vectorA.world = worldB
this.world = worldB
return worldB
} else if (worldB == '') {
// World A as the given world
// Assign the region and vectorB worlds to vectorA's world
this.vectorB.world = worldA
this.world = worldA
return worldA
} else if (worldB == worldA) {
// Both worlds have the same name
// Assign the region world to the two vectors one's
this.world = worldA
}
} else {
this.vectorA.world = this.world
this.vectorB.world = this.world
}
}
}