Skip to content

Latest commit

 

History

History
188 lines (130 loc) · 11.9 KB

File metadata and controls

188 lines (130 loc) · 11.9 KB

Ballistic Trajectory Simulation

A ballistic trajectory simulator that compares an ideal trajectory (no air resistance) against a true trajectory (with linear drag). Originally written as a college physics project in C++ for DOS/Windows around 2002, now ported to Linux using SDL2.

Screenshots

English UI

Chinese UI

Physics Model

The simulation models a projectile launched at velocity v and angle a from the horizontal, subject to gravity g and a linear drag force proportional to velocity with drag coefficient k.

Ideal trajectory (no air resistance)

Standard projectile motion equations:

  • x(t) = v * cos(a) * t
  • y(t) = v * sin(a) * t - (1/2) * g * t^2
  • Range: R = 2 * v^2 * sin(a) * cos(a) / g
  • Max elevation: H = v^2 * sin^2(a) / (2g)

True trajectory (with linear drag)

With a drag force F_drag = -k * velocity (proportional to velocity, not velocity squared), the equations of motion have closed-form solutions:

  • x(t) = (m/k) * v * cos(a) * (1 - exp(-k*t/m))
  • y(t) = (m/k) * (v*sin(a) + m*g/k) * (1 - exp(-k*t/m)) - (m*g/k) * t

The true range (where the projectile returns to ground level, y=0) does not have a simple closed-form solution. It is found numerically using the Newton-Raphson method: the y=0 condition is reformulated as a function of horizontal distance, f(u) = 0, and the root is found iteratively starting from the ideal range as an initial guess.

Parameters

Parameter Description Default Range Key
v Initial velocity (m/s) 80 1 - 800 LEFT/RIGHT
angle Launch angle (degrees) 60 1 - 89 UP/DOWN
m Projectile mass (kg) 12 1 - 10,000 W/S
k Drag coefficient 2.2 0.01 - 10.0 D/F
g Gravity (m/s^2) 9.88 fixed --

Mass adjustment uses nonlinear step sizes to make the full range practical to navigate:

Mass range Step size
1 - 100 kg 1 kg
100 - 200 kg 5 kg
200 - 1,000 kg 10 kg
1,000 - 5,000 kg 50 kg
5,000 - 10,000 kg 100 kg

What you can observe

  • At low drag or high mass, the true trajectory converges toward the ideal -- drag becomes negligible relative to momentum.
  • At high drag or low mass, the true trajectory falls dramatically short of the ideal, with both reduced range and lower peak elevation.
  • The ideal max elevation depends only on speed and angle; the true max elevation is always lower due to drag.
  • At 45 degrees the ideal range is maximized; the angle that maximizes true range is slightly lower than 45 degrees because drag penalizes the longer flight time of steeper angles.

Building

Prerequisites

  • Linux (tested on Ubuntu)
  • g++ with C++11 or later
  • SDL2 development libraries

Install SDL2 on Debian/Ubuntu:

sudo apt-get install libsdl2-dev

Compile and run

make
./trajectory

To clean:

make clean

Controls

Key Action
UP / DOWN Adjust launch angle (+/- 1 degree)
LEFT / RIGHT Adjust initial speed (+/- 1 m/s)
W / S Adjust mass (nonlinear steps, see table above)
D / F Adjust drag coefficient (+/- 0.01)
C Toggle Chinese/English UI
ESC Quit

All parameters update the plot in real time.

Porting from the Original DOS/Windows Code

The original project consisted of six files:

