Skip to content

Commit 65d5bbc

Browse files
committed
fix: π cloud lobes now sit entirely above/below the nodal plane
- Each lobe is a half-ellipse starting at the plane, bulging outward, returning to the plane (h = sin(θ), not cos(θ)) - The nodal plane between the two lobes is never filled - Lobes connect the p-orbital contributions of adjacent atoms
1 parent b192e63 commit 65d5bbc

1 file changed

Lines changed: 23 additions & 22 deletions

File tree

‎src/render/pi-systems.ts‎

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -164,23 +164,24 @@ export function renderPiSystems(
164164
}
165165
}
166166

167-
// Build a full π-cloud geometry: two thick, rounded lobes (above and
168-
// below the molecular plane) that span the spine of atom centers.
169-
//
170-
// Each lobe is a surface of revolution around the spine — a half-ellipse
171-
// profile swept along the curve. The lobes are fat at each atom center
172-
// and taper smoothly between them, giving the cloud a "bumpy" appearance
173-
// that mirrors the underlying p-orbital contributions.
167+
// Build a π-cloud geometry: two separate rounded lobes — one above, one
168+
// below the molecular plane — each connecting the corresponding p-orbital
169+
// lobes of adjacent atoms. The gap at the molecular plane is the p-orbital
170+
// node. Each lobe is a half-ellipse cross-section (sitting entirely on one
171+
// side of the plane) swept along the spine.
174172
function buildCloudGeometry(spine: THREE.Curve<THREE.Vector3>, piDir: THREE.Vector3): THREE.BufferGeometry {
175173
const N = 48; // samples along spine
176-
const M = 16; // angular samples around each lobe cross-section
177-
const lobeHeight = 0.7; // how far above/below the plane the cloud extends
178-
const lobeWidth = 0.55; // in-plane half-width of the cloud at atom centers
174+
const M = 20; // angular samples around the half-ellipse cross-section
175+
const lobeHeight = 0.65; // how far above/below the plane the cloud extends
176+
const lobeWidth = 0.50; // in-plane half-width at each cross-section
179177

180178
const positions: number[] = [];
181179
const indices: number[] = [];
182180

183-
// Build two lobes (top and bottom)
181+
// Build two separate lobes — top (+piDir) and bottom (−piDir).
182+
// Each lobe is a half-ellipse that starts at the molecular plane,
183+
// bulges outward, and returns to the plane. The nodal plane (the
184+
// gap between lobes) is never filled.
184185
for (let layer = 0; layer < 2; layer++) {
185186
const sign = layer === 0 ? 1 : -1;
186187
const baseOffset = layer * (N + 1) * (M + 1);
@@ -191,18 +192,18 @@ function buildCloudGeometry(spine: THREE.Curve<THREE.Vector3>, piDir: THREE.Vect
191192
const tangent = spine.getTangent(t).normalize();
192193
const binormal = new THREE.Vector3().crossVectors(tangent, piDir).normalize();
193194

194-
// Cloud thickness profile: fat at atom centers (t=0,1 and near
195-
// atom positions along the spine), tapering smoothly. Use a
196-
// raised-cosine envelope so the cloud is thickest at each atom
197-
// and thinnest between them.
198-
const envelope = 0.5 + 0.5 * Math.cos(2 * Math.PI * t - Math.PI);
199-
const width = lobeWidth * (0.4 + 0.6 * envelope);
200-
const height = lobeHeight * (0.4 + 0.6 * envelope) * sign;
195+
// Thickness profile: fattest at atom centers, thinner between them.
196+
// The raised-cosine envelope gives a smooth bumpy shape.
197+
const envelope = 0.4 + 0.6 * (0.5 + 0.5 * Math.cos(2 * Math.PI * t - Math.PI));
198+
const width = lobeWidth * envelope;
199+
const height = lobeHeight * envelope;
201200

202201
for (let j = 0; j <= M; j++) {
203-
const angle = (j / M) * Math.PI; // 0 → π (half ellipse)
204-
const w = Math.sin(angle) * width; // in-plane spread
205-
const h = Math.cos(angle) * height; // out-of-plane height
202+
// Half-ellipse from θ=0 (right edge at plane) to θ=π (left edge
203+
// at plane). The lobe sits entirely on one side of the plane.
204+
const theta = (j / M) * Math.PI;
205+
const w = Math.cos(theta) * width; // in-plane: +w → −w
206+
const h = Math.sin(theta) * height * sign; // out-of-plane: 0 → max → 0
206207

207208
const v = center.clone()
208209
.addScaledVector(binormal, w)
@@ -211,7 +212,7 @@ function buildCloudGeometry(spine: THREE.Curve<THREE.Vector3>, piDir: THREE.Vect
211212
}
212213
}
213214

214-
// Triangle indices for this lobe's ribbon
215+
// Triangle indices for this lobe
215216
const vertsPerRing = M + 1;
216217
for (let i = 0; i < N; i++) {
217218
for (let j = 0; j < M; j++) {

0 commit comments

Comments
 (0)