Как правильно имитировать линии электрического поля ⇐ Javascript
-
Anonymous
Как правильно имитировать линии электрического поля
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
function vec3_add(a, b) {
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
}
function vec3_sub(a, b) {
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
}
function vec3_scale(v, s) {
return [v[0] * s, v[1] * s, v[2] * s];
}
function vec3_magnitude(v) {
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
function vec3_normalize(v) {
const mag = vec3_magnitude(v);
if (mag === 0) return [0, 0, 0];
return [v[0] / mag, v[1] / mag, v[2] / mag];
}
const charges = [{
pos: [250, 250, 0],
id: "negative"
},
{
pos: [450, 250, 0],
id: "positive"
}
];
const lines = 16;
const step_size = 4;
const max_steps = 1000;
function calculate_field_at_point(point, charges) {
let field = [0, 0, 0];
for (let charge of charges) {
let dir = vec3_sub(charge.pos, point);
let dist = vec3_magnitude(dir);
if (dist < 5) continue;
let strength = charge.id.includes("negative") ? 1 : -1;
strength /= (dist * dist);
field = vec3_add(field, vec3_scale(dir, strength));
}
return vec3_normalize(field);
}
function rk4_step(point, charges) {
let k1 = calculate_field_at_point(point, charges);
let temp = vec3_add(point, vec3_scale(k1, step_size * 0.5));
let k2 = calculate_field_at_point(temp, charges);
temp = vec3_add(point, vec3_scale(k2, step_size * 0.5));
let k3 = calculate_field_at_point(temp, charges);
temp = vec3_add(point, vec3_scale(k3, step_size));
let k4 = calculate_field_at_point(temp, charges);
return vec3_scale(
vec3_add(
vec3_add(
vec3_scale(k1, 1 / 6),
vec3_scale(k2, 1 / 3)
),
vec3_add(
vec3_scale(k3, 1 / 3),
vec3_scale(k4, 1 / 6)
)
),
step_size
);
}
function generate_circle_points(center, radius, num_points) {
let points = [];
for (let i = 0; i < num_points; i++) {
let angle = (i / num_points) * Math.PI * 2.0;
let x = center[0] + radius * Math.cos(angle);
let y = center[1] + radius * Math.sin(angle);
points.push([x, y, 0]);
}
return points;
}
function integrate_field_line(start_point, charges) {
let points = [start_point];
let current_point = [...start_point];
for (let i = 0; i < max_steps; i++) {
let step = rk4_step(current_point, charges);
if (vec3_magnitude(step) < 0.1) break;
current_point = vec3_add(current_point, step);
points.push([...current_point]);
let too_close = charges.some(charge => vec3_magnitude(vec3_sub(current_point, charge.pos)) < 15);
if (too_close) break;
if (current_point[0] < 0 || current_point[0] > canvas.width ||
current_point[1] < 0 || current_point[1] > canvas.height) break;
}
return points;
}
const positive_charges = charges.filter(c => c.id.includes("positive"));
for (let charge of positive_charges) {
let start_points = generate_circle_points(charge.pos, 35, lines);
for (let start_point of start_points) {
let points = integrate_field_line(start_point, charges);
if (points.length > 5) {
ctx.beginPath();
ctx.moveTo(points[0][0], points[0][1]);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[0], points[1]);
}
ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
ctx.lineWidth = 2;
ctx.stroke();
}
}
}
ctx.beginPath();
ctx.arc(charges[0].pos[0], charges[0].pos[1], 30, 0, Math.PI * 2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(charges[0].pos[0] - 15, charges[0].pos[1]);
ctx.lineTo(charges[0].pos[0] + 15, charges[0].pos[1]);
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.arc(charges[1].pos[0], charges[1].pos[1], 30, 0, Math.PI * 2);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(charges[1].pos[0] - 15, charges[1].pos[1]);
ctx.lineTo(charges[1].pos[0] + 15, charges[1].pos[1]);
ctx.moveTo(charges[1].pos[0], charges[1].pos[1] - 15);
ctx.lineTo(charges[1].pos[0], charges[1].pos[1] + 15);
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
ctx.stroke();
< /code>
< /div>
< /div>
< /p>
Я пытаюсь моделировать электрическое поле между двумя заряженными частицами.
для того, чтобы я выбирал точки вокруг положительного заряда, предпринимайте серию маленьких шагов и приблизительно направление электрического поля, используя Runge -kutta. слева. хочу:
Подробнее здесь: https://stackoverflow.com/questions/794 ... ield-lines
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
function vec3_add(a, b) {
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
}
function vec3_sub(a, b) {
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
}
function vec3_scale(v, s) {
return [v[0] * s, v[1] * s, v[2] * s];
}
function vec3_magnitude(v) {
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
function vec3_normalize(v) {
const mag = vec3_magnitude(v);
if (mag === 0) return [0, 0, 0];
return [v[0] / mag, v[1] / mag, v[2] / mag];
}
const charges = [{
pos: [250, 250, 0],
id: "negative"
},
{
pos: [450, 250, 0],
id: "positive"
}
];
const lines = 16;
const step_size = 4;
const max_steps = 1000;
function calculate_field_at_point(point, charges) {
let field = [0, 0, 0];
for (let charge of charges) {
let dir = vec3_sub(charge.pos, point);
let dist = vec3_magnitude(dir);
if (dist < 5) continue;
let strength = charge.id.includes("negative") ? 1 : -1;
strength /= (dist * dist);
field = vec3_add(field, vec3_scale(dir, strength));
}
return vec3_normalize(field);
}
function rk4_step(point, charges) {
let k1 = calculate_field_at_point(point, charges);
let temp = vec3_add(point, vec3_scale(k1, step_size * 0.5));
let k2 = calculate_field_at_point(temp, charges);
temp = vec3_add(point, vec3_scale(k2, step_size * 0.5));
let k3 = calculate_field_at_point(temp, charges);
temp = vec3_add(point, vec3_scale(k3, step_size));
let k4 = calculate_field_at_point(temp, charges);
return vec3_scale(
vec3_add(
vec3_add(
vec3_scale(k1, 1 / 6),
vec3_scale(k2, 1 / 3)
),
vec3_add(
vec3_scale(k3, 1 / 3),
vec3_scale(k4, 1 / 6)
)
),
step_size
);
}
function generate_circle_points(center, radius, num_points) {
let points = [];
for (let i = 0; i < num_points; i++) {
let angle = (i / num_points) * Math.PI * 2.0;
let x = center[0] + radius * Math.cos(angle);
let y = center[1] + radius * Math.sin(angle);
points.push([x, y, 0]);
}
return points;
}
function integrate_field_line(start_point, charges) {
let points = [start_point];
let current_point = [...start_point];
for (let i = 0; i < max_steps; i++) {
let step = rk4_step(current_point, charges);
if (vec3_magnitude(step) < 0.1) break;
current_point = vec3_add(current_point, step);
points.push([...current_point]);
let too_close = charges.some(charge => vec3_magnitude(vec3_sub(current_point, charge.pos)) < 15);
if (too_close) break;
if (current_point[0] < 0 || current_point[0] > canvas.width ||
current_point[1] < 0 || current_point[1] > canvas.height) break;
}
return points;
}
const positive_charges = charges.filter(c => c.id.includes("positive"));
for (let charge of positive_charges) {
let start_points = generate_circle_points(charge.pos, 35, lines);
for (let start_point of start_points) {
let points = integrate_field_line(start_point, charges);
if (points.length > 5) {
ctx.beginPath();
ctx.moveTo(points[0][0], points[0][1]);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[0], points[1]);
}
ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
ctx.lineWidth = 2;
ctx.stroke();
}
}
}
ctx.beginPath();
ctx.arc(charges[0].pos[0], charges[0].pos[1], 30, 0, Math.PI * 2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(charges[0].pos[0] - 15, charges[0].pos[1]);
ctx.lineTo(charges[0].pos[0] + 15, charges[0].pos[1]);
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.arc(charges[1].pos[0], charges[1].pos[1], 30, 0, Math.PI * 2);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = "black";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(charges[1].pos[0] - 15, charges[1].pos[1]);
ctx.lineTo(charges[1].pos[0] + 15, charges[1].pos[1]);
ctx.moveTo(charges[1].pos[0], charges[1].pos[1] - 15);
ctx.lineTo(charges[1].pos[0], charges[1].pos[1] + 15);
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
ctx.stroke();
< /code>
< /div>
< /div>
< /p>
Я пытаюсь моделировать электрическое поле между двумя заряженными частицами.
для того, чтобы я выбирал точки вокруг положительного заряда, предпринимайте серию маленьких шагов и приблизительно направление электрического поля, используя Runge -kutta. слева. хочу:
Подробнее здесь: https://stackoverflow.com/questions/794 ... ield-lines
Мобильная версия