Sunday, October 12, 2025

The Father-Son duo's story - the four layered nested vectors...

My school going son, Ridit, had a complain against me...
"Baba, why didn't you teach me about nested vectors earlier? I am stuck in a particle simulation application where i am using Incremental Potential Contact (IPC) for collision detection. And I am trying to decipher the 4 layered nested vectors now."

" Okay... It's a little difficult for new comers. That's why i didn't touch nested vectors when i taught you C++. But here we go..."


1. Vector of Character: The String

"Look at your name: 'R-I-D-I-T'," I said, writing it on a whiteboard. "Each letter is a single character, right? A computer takes those individual characters and lines them up, one after the other, to make a single word."

"That single line of characters? That's what we call a 'vector of character'. It's the simplest type, just like a single word. And you know its called a string... right!!!"

Ridit nodded... Yes...

2. Vector of String: The Family Member List

"Exactly! Now, let's take a step up. You, me, and Mom." I wrote:

  • Ridit

  • Dad

  • Mom

"See? Now we have three separate 'strings'—three names. A computer can take a whole list of these strings and put them together into a bigger list."

"That bigger list—the list of names of all our family members—is a 'vector of string'. It's like a single list where every item is a word or a phrase. It’s a list of words."

3. Vector of Vector of String: The Family Album

"Now, let's think bigger. Imagine your friend Ishan's family. They have their own list of names, right? Ishan, his mom, his dad."

I drew a box around their family's list and another box around Ishan's family's list.

"In our program, we could have one list for The Sharma Family and a second list for The O'Connell Family. We now have a list of lists of names."

"That's a 'vector of vector of string'. It's an organized list where each item is a complete list of names from a different family. It's how we organize data for something like a Family Tree app or a guest list for a big party, where you group guests by family."


4. Vector of Vector of Vector of String: The Global Directory

"Alright, last one, the biggest level. Imagine a program that keeps track of families all over the world. Our set of families is in India." I wrote 'INDIA' above the Sharma and O'Connell families.

"Now, there's another set of families living in Japan , and maybe another set in Brazil."

"We can take the entire collection of Indian families (our previous 'vector of vector of string'), and put it on a larger list next to the collection of Japanese families and the collection of Brazilian families."

"This final, massive list is a 'vector of vector of vector of string'," I finished, pointing to the largest, outermost box. "It's how we group data by a major category, like Nation. It's a huge directory where each entry is a list of all the families in a specific country, and each family is a list of all its members."

Here's a pictorial explaining the above concepts ...


I told my son...Computer Science is like studying different seemingly disconnected subjects together.... but when the convergence happens after years of experience, the bigger picture comes out.

Then I asked my son, could you map this kinds of Data Structure with any of the design patterns you studied?

"Yeah... Composite Design Pattern...", Ridit answered confidently.

"Good... ", i said. " Now finish your particle simulation and contribute to the body learning of the universe. That's our final goal..."

Monday, October 6, 2025

The reverse osmosis - when my son gives me clue for different concepts of Computer Graphics - a story of the stuck-ball in a ping-pong game...



The little white circle, known in the digital world as Pingy, was having an existential crisis. He was a ball, and balls were meant to bounce, to fly with crisp, perfect elasticity. Yet, here he was, plastered against the blue paddle named Paddles.

It wasn't a normal contact; it was a cosmic entanglement.

"Let go of me, you big rectangle!" Pingy screamed, vibrating furiously.

Paddles, a Kinematic Body whose every move was dictated by a distant, jittery mouse cursor, didn't mean to hold him. "I'm trying, I swear! I've executed my full impulse to separate us, but the time step is too big!"

Pingy's crisis was the result of a flaw in their digital reality: penetration caused by Discrete Collision Detection (DCD).

The game's clock, ticking at 60 frames per second, was supposed to check Pingy's position at  t1 and then again at t2. But Pingy was fast—too fast. In one time slice, he'd jumped from being outside Paddles to being halfway inside him.

