Tuesday, March 11, 2025

The curious engineer is still thriving in me - checking the veracity of the continuity equation in computational fluid dynamics...

 It was early in the morning. Everywhere there was a pin-drop silence. After the regular morning exercise, I turned on my laptop. Today's plan was to verify the continuity equation of computational fluid dynamics. For noncompressible fluid, the continuity equation can be mathematically written as U=0. It's the conservation of mass in fluid simulation. Whatever goes into a volume has to come out - no creation, no destruction, just pure, seamless flow.

The paraFoam is good for visualizing the cavity example of the Tutorial that comes with openFoam. As I am new to using ParaView, i preferred raw data exported to a CSV file.

So I created the following Python script.

from paraview.simple import *

# Load the OpenFOAM case

foamCase = OpenFOAMReader(FileName="cavity.OpenFOAM")

foamCase.MeshRegions = ['internalMesh']

foamCase.CellArrays = ['U'] # Ensure velocity field is loaded


# Apply the new Gradient filter

gradFilter = Gradient(Input=foamCase)

gradFilter.ScalarArray = ['POINTS', 'U'] # Compute gradient of velocity U


# Show the gradient field in ParaView

gradDisplay = Show(gradFilter)

ColorBy(gradDisplay, ('POINTS', 'Gradient'))


# Apply a color map for better visualization

glyph = Glyph(Input=gradFilter, GlyphType='Arrow')

glyph.ScaleFactor = 0.01 # Adjust the size

Show(glyph)

Render()

# Optional: Save visualization as an image

SaveScreenshot("grad_U_visualization.png")

writer = CreateWriter("gradU_data.csv", gradFilter)

writer.UpdatePipeline()

Now the time is to test the veracity of the continuity equation.

So, another Python script as follows.

import pandas as pd
import matplotlib.pyplot as plt

# Load CSV file
df = pd.read_csv("/home/som/OpenFOAM/som-dev/run/cavity/cavity/gradU_data.csv")

# Compute divergence of U (sum of diagonal terms of gradient matrix)
df["divU"] = df["Gradient:0"] + df["Gradient:4"] + df["Gradient:8"]

# Plot divergence
plt.plot(df["Points:0"], df["divU"], marker="o", linestyle="-", label="∇·U")
plt.axhline(0, color='r', linestyle="--", label="Zero Line")
plt.xlabel("X Position")
plt.ylabel("Divergence of Velocity (∇·U)")
plt.title("Verification of Continuity Equation (∇·U)")
plt.legend()
plt.grid()
plt.show()

# Check if max deviation from zero is small
print("Max |∇·U| =", df["divU"].abs().max())



A little explanation for the code 
df["divU"] = df["Gradient:0"] + df["Gradient:4"] + df["Gradient:8"]
This is important because we must take the diagonal values of a 
3X3 matrix to verify the continuity equation.
Everything was looking fine except near the lid. The value was high. 

Max |∇·U| = 100.0.

The culprits were located near the moving lid and the corner regions of the cavity. This made sense—corners were prone to numerical singularities due to discontinuities in the velocity gradient.

Not to my surprise. But i wanted to verify using a histogram image.

So added the following python script.

plt.hist(df["divU"], bins=50)
plt.xlabel("∇·U values")
plt.ylabel("Frequency")
plt.title("Distribution of divergence (∇·U)")
plt.show()

And voila.

Most of the values are almost 0.

The scientist in me became happy to contribute to the learning community.

Happy learning...

Here's the simulation exported from ParaView...



That's it for today.

Reclaiming #WhoWeAre...

Friday, February 21, 2025

My first day encounter with KDevelop - simple yet powerful...


It was a calm afternoon in Kolkata. Yesterday it rained. The weather was muggy. There was silence everywhere.... only a few crows were making sound.

Before going to school, my son Ridit suggested that we must give a try to KDevelop for our C++ projects. So I installed the KDevelop using the apt command.

As I am planning to do a deep dive in openFoam source code, the first thing I did was to navigate to the openFoam source directory and opened the project in KDevelop.

I then built it...

And voila.... my dev environment is ready.