Original source files

  • trajecto1.cpp -- First version of the simulation with hardcoded parameters (v=80 m/s, angle=60 degrees, m=12 kg, k=2.2). Draws both ideal (red) and true (white) trajectories and prints range values. Contains the Newton-Raphson solver as separate f(), df(), and distance() functions.

  • trajecto2.cpp -- Interactive version that prompts the user for speed and angle via scanf(). Adds an animated projectile dot (putimage) that travels along each trajectory before leaving a trail. Inlines the Newton-Raphson solver rather than calling separate functions.

  • ccbp.h and ccbp_lib.h -- A custom Chinese character bitmap rendering library. These are two variants of the same library (slightly different function signatures and return types). They read glyph bitmaps from cclib.dat (a GB2312-encoded 16x16 bitmap font file) and render Chinese text pixel-by-pixel onto the BGI graphics screen. The library also includes a large collection of physics diagram drawing utilities: coordinate axes with arrowheads (coordc, coord), coil/inductor shapes (coil1-coil6), transistor symbols (jtd), wooden blocks (wood_b), inclined planes (inclined_p), arrowheads and arrows (arrowhead, arrowh), force vector decomposition (pxsbxxy), spring drawing (spring), grid drawing (square), light ray optics (refrac_light, reflec_light, light), magnetic field visualization (magnet_f), and electric field visualization (electric_f). This was clearly a shared library used across many physics course projects, not just the trajectory simulation.

  • cclib.dat -- Binary font data file containing 16x16 pixel bitmaps for GB2312-encoded Chinese characters. Used by the outhzxy3 / disp_hz3 functions in ccbp.h to render Chinese text labels on the graphics screen.

  • egavga.bgi -- Borland BGI (Borland Graphics Interface) driver file for EGA/VGA displays. Required by initgraph() to initialize the graphics mode on DOS.

What was ported

The physics and math were ported directly:

  • The trajectory equations are identical to the originals.
  • The Newton-Raphson solver logic is the same, reorganized into a single find_true_range() function that takes all parameters rather than relying on hardcoded globals.
  • The original constants (g=9.88, m=12, k=2.2, v=80, angle=60) are preserved as defaults.

What was replaced

The entire graphics layer was replaced. The original code depended on Borland's BGI (Borland Graphics Interface), a DOS-era graphics library that provided initgraph(), putpixel(), line(), bar(), setcolor(), outtextxy(), etc., plus the conio.h console I/O library (getch(), gotoxy(), delay()), and dos.h for DOS-specific functions. None of these exist on Linux.

Rather than using a BGI compatibility layer (e.g., SDL-BGI, WinBGIm), the port uses SDL2 directly:

Original (BGI/DOS) Replacement (SDL2)
initgraph(&gd, &gm, "c:\\tc") SDL_CreateWindow() + SDL_CreateRenderer()
putpixel(x, y, color) SDL_RenderFillRect() (3x3 dot for visibility)
line(x1,y1,x2,y2) SDL_RenderDrawLine()
bar(x1,y1,x2,y2) SDL_RenderFillRect()
setcolor(n) / BGI palette indices SDL_SetRenderDrawColor() with RGB values
outtextxy() / outhzxy3() (Chinese text) draw_text() (ASCII) + draw_text_gb() (mixed Chinese/ASCII)
getch() for key input SDL_PollEvent() with SDL_KEYDOWN events
delay(ms) SDL_Delay()
closegraph() SDL_DestroyRenderer() + SDL_DestroyWindow()
egavga.bgi driver file Not needed (SDL2 uses the OS display system)
cclib.dat + disp_hz3() cclib.dat loaded into memory + draw_gb_char() using SDL2

Chinese character rendering — what was ported and why it needed rewriting

The original Chinese character rendering (outhzxy3, disp_hz3) could not be used directly on Linux because these functions have two layers of dependencies that don't exist:

  1. BGI graphics calls: The rendering functions are built on top of BGI primitives. outhzxy3 calls getcolor(), setcolor(), setfillstyle(), moveto(), and outtextxy() for ASCII fallback. disp_hz3 calls putpixel(), bar(), getmaxx(), and getmaxy() to draw each glyph pixel-by-pixel, and uses BGI constants like SOLID_FILL, HORIZ_DIR, and VERT_DIR. All of these come from graphics.h, which is Borland-specific and does not exist on Linux.

  2. The ASCII path also depends on BGI: Even when outhzxy3 encounters a plain ASCII character (not a Chinese byte pair), it calls BGI's outtextxy() to render it. So neither the Chinese nor the ASCII code path can work without graphics.h.