The Pymunk Sequential Impulse Solver, their benevolent god, immediately registered the crime. "Overlap! Apply impulse to separate!"

But before the impulse could fully push Pingy back to the surface, the next time step arrived. Gravity was pulling Pingy down, and Paddles' surface was pushing him up, all while Pingy’s internal velocity was still trying to move him forward.

"I'm stuck in the Zeno's Paradox of physics engines!" Pingy wailed. "I'm forever approaching the exit, but never quite reaching it!"

The paddle surface felt like a sticky, repulsive field. Every millisecond, the solver applied a new impulse, resulting in a rapid, microscopic vibration that translated to an infuriating standstill on the screen.

Suddenly, a change came. A distant developer—their true god—finally adjusted the code, not by implementing the godly Offset Geometric Contact (OGC) model (which was reserved for fancy, billowing capes in ), but by simply making the right choice for the current world:

Python
ball_shape.friction = 0.0

With the removal of that final, tiny opposing force, the Sequential Impulse Solver finally won its tug-of-war. The microscopic forces holding Pingy hostage vanished. The final, forceful impulse took hold.

BWOOONG...

Pingy shot away from Paddles' surface with the perfect, glorious elasticity he was born with. He was flying, bouncing crisply off the walls, a free ball once more.

"I'm un-stuck!" Pingy cheered, realizing the solution to his existential problem wasn't magic, but just a properly applied zero-friction constraint that allowed the Impulse Solver to do its job unimpeded. The world was stable again.

Now some raw technical discussion...

Pymunk, being a wrapper for the Chipmunk engine, relies on an Impulse-Based Solver combined with a simple form of geometric offset to ensure stability.

Pymunk's Technology to Prevent Sticking

The "stuck ball" is a result of Discrete Collision Detection (DCD) failing at high speeds. Pymunk avoids this using a more robust, impulse-based physics loop.

Physics ConceptPymunk Implementation in ScriptHow It Prevents Sticking
1. Sequential Impulse Solverspace.step(1.0 / FPS)This is the core technology. Instead of just pushing objects apart when penetration is detected, the solver iteratively calculates the precise impulse (force X time) needed to satisfy the contact constraints (non-penetration, friction, elasticity) over the duration of the time step. This system is inherently more stable than simple "fix-up" forces.
2. Non-Penetration ConstraintBuilt into the pymunk.Circle and pymunk.Segment shapes.Pymunk treats the shapes as having a defined, non-negotiable surface thickness. When two shapes get too close, the solver activates a distance constraint. This is analogous to a simple, baked-in form of the Offset Geometric Contact (OGC) idea: it ensures the geometric boundaries are never violated.
3. High Elasticityball_shape.elasticity = 1.0In PyMunk, elasticity controls the coefficient of restitution. Setting it to (perfect bounce) ensures that the ball retains all of its kinetic energy after the collision. This prevents the ball from "thudding" and stopping due to energy loss, which often looks like sticking.
4. Zero Frictionball_shape.friction = 0.0Friction is a force that opposes motion between surfaces. Setting it to prevents the ball from "gripping" the paddle surface, which could otherwise slow it down and cause it to appear to halt or slide unnaturally.
5. Kinematic Paddle Controlpaddle_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)By using a Kinematic body and controlling its position directly (paddle_body.position = (clamped_x, PADDLE_Y)), you tell the solver the paddle's movement is guaranteed. This simplifies the physics calculation, allowing the solver to focus purely on resolving the ball's collision against a predictable target, which improves stability.

Why OGC is Not Used (and Why Pymunk is Enough)

While the problem the ball-and-paddle encounters is conceptually the same as what Offset Geometric Contact (OGC) solves, Pymunk/Chipmunk doesn't need to implement the complex OGC model because of three key differences:

  1. Low Dimensionality (2D): Pymunk is a 2D engine. OGC is primarily designed for complex 3D simulations of co-dimensional objects (thin cloth, shells, etc.) where penetration is far more difficult to detect and resolve.

  2. Simple Geometry: Your simulation uses simple geometries (circles and line segments). Pymunk's solver is highly optimized for these shapes.

  3. Efficiency over Guarantee: OGC provides a mathematical guarantee of zero penetration, which is extremely expensive. Pymunk prioritizes real-time efficiency and uses its impulse solver to achieve a highly reliable near-zero penetration state, which is perfectly sufficient for games.

