[工程文档] 微观电荷

为了防止开发中的大间隔导致自己看不懂逻辑,遂详细记录。

世界空间

把窗口平面放置到空间中的 \(xOy\) 平面中,视角为从上向下俯视。

一期Beta:9.13 issue:

  1. 物体(Object)是统一的,没有区分 Ball 这个对象
  2. 测试时发现 Full_Range 的磁场无法正确判断是否在范围内,出现一直不进区域的问题
  3. 定义的场是匀强场,不能定义关于信息变换的场
  4. 原初题目的问题没有解决!!!(物理某个洛伦兹力自助T7)
  5. 由于重置背景为白色,暴力的不清屏轨迹法失效

二期目标:10.1 preview:

  1. 解决issue1-2, issue1-3
  2. \(\color{red}(重要)\)将世界初始元素改为可编辑存档式:首先由存档生成器(临时:根据文本指令生成)根据用户提供数据生成二进制存档文件,再由计算程序读取该存档文件(此处只有指令文本是人类可读的)
  3. 加入时间关联/条件关联「事件」(event):包括修改某个对象的值,追加/删除对象,调整屏幕缩放(按键控制&作为条件触发时间关联事件),平移屏幕摄像机(按键控制&作为条件触发时间关联事件)
  4. 提前加入三期中的 「运动轨迹」对象:将非固定对象等时刻记录位置采样点,和该对象关联,依次用直线连接采样点得到轨迹图像

一期代码储存

// Demo.cpp
#include <SFML/Graphics.hpp>
#include "includes.h"
#include <windows.h>

unsigned int WIDTH = 1600;
unsigned int HEIGHT = 1200;
Vec2 centre = {WIDTH / 2, HEIGHT / 2, 0.0f};


int main()
{
    float delt_t = 1.0 / 60.0;

    // SFML draw 部分
    sf::ContextSettings Settings;
    Settings.antiAliasingLevel = 8; // 抗锯齿
    sf::Font font("Consolas.ttf");
    sf::Text text(font);


    sf::RenderWindow window(sf::VideoMode({WIDTH, HEIGHT}), "Title", sf::Style::Default, sf::State::Windowed, Settings);
    window.setVerticalSyncEnabled(true); // call it once after creating the window

    std :: vector <Object> objects; // 小球等物体
    std :: vector <Electric_Field> E_Fields; // 匀强电场      // 挖坑:非匀强电场
    std :: vector <Magnetic_Field> B_Fields; // 匀强磁场      // 挖坑:非匀强磁场
    std :: vector <Gravity_Field> G_Fields; // 引力场

    // 测试内容 内容在改错本已经 ISSUED

    B_Fields.push_back(
        {
            Full_Range, 
            {0.0f, 0.0f, 10000.0f}
        }
    );

    objects.push_back( // A点
        {
            Vec2{30, 40, 0}, true, 
            zero3, 
            zero3, 
            1.0f, 
            1e-4f
        }
    );
   objects.push_back( // B点
        {
            Vec2{30, 50, 0}, false, 
            Vec2{(float)sqrt(k_Coulomb * 1e-8 / 10.0f), 0, 0},
            zero3, 
            1.0f, 
            -1e-4f
        }
    );
   // B理应绕着A刚好做匀速圆周运动


    long long int ticks = 0;
    while (window.isOpen())
    {
        while (const std::optional event = window.pollEvent()) // 操作检测
        {
            if (event -> is<sf::Event::Closed>())
            {
                window.close();
                return 0;
            }
            if (sf :: Mouse :: isButtonPressed(sf :: Mouse :: Button :: Left))
            {

            }
        }

        WorldUpdate(
            delt_t,
            objects,
            E_Fields,
            B_Fields,
            G_Fields
        ); // 物理更新

        window.clear(sf::Color::White);
        // 绘图
        
        // 渲染小球
        window.draw(Draw_Ball(
            objects[0], 
            5.0f / 20, 
            sf::Color::Black)
        );

        window.draw(Draw_Ball(
            objects[1], 
            5.0f / 20, 
            sf::Color::Black)
        );


        // UI 信息
        std :: stringstream ss;
        ss << "Time: ";
        ss << std :: setiosflags(std :: ios::fixed) << std :: setprecision(2) << ticks * delt_t;
        text.setString(ss.str());

        text.setCharacterSize(24); // in pixels
        text.setFillColor(sf::Color::Black);
        window.draw(text);


        window.display();
        ticks++;
    }
}
math.h
#pragma once

// 三维向量(主平面即窗口平面为 xOy)
struct Vec2 
{
	float x;
	float y;
	float z;
	// 线性运算
	// 加法
	Vec2 operator+(const Vec2& b) const
	{
		return {x + b.x, y + b.y, z + b.z};
	}
	// 减法
	Vec2 operator-(const Vec2& b) const
	{
		return {x - b.x, y - b.y, z - b.z};
	}
	// 数乘
	Vec2 operator*(const float& b) const
	{
		return {x * b, y * b, z * b};
	}
	// 点乘
	float operator*(const Vec2& b) const
	{
		return x * b.x + y * b.y + z * b.z;
	}

	// 叉乘
	Vec2 operator^(const Vec2& b) const
	{
		return {y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x};
	}

