"use strict";
/**
* Utility-Klasse, um für Klassen-Instanzen konstante Eigenschaften zu definieren.
*/
class Const {
static create(_o, _name, _value) {
Object.defineProperty(
_o,
_name, {
value: _value,
writable: false
}
);
}
}
class Triangle {
constructor(_edges) {
Const.create(this, "countEdges", 3);
if(_edges.length != this.countEdges)
throw "a triangle must consist of " + this.countEdges + " edges";
var edges = [];
for(let i = 0; i < this.countEdges; ++i) {
if(!(_edges[i] instanceof Edge))
throw "value must be of type Edge";
edges[i] = _edges[i];
}
// Normale auf Dreieck:
let v0 = edges[0].asVector().normalize();
let v1 = edges[2].asVector(true).normalize();
var normal = v0.cross(v1);
// öffentliche Methoden:
this.getEdge = function(i) {
if(!Number.isInteger(i) || i < 0 || i >= this.countEdges)
throw "index must be 0 to " + (this.countEdges - 1);
return edges[i];
};
/**
* @return string
*/
this.toString = function() {
return "{" + edges[0].toString() + " " + edges[1].toString() + " " + edges[2].toString() + "}";
};
}
}
class Edge {
/**
* @param Vertex _from
* @param Vertex _to
*/
constructor(_from, _to) {
Const.create(this, "countVertices", 2);
// private Methoden:
var check = function(_vertex) {
if(!(_vertex instanceof Vertex))
throw "value must be of type Vertex";
return _vertex;
};
var vertices = [];
vertices[0] = check(_from);
vertices[1] = check(_to);
// öffentliche Methoden:
this.getVertex = function(_i) {
if(!Number.isInteger(_i) || _i < 0 || _i >= this.countVertices)
throw "index must be 0 to " + (this.countVertices - 1);
return vertices[_i];
};
/**
* Kante als Vektor zurückgeben.
* @param boolean _negate ob Vorzeichenwechsel
*/
this.asVector = function(_negate) {
if(_negate === undefined)
_negate = false;
else if(typeof(_negate) !== "boolean")
throw "negate must be of type boolean";
let v0 = vertices[0].w == 1 ? vertices[0] : vertices[0].homogenize();
let v1 = vertices[1].w == 1 ? vertices[1] : vertices[1].homogenize();
return _negate ? v0.minus(v1) : v1.minus(v0);
};
/**
* @return string
*/
this.toString = function() {
return "[" + vertices[0].toString() + " " + vertices[1].toString() + "]";
};
}
}
/**
* Abstrakte Klasse für die Klassen Vector und Vertex.
*/
class AVector {
constructor(_x, _y, _z) {
// öffentliche Methoden:
this.check = function(_v) {
if(isNaN(_v))
throw "value must be number";
return _v;
};
// private Eigenschaften:
var x = this.check(_x);
var y = this.check(_y);
var z = this.check(_z);
// öffentliche Methoden:
this.check = function(_v) {
if(isNaN(_v))
throw "value must be number";
return _v;
};
this.getX = function() {
return x;
};
this.getY = function() {
return y;
};
this.getZ = function() {
return z;
};
this.setX = function(_x) {
x = this.check(_x);
};
this.setY = function(_y) {
y = this.check(_y);
};
this.setZ = function(_z) {
z = this.check(_z);
};
}
// setter/getter:
set x(_x) {
this.setX(_x);
}
set y(_y) {
this.setY(_y);
}
set z(_z) {
this.setZ(_z);
}
get x() {
return this.getX();
}
get y() {
return this.getY();
}
get z() {
return this.getZ();
}
}
/**
* Ein Vektor besteht aus den Komponenten x, y und z.
* Ein Vektor ist eine Richtungsangabe.
*/
class Vector extends AVector {
/**
* @param number _x
* @param number _y
* @param number _z
*/
constructor(_x, _y, _z) {
super(_x, _y, _z);
/**
* @return number
*/
this.length = function() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
};
/**
* @param boolean _self optionell, ob dieser Vektor selbst normalisiert werden soll
* @return Vector
*/
this.normalize = function(_self) {
if(_self === undefined)
_self = false;
else if(typeof(_self) !== "boolean")
throw "self must be of type boolean";
let length = this.length();
if(length == 0)
throw "0-vector can´t be normalized";
if(_self) {
this.x /= length;
this.y /= length;
this.z /= length;
}
else return new Vector(
this.x / length,
this.y / length,
this.z / length
);
};
/**
* Cross-Produkt zwischen 2 Vectoren.
* @param Vector _other
* @return Vector
*/
this.cross = function(_other) {
if(!(_other instanceof Vector))
throw "other must be of type Vector";
return new Vector(
this.y * _other.z - this.z * _other.y,
this.z * _other.x - this.x * _other.z,
this.x * _other.y - this.y * _other.x
);
};
/**
* @return string
*/
this.toString = function() {
return "(" + this.x + " " + this.y + " " + this.z + ")";
};
}
}
/**
* Ein Vertex besteht aus den Komponenten x, y, z und w.
* Ein Vertex ist eine Positionsangabe.
*/
class Vertex extends AVector {
/**
* @param number _x
* @param number _y
* @param number _z
* @param number _w
*/
constructor(_x, _y, _z, _w) {
super(_x, _y, _z);
var w = _w === undefined ? 1 : this.check(_w); // darf die homogene Komponente auch negativ werden?
// Normale auf Vertex vorbereiten:
var normal = new Vector(0, 0, 0);
// öffentliche Methoden:
this.getW = function() {
return w;
};
this.setW = function(_w) {
w = this.check(_w);
};
/**
* @param boolean _self optionell, ob dieser Vertex selbst homogenisiert werden soll
* @return Vertex
*/
this.homogenize = function(_self) {
if(_self === undefined)
_self = false;
else if(typeof(_self) !== "boolean")
throw "self must be of type boolean";
if(this.w == 0)
throw "a vector with w = 0 can´t be homogenized";
if(_self) {
this.x /= this.w;
this.y /= this.w;
this.z /= this.w;
}
else return new Vertex(
this.x / this.w,
this.y / this.w,
this.z / this.w
);
};
/**
* Ein Vertex minus einem Vertex ergibt einen Vektor.
* @param Vertex _other
* @return Vector
*/
this.minus = function(_other) {
if(!(_other instanceof Vertex))
throw "other must be of type Vertex";
let v0 = this.w == 1 ? this : this.homogenize();
let v1 = _other.w == 1 ? _other : _other.homogenize();
return new Vector(
v0.x - v1.x,
v0.y - v1.y,
v0.z - v1.z
);
};
/**
* @return string
*/
this.toString = function() {
return "(" + this.x + " " + this.y + " " + this.z + " " + this.w + ")";
};
}
get w() {
return this.getW();
}
set w(_w) {
this.setW(_w);
}
}
var v0 = new Vertex(1, 0, 0);
var v1 = new Vertex(0, 0, 0);
var v2 = new Vertex(0, 0, 1);
var e0 = new Edge(v0, v1);
var e1 = new Edge(v1, v2);
var e2 = new Edge(v2, v0);
var t = new Triangle([e0, e1, e2]);
alert(t.toString());