diff options
| author | victor | 2026-10-24 15:57:01 +0200 |
|---|---|---|
| committer | victor | 2026-10-24 15:57:01 +0200 |
| commit | 4533910bce394e7a0ee6debfc05ca1221ee51899 (patch) | |
| tree | 73aaa5b2c7a48dbf226e6b81d499ba1a8ecc33a1 /src/models/electric-flux/physics.ts | |
| parent | Tilføj dansk (diff) | |
| download | 3D-Electrophysics-ny-start.tar.gz 3D-Electrophysics-ny-start.zip | |
Astra!ny-start
Diffstat (limited to '')
| -rw-r--r-- | src/models/electric-flux/physics.ts | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/models/electric-flux/physics.ts b/src/models/electric-flux/physics.ts new file mode 100644 index 0000000..78c21d0 --- /dev/null +++ b/src/models/electric-flux/physics.ts @@ -0,0 +1,53 @@ +/** All physics values use SI units. No rendering or localization dependencies. */ +export const VACUUM_PERMITTIVITY = 8.8541878128e-12; +export const COULOMB_CONSTANT = 1 / (4 * Math.PI * VACUUM_PERMITTIVITY); + +export type Vector3 = Readonly<{ x: number; y: number; z: number }>; +export type SurfaceShape = 'sphere' | 'cube'; +export type Membership = 'inside' | 'outside' | 'boundary'; + +export interface ClosedSurface { + shape: SurfaceShape; + /** Sphere radius or cube half side length, in metres. Center is the origin. */ + size: number; +} + +export interface PointCharge { + coulombs: number; + position: Vector3; +} + +export function surfaceMembership(position: Vector3, surface: ClosedSurface): Membership { + const distance = surface.shape === 'sphere' + ? Math.hypot(position.x, position.y, position.z) + : Math.max(Math.abs(position.x), Math.abs(position.y), Math.abs(position.z)); + // Absorb floating-point slider arithmetic without hiding a physical boundary region. + if (Math.abs(distance - surface.size) < 1e-9) return 'boundary'; + return distance < surface.size ? 'inside' : 'outside'; +} + +/** Returns null at the singular source of a nonzero ideal point charge. */ +export function electricFieldAt(point: Vector3, charge: PointCharge): Vector3 | null { + if (charge.coulombs === 0) return { x: 0, y: 0, z: 0 }; + const x = point.x - charge.position.x; + const y = point.y - charge.position.y; + const z = point.z - charge.position.z; + const r = Math.hypot(x, y, z); + if (r === 0) return null; + const scale = COULOMB_CONSTANT * charge.coulombs / r ** 3; + return { x: x * scale, y: y * scale, z: z * scale }; +} + +export function measureFlux(charge: PointCharge, surface: ClosedSurface) { + const membership = surfaceMembership(charge.position, surface); + const area = surface.shape === 'sphere' ? 4 * Math.PI * surface.size ** 2 : 24 * surface.size ** 2; + const enclosedCharge = charge.coulombs === 0 ? 0 + : membership === 'boundary' ? null + : membership === 'inside' ? charge.coulombs : 0; + return { + membership, + area, + enclosedCharge, + netFlux: enclosedCharge === null ? null : enclosedCharge / VACUUM_PERMITTIVITY, + }; +} |