As I shut my laptop, I realized I found a new favorite IDE—one that struck a perfect balance between simplicity and power.

Thursday, February 20, 2025

Computational Fluid Dynamics (CFD) & Fluid Simulation in ISRO and DRDO - my exploration continues...

My exploration continues...

Watch...



Both ISRO (Indian Space Research Organisation) and DRDO (Defence Research and Development Organisation) heavily rely on CFD (Computational Fluid Dynamics) and fluid simulations for aerospace, defense, and hypersonic vehicle design. They use high-performance computing (HPC), indigenous CFD solvers, and experimental validation for these applications.

1️⃣ ISRO: CFD Applications in Space Science 🚀

ISRO uses CFD simulations in various projects related to rocketry, re-entry vehicles, aerodynamics, and propulsion systems.

✅ Key CFD Applications in ISRO

  1. Rocket Aerodynamics & Re-entry Simulation

    • CFD is used to analyze airflow, pressure, and heating effects on launch vehicles like PSLV, GSLV, and LVM3.
    • Re-entry vehicles (Gaganyaan Crew Module) undergo hypersonic flow simulations to predict shock waves and thermal loads.
  2. Propulsion & Combustion Analysis

    • CFD helps in designing cryogenic, semi-cryogenic, and solid rocket engines.
    • Combustion chamber simulations predict fuel mixing efficiency and pressure variations in engines like Vikas and CE-20.
  3. Hypersonic Vehicle Simulations

    • Reusable Launch Vehicles (RLV) and Scramjets require CFD to analyze Mach 5+ speeds.
    • ISRO’s Scramjet Engine Test Flight (ATV) used CFD to predict shock interaction and fuel-air mixing.
  4. Satellite Thermal & Fluid Analysis

    • Thermal control systems use CFD to analyze fluid movement inside heat pipes.
    • Cryogenic fuel behavior inside tanks is simulated for fuel sloshing and vapor formation.

🖥️ Software & Tools Used in ISRO

  • OpenFOAM & Fluent – Used for general CFD analysis.
  • ISRO’s In-house CFD Solvers – Developed for hypersonic flow and propulsion studies.
  • ParaView & Tecplot – Used for visualizing simulation results.
  • HPC Clusters"SAGA" supercomputer is used for large-scale simulations.

💡 Example: ISRO used CFD to analyze the Gaganyaan Crew Module’s re-entry heating, ensuring astronauts survive high temperatures.


2️⃣ DRDO: CFD in Defense & Hypersonic Research 🛡️

DRDO (Defence Research and Development Organisation) applies fluid simulations in missiles, hypersonic systems, naval hydrodynamics, and UAVs.

✅ Key CFD Applications in DRDO

  1. Missile Aerodynamics & Guidance

    • CFD is used to simulate airflows around missiles like Agni, BrahMos, and Astra.
    • Studies include drag reduction, shock waves, and stability analysis.
  2. Hypersonic Weapons & Scramjet Engines

    • Hypersonic Technology Demonstrator Vehicle (HSTDV) used CFD for shockwave & heat analysis.
    • Scramjet CFD simulations analyze airflow and combustion at Mach 6+ speeds.
  3. Naval Hydrodynamics & Submarine CFD

    • DRDO’s naval research (NSTL, Visakhapatnam) uses CFD for submarine stealth, torpedo movement, and cavitation studies.
    • Underwater explosions and sonar signal behavior are simulated.
  4. Tank & Aircraft Aerodynamics

    • Arjun & T-90 tanks use CFD for dust flow, heat dissipation, and armor cooling.
    • Tejas Fighter Jet & AMCA (Advanced Medium Combat Aircraft) use CFD for stealth & aerodynamics optimization.

🖥️ Software & Tools Used in DRDO

  • ANSYS Fluent & CFX – Used for general missile & aerodynamics analysis.
  • OpenFOAM & SU2 – Open-source solvers for research & academic collaboration.
  • DRDO In-house CFD Codes – Special codes for hypersonic & naval simulations.
  • HPC Supercomputers"Dhruva" & "Aditya" supercomputers for high-speed calculations.

