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.
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.
Standard projectile motion equations:
x(t) = v * cos(a) * ty(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)
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.
| 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 |
- 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.
- Linux (tested on Ubuntu)
- g++ with C++11 or later
- SDL2 development libraries
Install SDL2 on Debian/Ubuntu:
sudo apt-get install libsdl2-devmake
./trajectoryTo clean:
make clean| 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.
The original project consisted of six 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 separatef(),df(), anddistance()functions. -
trajecto2.cpp-- Interactive version that prompts the user for speed and angle viascanf(). 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.handccbp_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 fromcclib.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 theouthzxy3/disp_hz3functions 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 byinitgraph()to initialize the graphics mode on DOS.
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.
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 |
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:
-
BGI graphics calls: The rendering functions are built on top of BGI primitives.
outhzxy3callsgetcolor(),setcolor(),setfillstyle(),moveto(), andouttextxy()for ASCII fallback.disp_hz3callsputpixel(),bar(),getmaxx(), andgetmaxy()to draw each glyph pixel-by-pixel, and uses BGI constants likeSOLID_FILL,HORIZ_DIR, andVERT_DIR. All of these come fromgraphics.h, which is Borland-specific and does not exist on Linux. -
The ASCII path also depends on BGI: Even when
outhzxy3encounters a plain ASCII character (not a Chinese byte pair), it calls BGI'souttextxy()to render it. So neither the Chinese nor the ASCII code path can work withoutgraphics.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.datunchanged 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 usingSDL_RenderFillRect()with a configurable scale factor. This replacesdisp_hz3()'s use of BGI'sputpixel()andbar(). - Rewrote the mixed-text walker as
draw_text_gb(). Like the originalouthzxy3(), 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-dependentouttextxy()fallback withdraw_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.datis 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.).
- 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.datfont) and English. The original only had one language mode.
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)

