[Android Apps and Games] Tamasaka:
Hybrid orbital

This script draws a 3D model of hybridized atomic orbitals for chemistry. The lobe is not a real wave function, but a pseudo model for education.

Parameter 1 is size of lobe in arbitrary unit.

Parameter 2 selects color of lobe from -9 to 9. 0 is black. 1 is white. 2 is light gray. 3 is dark gray. 4 is pale cyan. 5 is light yellow. The lobes of these colors are outlined by black and slightly transparent. 6 is light gray, 7 is dark gray, 8 is pale cyan and 9 is light yellow without outline. Color of negative number (from -1 to -9) fills the lobe with opaque color.

Parameter 3 is fatness of lobe in arbitrary unit. The default value is 0.6. Adequate value is from 0.4 to 1.

Parameter 4 is length of lobe in arbitrary unit. The default value is 0.7. Adequate value is from 0.4 to 1. The combination of fatness and length makes the shape of the lobe.

Parameter 5 is resolution of lobe. The lobe is drawn by superimposed filled circles. The default value of resolution is 12.

Parameter 6 selects hybridization from sp, sp2, sp3, dsp3 or d2sp3.

The center of the orbital i.e. the position of nucleus is snapped to the acadoid's standard grid. The direction of lobe is snapped to every 3 degrees.

/* Hybrid orbital ver. 1.07 */
size = 2;
color = 2;
fatness = 0.6;
length = 0.7;
resolution = 12;
spn = 3;
if (LN.getNumberOfParameters() >= 1)
size = LN.getParameter(1); /* Size, 1.0 ≤ Parameter(1) ≤ 3.0, 5 steps */
if (LN.getNumberOfParameters() >= 2)
color = LN.getParameter(2); /* Color (-9 to 9; 1:w, 2:lg, 3:dg, 4:c, 5:y), -9 ≤ Parameter(2) ≤ 9, 19 steps */
if (LN.getNumberOfParameters() >= 3)
fatness = LN.getParameter(3); /* Fatness (0.4 to 1.0), 0.4 ≤ Parameter(3) ≤ 1.0, 7 steps */
if (LN.getNumberOfParameters() >= 4)
length = LN.getParameter(4); /* Length (0.4 to 1.0), 0.4 ≤ Parameter(4) ≤ 1.0, 7 steps */
if (LN.getNumberOfParameters() >= 5)
resolution = LN.getParameter(5); /* Resolution, 5 ≤ Parameter(5) ≤ 20, 16 steps */
if (LN.getNumberOfParameters() >= 6)
spn = LN.getParameter(6); /* Hybrid (1:sp, 2:sp2, 3:sp3, 4:dsp3, 5:d2sp3), 1 ≤ Parameter(6) ≤ 5, 5 steps */

var xp = new Array(7);
var yp = new Array(7);
var n = [0, 1, 2, 3, 4, 5, 6];
width = LN.getWidth();
scale = LN.getScale();
step = width / 150 + scale * width / 25;
finestep = step / 40;
astep = Math.PI / 60;
lobesize = size * step;
radius = 2 / 3 /Math.sqrt(3) * lobesize;
area = radius * fatness + lobesize * length;

x1 = LN.getX1();
y1 = LN.getY1();
x2 = LN.getX2();
y2 = LN.getY2();

x1 = step/2 + Math.floor((x1 - step/2) / step + 0.5) * step;
y1 = step/2 + Math.floor((y1 - step/2) / step + 0.5) * step;
angle = Math.atan2(y2 - y1, x2 - x1);
ag = Math.floor(angle / astep + 0.5) * astep;
distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
dt = Math.floor(distance / finestep + 0.5) * finestep;
dg = Math.min(dt, lobesize);
dl = dg / lobesize;
twist = Math.PI * Math.min(0.5, Math.max((dt - finestep * 2) / lobesize - 1, 0));

LN.setClip(x1 - area, y1 - area, x1 + area, y1 + area);
LN.setSoftness(1);

phi1 = Math.acos(dl);
sinag = Math.sin(ag);
sinphi1 = Math.sin(phi1);
planeangle = Math.atan2(sinphi1, dl * sinag);
if (dl == 1) {
if (ag == 0)
planeangle = Math.PI;
else if (ag == Math.PI)
planeangle = 0;
}
if (y2 < y1)
ysign = -1;
else
ysign = 1;
alpha1 = Math.asin(Math.sqrt(sinphi1 * sinphi1 + dl * dl * sinag * sinag));
equatorial = (alpha1 < Math.PI * 10/180) ? true : false;
if (x2 < x1)
alpha1 = Math.PI - alpha1;
xp[1] = lobesize * Math.cos(alpha1);
yp[1] = lobesize * Math.sin(alpha1) * Math.cos(planeangle);

if (spn == 1) {
xp[2] = - xp[1];
yp[2] = - yp[1];
}