💡 Example: BrahMos missile’s CFD simulations optimized supersonic airflow and shockwave interaction, improving missile performance.


3️⃣ Research Centers & Universities Involved

Many IITs, IISc, and DRDO labs collaborate on CFD-based aerospace & defense research:

🔹 ISRO’s VSSC (Vikram Sarabhai Space Centre) – CFD for rockets & re-entry.
🔹 DRDO’s ADA (Aeronautical Development Agency) – CFD for Tejas & AMCA jets.
🔹 DRDL (Defence Research & Development Laboratory) – Missile CFD research.
🔹 NSTL (Naval Science & Technological Laboratory) – Naval hydrodynamics & submarine CFD.
🔹 IISc Bangalore & IIT Madras – Hypersonics & scramjet simulations using OpenFOAM.


Conclusion

CFD is a critical technology in ISRO & DRDO for aerospace and defense applications.
ISRO uses CFD for rockets, re-entry vehicles, combustion, and thermal analysis.
DRDO applies CFD in missiles, hypersonic weapons, submarines, and UAVs.
India has strong research in CFD, with IITs, IISc, and DRDO labs leading innovation.

Friday, January 31, 2025

Connecting C++ to Python using Boost.Python...


Gyan.... Knowledge...Wisdom... my wife Reema reciting her own poem...

Many modern C++ applications provide a Python interface because it combines performance (C++) with ease of use (Python). Here’s why this trend has become so popular:

✔ It allows rapid prototyping.
✔ It combines speed (C++) with flexibility (Python).
✔ Python is popular in AI, ML, and scientific computing.
✔ Users can extend software via Python scripting.

 Boost.Python is a powerful library that enables seamless integration between C++ and Python. It allows C++ functions and classes to be exposed to Python, enabling direct interaction between the two languages.

As I was playing around with Boost.Python, I made my existing Factory Pattern project written in C++ to expose itself to the python using Boost.Python library.

The most important part is the following lines of code. This is kind of self explanatory - how we expose the C++ classes and methods to Python code.

// Expose Singleton Factory to Python

BOOST_PYTHON_MODULE(FactoryPattern) {

using namespace boost::python;


class_<Food, boost::noncopyable>("Food", no_init)

.def("getName", pure_virtual(&Food::getName));


class_<Biscuit, bases<Food>>("Biscuit")

.def("getName", &Biscuit::getName); // Ensure Biscuit has getName


class_<Chocolate, bases<Food>>("Chocolate")

.def("getName", &Chocolate::getName); // Ensure Chocolate has getName


class_<Factory, boost::noncopyable>("Factory", no_init)

.def("getInstance", &Factory::getInstance, return_value_policy<reference_existing_object>())

.staticmethod("getInstance")

.def("makeFood", &Factory::makeFood, return_value_policy<manage_new_object>());

}

Here's the complete source code of the C++ Factory Pattern... We will have to make a shared object (so) from this C++ project.

/*

* Food.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef FOOD_H_

#define FOOD_H_

#include <string>


using namespace std;


class Food {

public:

virtual string getName() = 0;


virtual ~Food(){


}

};



#endif /* FOOD_H_ */




/*

* Chocolate.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef CHOCOLATE_H_

#define CHOCOLATE_H_


#include <iostream>

#include "Food.h"


class Chocolate: public Food {

public:

Chocolate();

virtual ~Chocolate();

string getName();

};



#endif /* CHOCOLATE_H_ */




/*

* Chocolate.cpp

*

* Created on: Mar 10, 2021

* Author: som

*/


#include "Chocolate.h"



Chocolate::Chocolate() {

// TODO Auto-generated constructor stub

cout<<"Chocolate is made..."<<endl;


}


Chocolate::~Chocolate() {

// TODO Auto-generated destructor stub

}


string Chocolate::getName(){

return "It's a Chocolate";

}



/*

* Biscuit.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef BISCUIT_H_

#define BISCUIT_H_


#include "Food.h"


class Biscuit: public Food {

public:

Biscuit();

string getName();

~Biscuit();

};


#endif /* BISCUIT_H_ */



