arrowBuilder = function( scene, params ) {
const start = [params.startx, params.starty, params.startz];
const end = [params.endx, params.endy, params.endz];
const dir = [params.dirx, params.diry, params.dirz];
let all = function(a: (number|undefined)[]) {
for (let i=0; i<a.length; i++) {
if (a[i] == undefined) {
return 0;
}
}
return 1;
}
const s = all(start)+all(end)+all(dir);
if ( s == 3 ) { throw new Error("Arrow start&end&dir defined -- must define precisely two"); }
if ( s<2 ) { throw new Error("Arrow <2 defined -- must define precisely two"); }
if (all(start) && all(dir)) {
for (let i=0; i<2; i++) {
end[i] = (start[i] || 0) + (dir[i] || 0);
}
}
if (all(end) && all(dir)) {
for (let i=0; i<2; i++) {
start[i] = (end[i] || 0) - (dir[i] || 0);
}
}
if (all(start) && all(end)) {
for (let i=0; i<2; i++) {
dir[i] = (end[i] || 0) - (start[i] || 0);
}
}
const thicknum = (params.thick || 1);
const rnum = (params.colorr || 1);
const gnum = (params.colorg || .5);
const bnum = (params.colorb || .5);
const dv = new Vector3(dir[0]||0, dir[1]||0, dir[2]||0);
const sv = new Vector3(start[0]||0, start[1]||0, start[2]||0);
const shaft = MeshBuilder.CreateCylinder("shaft", {height:dv.length()*4/5, diameter:thicknum}, scene);
const head = MeshBuilder.CreateCylinder("head", {height:dv.length()/5, diameterBottom:1.5*thicknum, diameterTop:0}, scene);
head.position.set(0, dv.length()/2 , 0);
const arrow = Mesh.MergeMeshes([shaft,head]);
if (arrow == null) { throw new Error("Arrow null. "); }
const arrowmat = new StandardMaterial("arrowmat", scene);
arrowmat.ambientColor = new Color3(rnum, gnum, bnum);
arrow.material = arrowmat;
const rotax = new Vector3(dir[2]||0, 0, -(dir[0]||0));
const angle = getAngleBetween(new Vector3(0,1,0), dv);
arrow.rotate(rotax, angle, Space.WORLD);
arrow.position = sv.add(dv.scale(.5));
return {arrow,arrowmat};
}