scripts/items/wall_item.js
import {Vector2, Vector3} from 'three';
import {EVENT_DELETED} from '../core/events.js';
import {Utils} from '../core/utils.js';
import {Item} from './item.js';
/**
* A Wall Item is an entity to be placed related to a wall.
*/
export class WallItem extends Item
{
constructor(model, metadata, geometry, material, position, rotation, scale, isgltf=false)
{
super(model, metadata, geometry, material, position, rotation, scale, isgltf);
/** The currently applied wall edge. */
this.currentWallEdge = null;
/* TODO:
This caused a huge headache.
HalfEdges get destroyed/created every time floorplan is edited.
This item should store a reference to a wall and front/back,
and grab its edge reference dynamically whenever it needs it.
*/
/** used for finding rotations */
this.refVec = new Vector2(0, 1.0);
/** */
this.wallOffsetScalar = 0;
/** */
this.sizeX = 0;
/** */
this.sizeY = 0;
/** */
this.addToWall = false;
/** */
this.boundToFloor = false;
/** */
this.frontVisible = false;
/** */
this.backVisible = false;
this.allowRotate = false;
}
/** Get the closet wall edge.
* @returns The wall edge.
*/
closestWallEdge()
{
var wallEdges = this.model.floorplan.wallEdges();
var wallEdge = null;
var minDistance = null;
var itemX = this.position.x;
var itemZ = this.position.z;
wallEdges.forEach((edge) => {
var distance = edge.distanceTo(itemX, itemZ);
if (minDistance === null || distance < minDistance)
{
minDistance = distance;
wallEdge = edge;
}
});
return wallEdge;
}
/** */
removed()
{
if (this.currentWallEdge != null && this.addToWall)
{
Utils.removeValue(this.currentWallEdge.wall.items, this);
this.redrawWall();
}
}
/** */
redrawWall()
{
if (this.addToWall)
{
this.currentWallEdge.wall.fireRedraw();
}
}
/** */
updateEdgeVisibility(visible, front)
{
if (front)
{
this.frontVisible = visible;
}
else
{
this.backVisible = visible;
}
this.visible = (this.frontVisible || this.backVisible);
}
/** */
updateSize()
{
this.wallOffsetScalar = (this.geometry.boundingBox.max.z - this.geometry.boundingBox.min.z) * this.scale.z / 2.0;
this.sizeX = (this.geometry.boundingBox.max.x - this.geometry.boundingBox.min.x) * this.scale.x;
this.sizeY = (this.geometry.boundingBox.max.y - this.geometry.boundingBox.min.y) * this.scale.y;
}
/** */
resized()
{
if (this.boundToFloor)
{
this.position.y = 0.5 * (this.geometry.boundingBox.max.y - this.geometry.boundingBox.min.y) * this.scale.y + 0.01;
}
this.updateSize();
this.redrawWall();
}
/** */
placeInRoom()
{
var closestWallEdge = this.closestWallEdge();
this.changeWallEdge(closestWallEdge);
this.updateSize();
if (!this.position_set)
{
// position not set
var center = closestWallEdge.interiorCenter();
var newPos = new Vector3(center.x, closestWallEdge.wall.height / 2.0, center.y);
this.boundMove(newPos);
this.position.copy(newPos);
this.redrawWall();
}
}
/** */
moveToPosition(vec3, intersection)
{
var intersectionEdge = (intersection) ? (intersection.object) ? intersection.object.edge: intersection : this.closestWallEdge();
this.changeWallEdge(intersectionEdge);
this.boundMove(vec3);
// this.position.copy(vec3);
super.moveToPosition(vec3);
this.redrawWall();
}
/** */
getWallOffset()
{
return this.wallOffsetScalar;
}
/** */
changeWallEdge(wallEdge)
{
if (this.currentWallEdge != null)
{
if (this.addToWall)
{
Utils.removeValue(this.currentWallEdge.wall.items, this);
this.redrawWall();
}
else
{
Utils.removeValue(this.currentWallEdge.wall.onItems, this);
}
}
var scope = this;
function __remove(event)
{
scope.remove(event.item);
}
// handle subscription to wall being removed
if (this.currentWallEdge != null)
{
// this.currentWallEdge.wall.dontFireOnDelete(this.remove.bind(this));
this.currentWallEdge.wall.removeEventListener(EVENT_DELETED, __remove);
}
// wallEdge.wall.fireOnDelete(this.remove.bind(this));
wallEdge.wall.addEventListener(EVENT_DELETED, __remove);
// find angle between wall normals
var normal2 = new Vector2();
var normal3 = wallEdge.plane.geometry.faces[0].normal;
normal2.x = normal3.x;
normal2.y = normal3.z;
var angle = Utils.angle( new Vector2(this.refVec.x, this.refVec.y), new Vector2(normal2.x, normal2.y));
this.rotation.y = angle;
// update currentWall
this.currentWallEdge = wallEdge;
if (this.addToWall)
{
wallEdge.wall.items.push(this);
this.redrawWall();
}
else
{
wallEdge.wall.onItems.push(this);
}
}
/** Returns an array of planes to use other than the ground plane
* for passing intersection to clickPressed and clickDragged */
customIntersectionPlanes()
{
return this.model.floorplan.wallEdgePlanes();
}
/** takes the move vec3, and makes sure object stays bounded on plane */
boundMove(vec3)
{
var tolerance = 1;
var edge = this.currentWallEdge;
vec3.applyMatrix4(edge.interiorTransform);
if (vec3.x < this.sizeX / 2.0 + tolerance)
{
vec3.x = this.sizeX / 2.0 + tolerance;
}
else if (vec3.x > (edge.interiorDistance() - this.sizeX / 2.0 - tolerance))
{
vec3.x = edge.interiorDistance() - this.sizeX / 2.0 - tolerance;
}
if (this.boundToFloor)
{
vec3.y = 0.5 * (this.geometry.boundingBox.max.y - this.geometry.boundingBox.min.y) * this.scale.y + 0.01;
}
else
{
if (vec3.y < this.sizeY / 2.0 + tolerance)
{
vec3.y = this.sizeY / 2.0 + tolerance;
}
else if (vec3.y > edge.height - this.sizeY / 2.0 - tolerance)
{
vec3.y = edge.height - this.sizeY / 2.0 - tolerance;
}
}
vec3.z = this.getWallOffset();
vec3.applyMatrix4(edge.invInteriorTransform);
}
}