/*

* Biscuit.cpp

*

* Created on: Mar 10, 2021

* Author: som

*/

#include <iostream>

#include "Biscuit.h"

using namespace std;



Biscuit::Biscuit() {

// TODO Auto-generated constructor stub

cout<<"Biscuit is made..."<<endl;


}


Biscuit::~Biscuit(){}



string Biscuit::getName(){

return "It's a Biscuit";

}




/*

* Factory.h

*

* Created on: Mar 10, 2021

* Author: som

*/


#ifndef FACTORY_H_

#define FACTORY_H_


#include <boost/python.hpp>

#include <iostream>

#include <string>


#include "Biscuit.h"

#include "Chocolate.h"


using namespace std;


class Factory{

public:

static Factory* instance;

static Factory* getInstance();


Food* makeFood(const string& type);


private:

Factory(){}


// Delete copy constructor & assignment operator (Singleton pattern)

Factory(const Factory&) = delete;

Factory& operator=(const Factory&) = delete;

};




#endif /* FACTORY_H_ */




/*

* Factory.cpp

*

* Created on: Jan 30, 2025

* Author: som

*/

#include "Factory.h"

Factory* Factory::instance = NULL;


Factory* Factory:: getInstance(){

if(Factory::instance == NULL){

Factory::instance = new Factory();

}

return Factory::instance;

}


Food* Factory::makeFood(const string& type){

if(type.compare("bi") == 0){

return new Biscuit();

}

if(type.compare("ch") == 0){

return new Chocolate();

}


return NULL;

}


// Expose Singleton Factory to Python

BOOST_PYTHON_MODULE(FactoryPattern) {

using namespace boost::python;


class_<Food, boost::noncopyable>("Food", no_init)

.def("getName", pure_virtual(&Food::getName));


class_<Biscuit, bases<Food>>("Biscuit")

.def("getName", &Biscuit::getName); // Ensure Biscuit has getName


class_<Chocolate, bases<Food>>("Chocolate")

.def("getName", &Chocolate::getName); // Ensure Chocolate has getName


class_<Factory, boost::noncopyable>("Factory", no_init)

.def("getInstance", &Factory::getInstance, return_value_policy<reference_existing_object>())

.staticmethod("getInstance")

.def("makeFood", &Factory::makeFood, return_value_policy<manage_new_object>());

}


Here's the project settings for the C++ code...








And here's the python script to access the C++ methods.


import FactoryPattern

factory = FactoryPattern.Factory.getInstance()

biscuit = factory.makeFood("bi")
print(biscuit.getName()) # Expected: "Biscuit"

chocolate = factory.makeFood("ch")
print(chocolate.getName()) # Expected: "Chocolate"


Here's a short video showing the output in a Python workspace...



Jai Hind... Jai Bharat...

By the way... there is another way to connect your Python code

to C++ - that is SWIG...


I explored SWIG sometimes back.


Here we go...



Thursday, January 30, 2025

Fluid Simulation and its importance for a career in Computer Graphics -- my exploration continues...

 Fluid simulation is a key area in computer graphics that models the motion and behavior of liquids, gases, and other fluid-like substances. It is highly valuable for careers in VFX, game development, animation, and scientific visualization.

What is Fluid Simulation?

Fluid simulation is the process of using numerical methods to approximate the behavior of liquids and gases. There are two main approaches:

  1. Grid-Based (Eulerian) Simulation

    • Uses a fixed 3D grid (voxels) to store velocity, pressure, and density.
    • Common in smoke, fire, and large-scale water simulations.
    • Examples: Navier-Stokes solvers, Mantaflow, OpenVDB
  2. Particle-Based (Lagrangian) Simulation

    • Uses particles that move with the fluid.
    • Ideal for splashes, droplets, and foam.
    • Examples: SPH (Smoothed Particle Hydrodynamics), FLIP, PIC
  3. Hybrid Methods

    • Combines both grid-based and particle-based approaches
    • Used in high-quality liquid simulations for films and games.
    • Example: FLIP fluids (used in Houdini, Blender Mantaflow)