In short, Pymunk uses a combination of an Impulse-Based Solver and Constraint Satisfaction to ensure the ball never violates the surface of the paddle, making the expensive, complex methods like OGC unnecessary for a simple, stable game.

The Source Code...

import pymunk
import pymunk.pygame_util
import pygame
# 1. Import the DrawOptions class for modern Pymunk drawing
from pymunk.pygame_util import DrawOptions

pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Pymunk Ping Pong (No Sticking)")

# --- Physics Space Setup ---
space = pymunk.Space()
# For classic ping pong, set gravity to (0, 0)
space.gravity = (0, 0)

# --- Ball: Dynamic Circle ---
mass = 1
radius = 10
moment = pymunk.moment_for_circle(mass, 0, radius)
ball_body = pymunk.Body(mass, moment)
ball_body.position = (screen_width // 2, screen_height // 2)

# Give the ball an initial velocity to start the game
ball_body.velocity = (300, 200)

ball_shape = pymunk.Circle(ball_body, radius)
ball_shape.elasticity = 1.0 # Perfect bounce for ping pong
ball_shape.friction = 0.0 # No friction to maintain speed
ball_shape.color = (255, 255, 255, 255) # White ball
space.add(ball_body, ball_shape)

# --- Paddle (Player): Kinematic Body ---
# Use a Kinematic body so we can move it manually without physics forces
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_Y = screen_height - 50

paddle_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
paddle_body.position = (screen_width // 2, PADDLE_Y)

# Segment shape for the paddle surface
paddle_shape = pymunk.Segment(
paddle_body,
(-PADDLE_WIDTH // 2, 0), # Start relative to body center
(PADDLE_WIDTH // 2, 0), # End relative to body center
PADDLE_HEIGHT // 2 # Thickness
)
paddle_shape.elasticity = 1.0
paddle_shape.friction = 0.0
paddle_shape.color = (0, 100, 255, 255) # Blue paddle
space.add(paddle_body, paddle_shape)

# --- Walls/Boundaries (Static Segments) ---
# Create four static segments to form the screen boundaries
boundary_lines = [
pymunk.Segment(space.static_body, (0, 0), (screen_width, 0), 1), # Top
pymunk.Segment(space.static_body, (0, screen_height), (screen_width, screen_height), 1), # Bottom
pymunk.Segment(space.static_body, (0, 0), (0, screen_height), 1), # Left
pymunk.Segment(space.static_body, (screen_width, 0), (screen_width, screen_height), 1) # Right
]
for line in boundary_lines:
line.elasticity = 1.0
line.friction = 0.0
line.color = (100, 100, 100, 255)
space.add(line)

# --- Game Loop ---
running = True
clock = pygame.time.Clock()
FPS = 60
# 2. Initialize DrawOptions, passing the screen surface
options = DrawOptions(screen)

while running:
# --- Input Handling ---
mouse_x, _ = pygame.mouse.get_pos()

for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

# Move paddle to follow the mouse's X position
target_x = mouse_x

# Clamp paddle position within screen boundaries
min_x = PADDLE_WIDTH // 2
max_x = screen_width - PADDLE_WIDTH // 2
clamped_x = max(min_x, min(target_x, max_x))

# Move the kinematic body
paddle_body.position = (clamped_x, PADDLE_Y)

# --- Physics Step (Solver) ---
# The time step duration is passed as the argument
space.step(1.0 / FPS)

# --- Drawing ---
screen.fill((10, 20, 30)) # Dark blue background

# 3. Call debug_draw() on the space, passing the options
space.debug_draw(options)

pygame.display.flip()
clock.tick(FPS)

pygame.quit()