However, the cclib.dat font data itself is fully portable. It is a flat binary file containing 16x16 pixel bitmaps indexed by GB2312 code point. Each glyph is 32 bytes (2 bytes per row, 16 rows, MSB = leftmost pixel). The offset for a character with byte values (byte1, byte2) is ((byte1-0xA1)*0x5E + byte2-0xA1) * 32. The file I/O to read it is standard C (fopen, fseek, fread), and the bitmap decoding is pure bit manipulation — nothing platform-specific.

The port therefore:

  • Kept cclib.dat unchanged as the font data source.
  • Rewrote the renderer from scratch for SDL2. The new draw_gb_char() function loads the 32-byte glyph record from the in-memory font data (loaded once at startup), iterates over the 16x16 bit matrix, and draws each set pixel using SDL_RenderFillRect() with a configurable scale factor. This replaces disp_hz3()'s use of BGI's putpixel() and bar().
  • Rewrote the mixed-text walker as draw_text_gb(). Like the original outhzxy3(), it walks a byte string and checks each byte pair: if both bytes are in the GB2312 range (0xA1-0xFE), it renders a 16x16 Chinese character; otherwise it renders an 8x8 ASCII character. ASCII characters are vertically centered within the 16-pixel Chinese character height. This replaces the original's BGI-dependent outtextxy() fallback with draw_ascii_char() using the embedded 8x8 bitmap font.
  • Added Chinese translations for all UI text (title, labels, equations, instructions, parameter names) stored as GB2312 byte arrays in the source code.
  • Added a language toggle (C key) that switches between English and Chinese at runtime. If cclib.dat is not found at startup, Chinese mode is silently disabled and the app works in English only.

The physics diagram utilities from ccbp.h (coils, transistors, springs, optics, etc.) were not ported as they are unrelated to the trajectory simulation. They also depend entirely on BGI drawing primitives (line, arc, rectangle, setlinestyle, etc.).

What was improved

  • Resolution: Scaled from 640x480 to 1280x720 for modern displays.
  • Uniform scaling: Both axes use the same pixels-per-meter ratio, so the visual launch angle matches the actual angle. The original used independent X/Y scaling which distorted the geometry.
  • Adaptive point density: The original used a fixed time step (dt=0.05), producing ~280 dots at high speed but only ~8 dots at low speed. The port uses a fixed 500 steps per curve regardless of flight time.
  • Interactive controls: The original either hardcoded parameters (trajecto1) or prompted via scanf (trajecto2). The port uses real-time keyboard controls with immediate visual feedback.
  • Adjustable mass: Mass was hardcoded at 12 kg in the original. Now adjustable from 1 to 10,000 kg with nonlinear step sizes.
  • Displayed metrics: Both range and maximum elevation are shown for ideal and true trajectories.
  • Chinese/English toggle: Press C to switch all UI text between Chinese (rendered from the original cclib.dat font) and English. The original only had one language mode.

File Structure

ccbp/                       -- repository root (shared CCBP library files)
  ccbp.h                    -- original Chinese text + physics drawing library
  ccbp_lib.h                -- original Chinese text + physics drawing library (variant)
  cclib.dat                 -- GB2312 16x16 bitmap font data (used for Chinese mode)
  egavga.bgi                -- original Borland BGI graphics driver (not used by port)
  ballistic_trajectory/     -- this project
    trajectory.cpp          -- SDL2 port (the program)
    Makefile                -- build script
    README.md               -- this file
    trajecto1.cpp           -- original source (hardcoded params, ~2002)
    trajecto2.cpp           -- original source (interactive, ~2002)