Why is Fluid Simulation Important for a Career in Computer Graphics?

1️⃣ VFX & Animation Industry 🎬

  • Used in Hollywood movies for realistic water, explosions, and smoke.
  • Example: Houdini's FLIP & Pyro Solver (used in Marvel movies, Pixar, DreamWorks).
  • Tools to Learn: Houdini, Blender Mantaflow, Maya Bifrost, RealFlow

2️⃣ Game Development 🎮

  • Fluid physics makes games more immersive.
  • Used for realistic water, blood splatter, fog, and lava.
  • Example: Unreal Engine Niagara, Unity Visual Effects Graph, NVIDIA Flex
  • Tools to Learn: Unity, Unreal Engine, Frostbite (EA), CryEngine

3️⃣ CAD, Engineering & Scientific Simulations 🏗️

  • Simulations for aerodynamics, weather forecasting, and biomedical applications.
  • Example: CFD (Computational Fluid Dynamics) for car designs (used in F1, Tesla).
  • Tools to Learn: OpenFOAM, ANSYS Fluent, SimScale

4️⃣ Machine Learning & AI in Fluid Simulation 🤖

  • AI can speed up simulations using deep learning (e.g., Neural Fluid Simulation).
  • Example: Google’s AI FluidNet, NVIDIA's AI-driven smoke & fire simulation
  • Tools to Learn: PyTorch, TensorFlow, Taichi, JAX, CUDA

How to Get Started?

1️⃣ Learn the Basics

  • Study Navier-Stokes equations and basic physics behind fluids.
  • Try JavaFX or Python (Mantaflow, OpenFOAM) to experiment.

2️⃣ Experiment with Simulation Tools

  • Blender Mantaflow (Beginner)
  • Houdini (Professional VFX)
  • Unity/Unreal Engine (Game fluids)
  • OpenFOAM/ANSYS (Scientific applications)

3️⃣ Develop Your Own Fluid Simulation Algorithms

  • Try coding FLIP/SPH algorithms in Java, C++, or Python.
  • Learn GPU acceleration (CUDA, OpenCL, Vulkan) to optimize performance.

4️⃣ Specialize in a Field

  • Movies/VFX? → Learn Houdini, RealFlow, Blender
  • Games? → Learn Unity, Unreal Engine, NVIDIA Flex
  • Scientific Simulation? → Learn OpenFOAM, CFD, Python ML for fluids
Here's my exploration of openFOAM....

Enjoy...

Jai Hind...

Tuesday, January 28, 2025

B-Spline curve in Javafx...

 A B-spline (Basis Spline) is a type of smooth, piecewise-defined curve commonly used in computer graphics, computer-aided design (CAD), and other computational fields. It generalizes Bézier curves by providing greater flexibility and control over the shape of the curve while maintaining important mathematical properties like smoothness and continuity.


Key Properties of B-Splines

  1. Piecewise Polynomial:

    • A B-spline curve is defined by connecting multiple polynomial segments, ensuring a smooth transition between them.
  2. Control Points:

    • A B-spline is influenced by a set of control points. These points do not necessarily lie on the curve, but they define its general shape.
  3. Degree (Order):

    • The degree of the B-spline determines the complexity of the curve segments (linear, quadratic, cubic, etc.).
    • Higher-degree B-splines produce smoother curves.
  4. Knots:

    • A knot vector is used to divide the curve into segments and determines how the control points influence the curve. Knots can be uniform (evenly spaced) or non-uniform (custom spacing).
  5. Continuity:

    • The continuity of a B-spline curve depends on its degree and the knot vector. It ensures smooth transitions between segments (e.g., C0,C1,C2C^0, C^1, C^2 continuity).
  6. Local Control:

    • Modifying a control point affects only a portion of the curve, making B-splines highly versatile for designing complex shapes.

Mathematical Definition

A B-spline curve is defined as:

