7.6 KiB
Coding Standards - Orbital Mechanics Simulation
Code Style
- C-style C++: structs and functions only, NO classes or templates
- File extensions: Use
.cppextensions for all source files (for future C++ features if needed) - Include guards: All headers use include guards (e.g.,
#ifndef MODULE_NAME_H) - Function design: Small, focused functions with single responsibilities
// Header file with include guard
#ifndef ORBITAL_MECHANICS_H
#define ORBITAL_MECHANICS_H
struct OrbitalElements {
double semi_major_axis;
double eccentricity;
double true_anomaly;
};
OrbitalElements propagate_orbital_elements(OrbitalElements elements, double dt, double parent_mass);
#endif
Naming Conventions
Struct names: PascalCase
struct CelestialBody { };
struct OrbitalElements { };
struct Spacecraft { };
Function names: snake_case
propagate_orbital_elements()
find_dominant_body()
update_bodies_physics()
Member variables: snake_case
global_position
local_velocity
parent_index
Constants: UPPER_CASE
PARABOLIC_TOLERANCE
MIN_MASS_RATIO
Enum values: UPPER_CASE with prefix
enum BurnDirection { BURN_PROGRADE, BURN_RETROGRADE };
enum TriggerType { TRIGGER_TIME, TRIGGER_TRUE_ANOMALY };
Comments
- Minimal comments: Code should be self-documenting
- Non-obvious logic only: Comment only what cannot be inferred from the code
- No decorative blocks: No
===,---, or ASCII art comment blocks
// Good: minimal comments
if (vec3_distance(pos, parent_pos) > soi_radius) {
return 0;
}
// Bad: excessive decoration
// ========================================
// SOI Check Function
// ========================================
// This function checks if we're in SOI
// ========================================
Whitespace
- No trailing whitespace: All files (including markdown) must not have trailing whitespace
- Pre-commit hook: Automatically strips trailing whitespace
- Markdown line breaks: Use
<br>tag instead of two trailing spaces
Good:
Line 1<br>
Line 2
Bad:
Line 2
Line 4
Memory Management
- Dynamic arrays: Use
mallocandfree - Struct-based design: No RAII or smart pointers
- Manual cleanup: Destroy functions handle cleanup
// Allocation
SimulationState* sim = malloc(sizeof(SimulationState));
sim->bodies = malloc(max_bodies * sizeof(CelestialBody));
// Cleanup
void destroy_simulation(SimulationState* sim) {
free(sim->bodies);
free(sim->spacecraft);
free(sim);
}
Code Organization
Layer separation: Physics, Simulation, Configuration, Rendering layers
Physics module independence: Physics functions use parameter-based signatures, no dependencies on simulation structures
// Good: parameter-based, independent
Vec3 vec3_add(Vec3 a, Vec3 b);
Mat3 mat3_rotation_orbital(double omega, double i, double omega_upper);
// Avoid: depends on specific structures
Vec3 compute_global_position(CelestialBody* body); // Simulation layer
Headers vs implementation:
- Headers (
.h): Declarations only - Implementation (
.cpp): Function definitions
Floating-Point Comparisons (Testing)
- Use
WithinAbs(): Required for floating-point comparisons - Avoid
Approx(): Deprecated in Catch2 - Required header:
<catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
TEST_CASE("orbital energy conservation") {
double energy = calculate_total_energy(sim);
REQUIRE_THAT(energy, WithinAbs(expected, 1e-6));
}
Git Workflow
- Small commits: Logical separation of changes
- Concise messages: One-line commit messages preferred
- Build before commit: Run
make && make testbefore committing
# Verify build and tests pass
make && make test
# Commit with descriptive message
git add .
git commit -m "add parabolic orbit propagation"
Build System
Makefile targets:
makeormake all: Build simulationmake test: Build and run automated testsmake clean: Remove build artifactsmake rebuild: Clean and rebuild
Default configuration:
- Time step: 60 seconds for solar system scale
- Physics steps per frame: 100 (default)
- Simulation time per frame: 60s × 100 = 6000 seconds at 1× speed
# Full build
make
# Run tests
make test
# Clean and rebuild
make rebuild
Physics Considerations
Time step: 60 seconds for solar system scale
Circular orbit velocity:
v = sqrt(G * M / r)
Sphere of Influence (SOI): Hill sphere approximation
r_soi = a * (m / M)^(2/5)
SOI transitions: 0.5× distance hysteresis to prevent oscillation
Parabolic orbits: Escape velocity
v² = 2GM / r
Hyperbolic orbits: Positive total energy with asymptotic velocity at infinity
Analytical propagation: Uses Kepler equation solvers (not RK4 integration)
- Elliptical: E - e·sin(E) = M
- Parabolic: D + D³/3 = M (Barker's equation)
- Hyperbolic: H - e·sinh(H) = M
Module Dependencies
Physics (foundation, no dependencies)
↓
Orbital Mechanics (depends only on Physics)
↓
Spacecraft, Maneuver (depend on Physics)
↓
Simulation (depends on Physics, Orbital Mechanics, Spacecraft, Maneuver)
↓
Config Loader (depends on Simulation)
Config Validator (depends on Simulation and Orbital Mechanics)
Renderer (depends on Simulation)
UI Renderer (depends on Renderer and Simulation)
Key principles:
- Physics is completely independent
- Lower layers never depend on upper layers
- Each module has clear, minimal dependencies
Testing Guidelines
- Framework: Catch2
- Run tests:
make test - Test configs: Located in
tests/configs/ - Descriptive names: Use clear test case names
# Run all tests
make test
# Run specific test config
./orbit_test '[config_name]'
# Test with debug output (shows INFO messages)
./orbit_test -s '[config_name]'
Test structure:
TEST_CASE("elliptical orbit energy conservation", "[energy]") {
SimulationState* sim = create_simulation(10, 1, 0, 60.0);
load_system_config(sim, "tests/configs/elliptical.toml");
double initial_energy = calculate_system_total_energy(sim);
for (int i = 0; i < 100; i++) {
update_simulation(sim);
}
double final_energy = calculate_system_total_energy(sim);
REQUIRE_THAT(final_energy, WithinAbs(initial_energy, 1e-6));
destroy_simulation(sim);
}
Common Patterns
Struct initialization:
CelestialBody earth = {0};
strcpy(earth.name, "Earth");
earth.mass = 5.972e24;
earth.radius = 6.371e6;
Error handling: Return codes or NULL pointers
int result = some_function();
if (result != 0) {
return result;
}
CelestialBody* body = find_body(sim, "Earth");
if (body == NULL) {
return -1;
}
Const correctness: Use const for read-only parameters
Vec3 vec3_add(const Vec3 a, const Vec3 b) {
Vec3 result = { a.x + b.x, a.y + b.y, a.z + b.z };
return result;
}
File Organization
Directory structure:
src/
physics.h/cpp
orbital_mechanics.h/cpp
simulation.h/cpp
spacecraft.h/cpp
maneuver.h/cpp
config_loader.h/cpp
config_validator.h/cpp
renderer.h/cpp
ui_renderer.h/cpp
test_utilities.h/cpp
tests/
test_*.cpp
configs/
configs/
*.toml
docs/
*.md
Pre-commit Hooks
The project uses a pre-commit hook that:
- Strips trailing whitespace from all files
- Prevents commits with trailing whitespace
If you see a "trailing whitespace" error:
- The hook has automatically fixed the files
- Review the changes
- Stage them again and retry the commit