A small full-stack project for computing 4x4 homogeneous transformation matrices from a 3D pose. Given a translation plus a rotation (as either Euler angles or a quaternion), it returns the corresponding transformation matrix.
The project has two parts:
backend/transformation_matrix_api— a Python FastAPI service that does the actual math (viatorchandscipy.spatial.transform.Rotation), optionally on GPU.webapp— an ASP.NET Core MVC (.NET) web app that provides a simple UI for entering a pose and viewing the resulting matrix, calling the API behind the scenes.
Both services are also fully dockerized and can be run together with a single docker compose up.
- The user fills in a pose on the web app — either:
- Euler:
x, y, z, euler_x, euler_y, euler_z(angles in degrees), or - Quaternion:
x, y, z, qw, qx, qy, qz
- Euler:
- The web app posts the pose to the backend API.
- The API builds a 3x3 rotation matrix from the input (Euler or quaternion) and combines it with the translation into a 4x4 homogeneous transformation matrix.
- The result is returned as JSON and rendered in the web app.
TransformationMatrixProject/
├── backend/
│ └── transformation_matrix_api/
│ ├── main.py # entrypoint
│ ├── communication/
│ │ ├── transformation_matrix_api.py # FastAPI server + routes
│ │ └── schema.py # request/response models (pydantic)
│ ├── transformation_matrix/
│ │ └── transformation_matrix.py # core matrix math (torch + scipy)
│ ├── utils/
│ │ └── utils.py # config loading, device selection
│ ├── config/
│ │ └── config_server.yaml # server config (host, port, CUDA, debug)
│ ├── docker/
│ │ └── Dockerfile # backend image
│ ├── .dockerignore
│ └── requirements.txt
├── webapp/
│ ├── Controllers/HomeController.cs # MVC controller
│ ├── Services/ # HTTP client for the backend API
│ ├── Models/ # request models (Euler / Quaternion)
│ ├── Configuration/ # typed API config binding
│ ├── Views/ # Razor views (forms + result page)
│ ├── Program.cs # app startup
│ ├── docker/
│ │ └── Dockerfile # webapp image
│ └── .dockerignore
└── docker-compose.yml # runs backend + webapp together
A FastAPI service exposing:
| Method | Route | Description |
|---|---|---|
GET |
/home |
Health/welcome check |
POST |
/v1/single_transformation |
Compute a single transformation matrix from a Euler or quaternion pose |
POST |
/v1/run_batch_transformations/{object_id} |
Kick off a batch of transformation computations in a background process |
GET |
/server_status |
Current server state (ServerFree, ServerBusy, Error) and active object ID |
POST |
/reset_error |
Reset the server out of an Error state |
Rotation math is handled with scipy.spatial.transform.Rotation, and matrices are built and returned as torch.Tensors (with optional CUDA acceleration, configurable via config/config_server.yaml).
Euler:
{
"x": 10, "y": 10, "z": 10,
"euler_x": 0, "euler_y": 0, "euler_z": 0
}Quaternion:
{
"x": 10, "y": 10, "z": 10,
"qw": 0.9437, "qx": 0.2685, "qy": 0.1449, "qz": 0.1277
}cd backend/transformation_matrix_api
pip install -r requirements.txt
python main.pyBy default the API listens on 0.0.0.0:8000 (see config/config_server.yaml). A debug server (via debugpy) also listens on 0.0.0.0:5678 when DEBUG_MODE: true, and will pause startup waiting for a debugger to attach — set DEBUG_MODE: false in the config if you just want to run it normally.
An ASP.NET Core MVC app (targeting .NET 10) with pages for entering a pose (Euler or quaternion form) and viewing the resulting matrix.
Services/TransformationMatrixClient.cs— typedHttpClientthat posts the pose to the backend's/v1/single_transformationendpoint.Configuration/TransformationMatrixConfig.cs— binds the backend base URL and endpoint fromappsettings.Controllers/HomeController.cs— handles the Euler/Quaternion forms and renders the resulting matrix via theResponseview.
The backend location is configured under the TransformationMatrixApi section, e.g. in appsettings.Development.json:
{
"TransformationMatrixApi": {
"BaseUrl": "http://localhost:8000/",
"SingleTransformationEndpoint": "v1/single_transformation"
}
}Update BaseUrl if the API is running elsewhere. (When running via Docker Compose, this is instead supplied through environment variables — see below.)
Requires the .NET 10 SDK.
cd webapp
dotnet restore
dotnet runThen open the app in your browser (the exact URL is printed on startup, e.g. https://localhost:5001), and make sure the backend API is running first so the forms have something to call.
This is the easiest way to run the full stack — no local Python or .NET installs required, just Docker and Docker Compose.
docker compose up --buildThis builds and starts:
backend— the FastAPI service, published onhttp://localhost:8000webapp— the ASP.NET Core app, published onhttp://localhost:8080, configured (via environment variables indocker-compose.yml) to call the backend athttp://backend:8000/using Docker's internal networking
Once both are up, open http://localhost:8080 and submit a pose.
To stop everything:
docker compose downNote on debug mode: The backend's Dockerfile disables
DEBUG_MODEat build time (it'strueinconfig/config_server.yaml, which otherwise makes the server block on startup waiting for adebugpyclient to attach). If you want to attach a remote debugger to the containerized backend, remove that step from the Dockerfile and publish port5678.
Without Docker:
- Backend: Python 3.x,
pip, and optionally CUDA + a compatible GPU for accelerated computation. - Frontend: .NET 10 SDK.
With Docker:
- Docker and Docker Compose only.
No license has been specified for this project yet.