C(t)=i=0nNi,k(t)PiC(t) = \sum_{i=0}^{n} N_{i,k}(t) \mathbf{P}_i
  • Pi\mathbf{P}_i: Control points.

  • Ni,k(t)N_{i,k}(t): Basis functions of degree kk, calculated recursively using the Cox-de Boor recursion formula:

    Ni,0(t)={1if tit<ti+10otherwiseN_{i,0}(t) = \begin{cases} 1 & \text{if } t_i \leq t < t_{i+1} \\ 0 & \text{otherwise} \end{cases} Ni,k(t)=ttiti+ktiNi,k1(t)+ti+k+1tti+k+1ti+1Ni+1,k1(t)N_{i,k}(t) = \frac{t - t_i}{t_{i+k} - t_i} N_{i,k-1}(t) + \frac{t_{i+k+1} - t}{t_{i+k+1} - t_{i+1}} N_{i+1,k-1}(t)
  • tt: Parametric value in the range of the knot vector.


Applications of B-Splines

  1. CAD and CAM:

    • Used for designing and manufacturing complex surfaces and shapes.
  2. Animation:

    • Smooth interpolation of motion paths or object deformation.
  3. Data Fitting:

    • Approximate noisy data points with smooth curves.
  4. Computer Graphics:

    • Modeling free-form curves and surfaces (e.g., NURBS, a special type of B-spline).
  5. Image Processing:

    • Resampling and interpolation of image data.

Advantages of B-Splines

  • Greater flexibility than Bézier curves.
  • Local control ensures efficiency in complex modeling tasks.
  • Customizable smoothness and continuity.
  • Can represent a Bézier curve or polynomial curve as a special case.



And here we go... the source code of B-Spline implemented in Javafx...

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Path;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.CubicCurveTo;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class BSplineDemo extends Application {

private final List<Circle> controlPoints = new ArrayList<>();
private final Path bSplinePath = new Path();

@Override
public void start(Stage primaryStage) {
// Create the main pane
Pane pane = new Pane();
pane.setStyle("-fx-background-color: #f4f4f4");

// Add initial control points
addControlPoint(pane, 100, 200);
addControlPoint(pane, 200, 100);
addControlPoint(pane, 300, 250);
addControlPoint(pane, 400, 150);
addControlPoint(pane, 500, 200);

// Configure the B-spline path
bSplinePath.setStroke(Color.BLACK);
bSplinePath.setStrokeWidth(2);
bSplinePath.setFill(null);

// Add path and points to the pane
pane.getChildren().add(bSplinePath);
updateBSpline();

// Create the scene
Scene scene = new Scene(pane, 600, 400);
primaryStage.setTitle("B-Spline Demo");
primaryStage.setScene(scene);
primaryStage.show();
}

// Adds a draggable control point
private void addControlPoint(Pane pane, double x, double y) {
Circle point = new Circle(x, y, 8, Color.RED);
point.setStroke(Color.BLACK);
point.setStrokeWidth(1);
point.setOnMouseDragged(event -> {
point.setCenterX(event.getX());
point.setCenterY(event.getY());
updateBSpline();
});
controlPoints.add(point);
pane.getChildren().add(point);
}

// Updates the B-spline path
private void updateBSpline() {
if (controlPoints.size() < 4) {
bSplinePath.getElements().clear(); // Clear path if not enough points
return;
}

bSplinePath.getElements().clear();

// Use the de Boor algorithm for cubic B-spline interpolation
for (int i = 1; i < controlPoints.size() - 2; i++) {
Circle p0 = controlPoints.get(i - 1);
Circle p1 = controlPoints.get(i);
Circle p2 = controlPoints.get(i + 1);
Circle p3 = controlPoints.get(i + 2);

// Define cubic curve control points
double x1 = (p0.getCenterX() + 4 * p1.getCenterX() + p2.getCenterX()) / 6;
double y1 = (p0.getCenterY() + 4 * p1.getCenterY() + p2.getCenterY()) / 6;

double x2 = (p1.getCenterX() + 4 * p2.getCenterX() + p3.getCenterX()) / 6;
double y2 = (p1.getCenterY() + 4 * p2.getCenterY() + p3.getCenterY()) / 6;

double xControl1 = (2 * p1.getCenterX() + p2.getCenterX()) / 3;
double yControl1 = (2 * p1.getCenterY() + p2.getCenterY()) / 3;

double xControl2 = (p1.getCenterX() + 2 * p2.getCenterX()) / 3;
double yControl2 = (p1.getCenterY() + 2 * p2.getCenterY()) / 3;

// First point
if (i == 1) {
bSplinePath.getElements().add(new MoveTo(x1, y1));
}

// Add cubic segment
bSplinePath.getElements().add(new CubicCurveTo(xControl1, yControl1, xControl2, yControl2, x2, y2));
}
}

public static void main(String[] args) {
launch(args);
}
}

Bezier curve revisited - an implementation using Javafx...

 Cubic Bézier curves...

Four points P0, P1, P2 and P3 in the plane or in higher-dimensional space define a cubic Bézier curve. The curve starts at P0 going toward P1 and arrives at P3 coming from the direction of P2. Usually, it will not pass through P1 or P2; these points are only there to provide directional information. The distance between P1 and P2 determines "how far" and "how fast" the curve moves towards P1 before turning towards P2.

Writing BPi,Pj,Pk(t) for the quadratic Bézier curve defined by points PiPj, and Pk, the cubic Bézier curve can be defined as an affine combination of two quadratic Bézier curves:

The explicit form of the curve is:


Any series of 4 distinct points can be converted to a cubic Bézier curve that goes through all 4 points in order. Given the starting and ending point of some cubic Bézier curve, and the points along the curve corresponding to t = 1/3 and t = 2/3, the control points for the original Bézier curve can be recovered.

Here's how it looks like - an experimentation...


And here's the source code of the experimentation (JavaFx application)...

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class BezierCurveDemo extends Application {

@Override
public void start(Stage primaryStage) {
// Main pane
Pane pane = new Pane();

// Control points
Circle start = createControlPoint(100, 300, Color.RED); // Start point
Circle control1 = createControlPoint(200, 100, Color.BLUE); // First control point
Circle control2 = createControlPoint(400, 100, Color.BLUE); // Second control point
Circle end = createControlPoint(500, 300, Color.RED); // End point

// Lines to show the control points
Line line1 = new Line();
Line line2 = new Line();

line1.startXProperty().bind(start.centerXProperty());
line1.startYProperty().bind(start.centerYProperty());
line1.endXProperty().bind(control1.centerXProperty());
line1.endYProperty().bind(control1.centerYProperty());
line1.setStroke(Color.LIGHTGRAY);

line2.startXProperty().bind(control2.centerXProperty());
line2.startYProperty().bind(control2.centerYProperty());
line2.endXProperty().bind(end.centerXProperty());
line2.endYProperty().bind(end.centerYProperty());
line2.setStroke(Color.LIGHTGRAY);

// Bezier Curve
CubicCurve bezierCurve = new CubicCurve();
bezierCurve.setStroke(Color.BLACK);
bezierCurve.setFill(null);
bezierCurve.setStrokeWidth(2);

bezierCurve.startXProperty().bind(start.centerXProperty());
bezierCurve.startYProperty().bind(start.centerYProperty());
bezierCurve.controlX1Property().bind(control1.centerXProperty());
bezierCurve.controlY1Property().bind(control1.centerYProperty());
bezierCurve.controlX2Property().bind(control2.centerXProperty());
bezierCurve.controlY2Property().bind(control2.centerYProperty());
bezierCurve.endXProperty().bind(end.centerXProperty());
bezierCurve.endYProperty().bind(end.centerYProperty());

// Add everything to the pane
pane.getChildren().addAll(line1, line2, bezierCurve, start, control1, control2, end);

// Create scene and display
Scene scene = new Scene(pane, 600, 400);
primaryStage.setTitle("Bezier Curve Demo");
primaryStage.setScene(scene);
primaryStage.show();
}

// Helper function to create control points
private Circle createControlPoint(double x, double y, Color color) {
Circle circle = new Circle(8, color);
circle.setCenterX(x);
circle.setCenterY(y);

// Make control points draggable
circle.setOnMouseDragged(event -> {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
});

return circle;
}

public static void main(String[] args) {
launch(args);
}
}