if (spn == 2) {
alpha2 = alpha1 + Math.PI * 2/3;
alpha3 = alpha1 - Math.PI * 2/3;
if (twist > 0 || dl == 1) {
xm = - xp[1] / 2;
ym = - yp[1] / 2;
xp[2] = xm + lobesize * Math.sqrt(3) / 2 * Math.cos(twist) * Math.cos(ag - Math.PI/2);
yp[2] = ym + lobesize * Math.sqrt(3) / 2 * Math.cos(twist) * Math.sin(ag - Math.PI/2);
xp[3] = 2 * xm - xp[2];
yp[3] = 2 * ym - yp[2];
n[1] = 2;
n[2] = 1;
}
else {
xp[2] = lobesize * Math.cos(alpha2);
yp[2] = lobesize * Math.sin(alpha2) * Math.cos(planeangle);
xp[3] = lobesize * Math.cos(alpha3);
yp[3] = lobesize * Math.sin(alpha3) * Math.cos(planeangle);
if (Math.abs(xp[3]) >= Math.abs(xp[2])) {
n[2] = 3;
n[3] = 2;
}
}
}

if (spn == 3) {
alpha2 = alpha1 + 2.1863;
alpha3 = alpha1 - 1.9106;
alpha4 = alpha1 + 2.1863;
if (twist > 0 || dl == 1) {
xm = - xp[1] / 3;
ym = - yp[1] / 3;
if (equatorial) {
xp[2] = xm + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - ysign * alpha1 * 3 + Math.PI/6) * Math.cos(ag - Math.PI/2);
yp[2] = ym + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - ysign * alpha1 * 3 + Math.PI/6) * Math.sin(ag - Math.PI/2);
xp[3] = xm + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - ysign * alpha1 * 3 - Math.PI/2) * Math.cos(ag - Math.PI/2);
yp[3] = ym + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - ysign * alpha1 * 3 - Math.PI/2) * Math.sin(ag - Math.PI/2);
if (x2 < x1) {
n[1] = 3;
n[2] = 1;
n[3] = 4;
n[4] = 2;
}
else {
n[3] = 4;
n[4] = 3;
}
}
else {
xp[2] = xm + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - (ysign-1)/2 * Math.PI/3) * Math.cos(ag - Math.PI/2);
yp[2] = ym + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 - (ysign-1)/2 * Math.PI/3) * Math.sin(ag - Math.PI/2);
xp[3] = xm + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 + (5-ysign)/6 * Math.PI) * Math.cos(ag - Math.PI/2);
yp[3] = ym + lobesize * Math.sqrt(2/3) * Math.cos(twist*2/3 + (5-ysign)/6 * Math.PI) * Math.sin(ag - Math.PI/2);
}
xp[4] = 3 * xm - xp[2] - xp[3];
yp[4] = 3 * ym - yp[2] - yp[3];
}
else {
xp[3] = lobesize * Math.cos(alpha3);
yp[3] = lobesize * Math.sin(alpha3) * Math.cos(planeangle);
xm2 = -(xp[1] + xp[3]) / 2;
ym2 = -(yp[1] + yp[3]) / 2;
xp[2] = xm2;
yp[2] = ym2 + lobesize * Math.sin(1.9106 / 2) * Math.cos(planeangle + Math.PI/2);
xp[4] = xm2;
yp[4] = 2 * ym2 - yp[2];
if (Math.abs(ag) > Math.PI/4) {
n[2] = 3;
if (y2 < y1) {
n[3] = 4;
n[4] = 2;
}
else {
n[3] = 2;
n[4] = 4;
}
}
else {
n[4] = 3;
if (y2 < y1) {
n[2] = 4;
n[3] = 2;
}
else {
n[2] = 2;
n[3] = 4;
}
}
}
}