	// 模长
	float mod() const
	{
		return sqrt(x * x + y * y + z * z);
	}
};

const Vec2 zero3 = {0.0f, 0.0f, 0.0f}; // 零向量

// 范围
struct Range
{
	int type; // 类型:0为矩形 1为圆形
	Vec2 minn; // 左上角
	Vec2 maxn; // 右下角

	Vec2 centre; // 圆心
	float radius; // 半径
};

const Range Full_Range = {
	0,
	{-1e9f, 1e9f, 0.0f},
	{1e9f, -1e9f, 0.0f},
	zero3,
	0.0f
};

// 该坐标点是否位于区域内
bool isInRect(Vec2 point, Range temp) // true为在区域内
{
	if (temp.type == 0)
	{
		return (temp.minn.x <= point.x && point.x <= temp.maxn.x) && (temp.minn.y <= point.y && point.y <= temp.maxn.y);
	}
	if (temp.type == 1)
	{
		return (point - temp.centre).mod() <= temp.radius;
	}
}
// physic.h
#pragma once

const float k_Coulomb = 8.9875517923e9f; // 库仑常数 N·m²/C²

// 物体
struct Object
{
	Vec2 position; // 位置
	bool isFixed; // 是否固定
	Vec2 velocity; // 速度
	Vec2 acceleration; // 加速度
	float mass;    // 质量
	float quantity; // 电荷量
};

// 电场
struct Electric_Field
{
	Range area; // 作用区域
	Vec2 E; // 场强
};

// 磁场
struct Magnetic_Field
{
	Range area; // 作用区域
	Vec2 B; // 磁感应强度
};

// 引力场
struct Gravity_Field
{
	Range area; // 作用区域
	Vec2 G; // 引力加速度
};

// 点电荷间库仑力
Vec2 Coulomb_Force(const Object& a, const Object& b) // a 对 b 施加的力
{
	Vec2 AB = b.position - a.position;

	if (AB.mod() - 1e-5 <= 0)
	{
		return zero3;
	}

	Vec2 E = AB * (k_Coulomb * a.quantity * pow(AB * AB, -1.5f));

	return E * b.quantity;
}

void WorldUpdate(
	float deltaTime,
	std :: vector <Object> &objects,
	std :: vector <Electric_Field> &E_Fields,
	std :: vector <Magnetic_Field> &B_Fields,
	std :: vector <Gravity_Field> &G_Fields
)
{
   // 根据更新前的状态计算力
	for (auto& i : objects)
	{
		if (i.isFixed) // 固定物体不更新
		{
			i.acceleration = zero3;
			i.velocity = zero3;
			continue;
		}

		Vec2 F_Sum = zero3;
		// 物体间的电荷库伦力(静电力)
		Vec2 F_Coulomb = zero3;
		for (auto& j : objects)
		{
			F_Coulomb = F_Coulomb + Coulomb_Force(j, i);
		}
		// 物体所受的电场力
		Vec2 F_Efield = zero3;
		for (auto &j : E_Fields)
		{
			if (isInRect(i.position, j.area))
			{
				F_Efield = F_Efield + j.E * i.quantity;
			}
		}
		// 物体所受的磁场洛伦兹力
		Vec2 F_Bfield = zero3;
		for (auto &j : B_Fields)
		{
			//if (isInRect(i.position, j.area)) //! ISSUE:无法正确判断范围
			{
				//std :: cerr << "Updated\n";
				F_Bfield = F_Bfield + (i.velocity ^ j.B) * i.quantity;
			}
		}
		// 物体所受的引力场力
		Vec2 F_Gfield = zero3;
		for (auto &j : G_Fields)
		{
			if (isInRect(i.position, j.area))
			{
				F_Gfield = F_Gfield + j.G * i.mass;
			}
		}
		F_Sum = F_Coulomb + F_Efield + F_Bfield + F_Gfield;
		// 更新加速度
		i.acceleration = F_Sum * (1.0f / i.mass);
	}
   
	// 更新速度
	for (auto& i : objects)
	{
		i.velocity = i.velocity + i.acceleration * deltaTime;
	}
	// 更新位置
	for (auto& i : objects)
	{
		i.position = i.position + i.velocity * deltaTime;
	}
}
// drawer.h
#pragma once
const float K = 20; // 缩放比例 :世界坐标 * K = 屏幕像素坐标
extern unsigned int WIDTH;
extern unsigned int HEIGHT;
extern Vec2 centre;

inline Vec2 transform_to_screen(Vec2 world_pos)
{
    return Vec2{world_pos.x * K, HEIGHT - world_pos.y * K, 0.0f};
}


inline sf::CircleShape Draw_Ball(Object A, float radius, sf:: Color color)
{
    sf::CircleShape t;
    t.setRadius(radius * K);
    t.setPointCount(20);
    Vec2 screen_pos = transform_to_screen(A.position);
    t.setPosition({screen_pos.x, screen_pos.y});
    t.setFillColor(color);
    return t;
}
// includes.h
#pragma once
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>

// New Function
#include "math.h"
#include "physic.h"
#include "drawer.h"

posted @ 2025-09-14 00:11  gzxworld  阅读(26)  评论(0)    收藏  举报