if (spn == 4) {
alpha4 = alpha1 + Math.PI * 2/3;
alpha5 = alpha1 - Math.PI * 2/3;
if (twist > 0 || dl == 1) {
xm = - xp[1] / 2;
ym = - yp[1] / 2;
xp[4] = xm + lobesize * Math.sqrt(3) / 2 * Math.cos(twist) * Math.cos(ag - Math.PI/2);
yp[4] = ym + lobesize * Math.sqrt(3) / 2 * Math.cos(twist) * Math.sin(ag - Math.PI/2);
xp[5] = 2 * xm - xp[4];
yp[5] = 2 * ym - yp[4];
xp[2] = lobesize * Math.sin(twist) * Math.cos(ag - Math.PI/2);
yp[2] = lobesize * Math.sin(twist) * Math.sin(ag - Math.PI/2);
xp[3] = - xp[2];
yp[3] = - yp[2];
n[3] = 1;
if (twist < Math.PI/4) {
n[1] = 2;
n[2] = 4;
n[4] = 5;
n[5] = 3;
}
else {
n[1] = 5;
n[2] = 2;
n[4] = 3;
n[5] = 4;
}
}
else {
xp[4] = lobesize * Math.cos(alpha4);
yp[4] = lobesize * Math.sin(alpha4) * Math.cos(planeangle);
xp[5] = lobesize * Math.cos(alpha5);
yp[5] = lobesize * Math.sin(alpha5) * Math.cos(planeangle);
xp[2] = 0;
yp[2] = lobesize * Math.sin(planeangle);
xp[3] = 0;
yp[3] = - yp[2];
if (Math.abs(xp[5]) > Math.abs(xp[4])) {
n[5] = 4;
n[4] = 5;
}
if (Math.abs(yp[5]) > Math.abs(yp[3]) || Math.abs(yp[4]) > Math.abs(yp[3]) ) {
n[1] = 2;
n[2] = 1;
n[3] = 4;
n[4] = 5;
n[5] = 3;
if (yp[1] > 0) {
n[1] = 3;
n[5] = 2;
}
}
}
}

if (spn == 5) {
xp[6] = - xp[1];
yp[6] = - yp[1];
if (twist > 0 || dl == 1) {
xp[2] = lobesize * Math.sin(twist / 2) * Math.cos(ag - Math.PI/2);
yp[2] = lobesize * Math.sin(twist / 2) * Math.sin(ag - Math.PI/2);
xp[3] = lobesize * Math.sin(twist / 2 - Math.PI/2) * Math.cos(ag - Math.PI/2);
yp[3] = lobesize * Math.sin(twist / 2 - Math.PI/2) * Math.sin(ag - Math.PI/2);
xp[4] = - xp[3];
yp[4] = - yp[3];
xp[5] = - xp[2];
yp[5] = - yp[2];
n[1] = 2;
n[2] = 3;
n[3] = 1;
n[4] = 6;
n[5] = 4;
n[6] = 5;
}
else {
xp[3] = lobesize * Math.cos(alpha1 + Math.PI/2);
yp[3] = lobesize * Math.sin(alpha1 + Math.PI/2) * Math.cos(planeangle);
xp[4] = - xp[3];
yp[4] = - yp[3];
xp[2] = 0;
yp[2] = lobesize * Math.sin(planeangle);
xp[5] = 0;
yp[5] = - yp[2];
if (Math.abs(xp[1]) > Math.abs(xp[3])) {
n[1] = 3;
n[2] = 1;
n[3] = 2;
n[4] = 5;
n[5] = 6;
n[6] = 4;
if (xp[1] < 0) {
n[1] = 4;
n[6] = 3;
}
}
if (Math.abs(yp[1]) > Math.abs(yp[2]) || Math.abs(yp[3]) > Math.abs(yp[2]) ) {
n[1] = 2;
n[2] = 1;
n[3] = 3;
n[4] = 4;
n[5] = 6;
n[6] = 5;
if (yp[1] > 0) {
n[1] = 5;
n[6] = 2;
}
}
}
}

for (k = spn + 1; k > 0; k--) {
drawColorLobe (x1, y1, xp[n[k]], yp[n[k]], lobesize, fatness, length, resolution, color);
}

function drawColorLobe (x0, y0, xp, yp, lsize, fat, len, res, col) {
if (col < 0) {
opaque = true;
col = -col;
}
else
opaque = false;
if (col >= 6) {
outline = false;
col = col - 4;
}
else
outline = true;
setLobeColor(col);
if (outline)
LN.setColor(0, 0, 0);
if (! opaque)
LN.setAlpha(0.7);
drawLobe(x0, y0, xp, yp, lsize, fat, len, res);
if (outline && col >= 1) {
setLobeColor(col);
if (! opaque) {
if (col == 1)
LN.setAlpha(0);
else
LN.setAlpha(0.7);
}
drawLobe(x0, y0, xp, yp, lsize, fat * 0.95, len, res);
}
}

function drawLobe(x0, y0, xp, yp, ls, fa, le, re) {
dp = 0;
ps = ls / re;
xs = xp / re;
ys = yp / re;
fll = fa / ls / ls;
for (var i = 1; i < re * le; i++) {
dp += ps;
r = Math.abs(dp * (dp - ls) * (dp + ls) * fll);
LN.drawFilledCircle(x0 += xs, y0 += ys, r);
}
}

function setLobeColor(co) {
switch (co) {
default:
case 0:
LN.setColor(0, 0, 0);
break;
case 1:
LN.setColor(1, 1, 1);
break;
case 2:
LN.setColor(0.95, 0.95, 0.95);
break;
case 3:
LN.setColor(0.8, 0.8, 0.8);
break;
case 4:
LN.setColor(0.8, 1, 1);
break;
case 5:
LN.setColor(1, 1, 0.7);
break;
}
}