diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..f8d25a8b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,57 @@
+BasedOnStyle: Google
+Language: Cpp
+Standard: c++20
+
+# Indentation
+IndentWidth: 4
+TabWidth: 4
+UseTab: Never
+NamespaceIndentation: All
+IndentCaseLabels: true
+IndentPPDirectives: BeforeHash
+
+# Line length
+ColumnLimit: 100
+
+# Braces
+BreakBeforeBraces: Attach
+AllowShortBlocksOnASingleLine: Empty
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+
+# Alignment
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignOperands: Align
+AlignTrailingComments: true
+
+# Includes
+SortIncludes: CaseInsensitive
+IncludeBlocks: Preserve
+
+# Spacing
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpacesInParentheses: false
+SpacesInAngles: Never
+
+# Penalties
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+
+# Pointer/reference alignment
+PointerAlignment: Left
+ReferenceAlignment: Left
+
+# Other
+ReflowComments: true
+BinPackArguments: true
+BinPackParameters: true
+AllowAllParametersOfDeclarationOnNextLine: true
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..25761c43
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,33 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+[*.{js,json,css,html}]
+indent_style = space
+indent_size = 4
+
+[*.{cpp,h,hpp,c}]
+indent_style = space
+indent_size = 4
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[*.{sh,bash}]
+indent_style = space
+indent_size = 4
+
+[*.{yaml,yml}]
+indent_style = space
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 5114bafe..67dffd9a 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -11,17 +11,9 @@
# Python Web Server
/Software/web-server/ @connorgallopo
-# Yolo Model + Tooling
-/Software/GroundTruthAnnotator/ @connorgallopo
+# Image Processing
/Software/LMSourceCode/ImageProcessing/ @jamespilgrim @connorgallopo
-# Documentation files
-/docs/ @jeshernandez @connorgallopo
-/docs/hardware/ @markjonharman
-
-# Installation Scripts
-/Dev/ @jeshernandez @connorgallopo
-
# Hardware
/Hardware/ @markjonharman
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index aae94247..d2a37453 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -9,7 +9,7 @@ body:
## Thanks for helping improve PiTrac! 🏌️
Before submitting, please:
- - Check our [Troubleshooting Guide](https://pitraclm.github.io/PiTrac/troubleshooting/troubleshooting.html)
+ - Check our [Troubleshooting Guide](https://docs.pitrac.org/reference/troubleshooting/)
- Search [existing issues](https://github.com/pitraclm/pitrac/issues)
- Join our [Discord](https://discord.gg/vGuyAAxXJH) for community help
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index cbc0cde5..456faa85 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -9,7 +9,7 @@ body:
## Feature Request
Help us make PiTrac better! Consider:
- - Checking our [Roadmap](https://pitraclm.github.io/PiTrac/getting-started/roadmap.html)
+ - Checking our [Roadmap](https://docs.pitrac.org/reference/roadmap/)
- type: dropdown
id: feature-area
attributes:
diff --git a/.github/ISSUE_TEMPLATE/hardware_issue.yml b/.github/ISSUE_TEMPLATE/hardware_issue.yml
index ac180236..536fd981 100644
--- a/.github/ISSUE_TEMPLATE/hardware_issue.yml
+++ b/.github/ISSUE_TEMPLATE/hardware_issue.yml
@@ -9,8 +9,8 @@ body:
## Hardware Issue Report 🔧
For hardware help, also check:
- - [Hardware Assembly Guide](https://pitraclm.github.io/PiTrac/hardware/assembly-guide.html)
- - [Parts List](https://pitraclm.github.io/PiTrac/hardware/parts-list.html)
+ - [Hardware Assembly Guide](https://docs.pitrac.org/hardware/v3-enclosure/assembly/)
+ - [Parts List](https://docs.pitrac.org/hardware/parts-list/)
- type: dropdown
id: hardware-category
diff --git a/.github/workflows/camera-tests.yml b/.github/workflows/camera-tests.yml
deleted file mode 100644
index 916fbc8d..00000000
--- a/.github/workflows/camera-tests.yml
+++ /dev/null
@@ -1,81 +0,0 @@
----
-name: Camera Tests
-on:
- push:
- branches:
- - "**"
- paths:
- - 'Software/LMSourceCode/ImageProcessing/Camera/**'
- - '.github/workflows/camera-tests.yml'
- pull_request:
- branches:
- - "**"
- paths:
- - 'Software/LMSourceCode/ImageProcessing/Camera/**'
- - '.github/workflows/camera-tests.yml'
-env:
- BOOST_VERSION: 1.84.0
- BOOST_MSVC_VERSION: "14.3"
-jobs:
- camera-tests:
- name: Camera Bounded Context Tests
- runs-on: windows-latest
- defaults:
- run:
- working-directory: Software/LMSourceCode/ImageProcessing/Camera
- steps:
-
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Install CMake
- uses: jwlawson/actions-setup-cmake@v2
- with:
- cmake-version: "3.20"
-
- - name: Install boost
- uses: MarkusJx/install-boost@v2
- id: install-boost
- with:
- boost_version: ${{ env.BOOST_VERSION }}
- boost_install_dir: C:\Dev_Env\
- platform_version: 2019
- toolset: msvc
-
- - name: Setup MSVC
- uses: ilammy/msvc-dev-cmd@v1
- with:
- arch: x64
-
- - name: Configure CMake
- run: >
- mkdir build
-
- cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -B build -DBoost_INCLUDE_DIR=${{steps.install-boost.outputs.BOOST_ROOT}}/include -DBoost_LIBRARY_DIRS=${{steps.install-boost.outputs.BOOST_ROOT}}/lib
- env:
- BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }}
-
- - name: Build tests
- run: |
- cd build
- cmake --build . --config Debug
- shell: pwsh
-
- - name: Quick Test Validation
- run: |
- Write-Host "=== Running Direct Test Executable ==="
- ./build/tests/camera_tests.exe
- shell: pwsh
-
- - name: Comprehensive Test Report
- run: |
- Write-Host "=== Running CTest with Detailed Reporting ==="
- cd build/tests
-
- # Run CTest with XML output (JUnit format) from the tests directory
- ctest -C Debug --verbose --output-on-failure --output-junit ./build/tests/test-results.xml
-
- # Debug: Show what files were created
- Write-Host "=== Files in tests directory after CTest ==="
- Get-ChildItem | Format-Table Name, Length
- shell: pwsh
diff --git a/.github/workflows/docs-ci.yml b/.github/workflows/docs-ci.yml
deleted file mode 100644
index 8d22e4ac..00000000
--- a/.github/workflows/docs-ci.yml
+++ /dev/null
@@ -1,42 +0,0 @@
----
-name: Docs CI (build only)
-"on":
- pull_request:
- paths:
- - "docs/**"
-
-permissions:
- contents: read
-
-concurrency:
- group: docs-ci-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- build:
- name: Build Docs (no deploy)
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: docs
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Ruby
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: '3.3' # or omit to use docs/.ruby-version
- bundler-cache: true
- cache-version: 0
- env:
- BUNDLE_GEMFILE: ${{ github.workspace }}/docs/Gemfile
-
- - name: Generate Just the Docs search index
- run: bundle exec just-the-docs rake search:init
-
- - name: Build with Jekyll
- env:
- JEKYLL_ENV: production
- run: bundle exec jekyll build
diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml
deleted file mode 100644
index c3e10921..00000000
--- a/.github/workflows/docs-deploy.yml
+++ /dev/null
@@ -1,76 +0,0 @@
----
-name: Build & Deploy PiTrac Docs to GitHub Pages
-"on":
- push:
- branches:
- - "main"
- paths:
- - "docs/**"
- workflow_dispatch: {}
-
-permissions:
- contents: read
- pages: write
- id-token: write
-
-concurrency:
- group: pages
- cancel-in-progress: true
-
-jobs:
- build:
- name: Build Docs
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: docs
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Ruby
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: '3.3' # or omit to use docs/.ruby-version
- bundler-cache: true
- cache-version: 0
- env:
- # Ensure bundler resolves against the docs Gemfile
- BUNDLE_GEMFILE: ${{ github.workspace }}/docs/Gemfile
-
- - name: Generate Just the Docs search index
- run: bundle exec just-the-docs rake search:init
-
- - name: Setup Pages
- id: pages
- uses: actions/configure-pages@v5
-
- - name: Build with Jekyll
- env:
- JEKYLL_ENV: production
- run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
-
- - name: Verify build output
- run: |
- pwd
- ls -la _site || true
- ls -la docs/_site || true
-
- - name: Upload artifact
- uses: actions/upload-pages-artifact@v3
- with:
- path: docs/_site
-
- deploy:
- name: Deploy Docs to Pages
- needs: build
- runs-on: ubuntu-latest
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
- steps:
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v4
diff --git a/.github/workflows/image-analysis-tests.yml b/.github/workflows/image-analysis-tests.yml
deleted file mode 100644
index 55455d92..00000000
--- a/.github/workflows/image-analysis-tests.yml
+++ /dev/null
@@ -1,96 +0,0 @@
----
-name: Image Analysis Tests
-on:
- push:
- branches:
- - "**"
- paths:
- - 'Software/LMSourceCode/ImageProcessing/ImageAnalysis/**'
- - '.github/workflows/image-analysis-tests.yml'
- pull_request:
- branches:
- - "**"
- paths:
- - 'Software/LMSourceCode/ImageProcessing/ImageAnalysis/**'
- - '.github/workflows/image-analysis-tests.yml'
-env:
- BOOST_VERSION: 1.87.0
- BOOST_ROOT: C:\Dev_Env\boost\boost
- OPENCV_DIR: C:\tools\opencv
-jobs:
- camera-tests:
- name: Image Analysis Tests
- runs-on: windows-latest
- defaults:
- run:
- working-directory: Software/LMSourceCode/ImageProcessing/ImageAnalysis
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Cache OpenCV
- uses: actions/cache@v3
- with:
- path: ${{ env.OPENCV_DIR }}
- key: ${{ runner.os }}-opencv-4.10.0-binaries
- restore-keys: |
- ${{ runner.os }}-opencv-4.10.0-
-
- - name: Install CMake
- uses: jwlawson/actions-setup-cmake@v2
- with:
- cmake-version: "4.0.3"
-
- - name: Install OpenCV
- run: |
- if (-not (Test-Path "$env:OPENCV_DIR")) {
- Write-Host "Installing OpenCV 4.10.0..."
- New-Item -ItemType Directory -Path C:\tools -Force
- pushd C:\tools
- $url = "https://github.com/opencv/opencv/releases/download/4.10.0/opencv-4.10.0-windows.exe"
- Invoke-WebRequest -Uri $url -OutFile "opencv.exe"
- Start-Process -FilePath "opencv.exe" -ArgumentList "-o", "$env:OPENCV_DIR", "-y" -Wait
- Remove-Item "opencv.exe"
- Write-Host "✓ OpenCV installed at $env:OPENCV_DIR"
- popd
- } else {
- Write-Host "✓ OpenCV found in cache"
- }
- shell: pwsh
-
- - name: Install boost
- uses: MarkusJx/install-boost@v2
- with:
- boost_version: ${{ env.BOOST_VERSION }}
- boost_install_dir: C:\Dev_Env\
- platform_version: 2022
- toolset: msvc
-
- - name: Setup MSVC
- uses: ilammy/msvc-dev-cmd@v1
- with:
- arch: x64
-
- - name: Configure CMake
- run: |
- if (Test-Path build) { Remove-Item build -Recurse -Force }
- mkdir build
- $OpenCVConfigPath = "$env:OPENCV_DIR\build"
-
- cmake -B build -DCMAKE_BUILD_TYPE=Release -DOPENCV_DIR="$OpenCVConfigPath"
- shell: pwsh
-
- - name: Build and Test
- run: |
- pushd build
- cmake --build . --config Release
-
- # Add OpenCV DLLs to PATH for test execution
- $opencvBinPath = "$env:OPENCV_DIR\build\x64\vc16\bin"
- if (Test-Path $opencvBinPath) {
- $env:PATH = "$opencvBinPath;$env:PATH"
- }
-
- ctest -C Release --output-on-failure
- popd
- shell: pwsh
diff --git a/.gitignore b/.gitignore
index 0f6068d7..6cf86bb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -100,4 +100,7 @@ Dev/scripts/__pycache__
packaging/pitrac
# FreeCAD backup files
-*.FCBak
\ No newline at end of file
+*.FCBak
+
+# Node.js (root-level tooling)
+node_modules/
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..0bc201d9
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,54 @@
+# Build artifacts
+build/
+builddir/
+out/
+dist/
+target/
+node_modules/
+
+# C++ (use clang-format instead)
+*.cpp
+*.h
+*.hpp
+*.c
+
+# Shell scripts (use shfmt instead)
+*.sh
+
+# Minified / vendored
+*.min.js
+*.min.css
+
+# Binary and ML artifacts
+*.pt
+*.onnx
+*.deb
+*.so
+*.o
+
+# Hardware / CAD files
+Hardware/
+3D Printed Parts/
+*.kicad_pcb
+*.kicad_sch
+*.FCBak
+
+
+# Generated coverage
+htmlcov/
+.coverage
+
+# Packaging artifacts
+packaging/deps-artifacts/
+packaging/pitrac
+
+# Python caches
+__pycache__/
+*.pyc
+*.egg-info/
+.pytest_cache/
+
+# Vendor / env
+vendor/
+venv/
+.venv/
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..5d204970
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,27 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "tabWidth": 4,
+ "useTabs": false,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "bracketSpacing": true,
+ "arrowParens": "always",
+ "endOfLine": "lf",
+ "htmlWhitespaceSensitivity": "css",
+ "proseWrap": "preserve",
+ "overrides": [
+ {
+ "files": "*.yaml",
+ "options": {
+ "tabWidth": 2
+ }
+ },
+ {
+ "files": "*.yml",
+ "options": {
+ "tabWidth": 2
+ }
+ }
+ ]
+}
diff --git a/3D Printed Parts/Enclosure Version 2/Tower-Single-Pi-V2-Connector-Board-Variant/README.md b/3D Printed Parts/Enclosure Version 2/Tower-Single-Pi-V2-Connector-Board-Variant/README.md
index 0989de1c..d9ae0f87 100755
--- a/3D Printed Parts/Enclosure Version 2/Tower-Single-Pi-V2-Connector-Board-Variant/README.md
+++ b/3D Printed Parts/Enclosure Version 2/Tower-Single-Pi-V2-Connector-Board-Variant/README.md
@@ -21,7 +21,7 @@ Recommended print settings: 2 perimeter layers, 15% infill, grid or rectilinear
Please note that the default version is setup to accept 4 M2.5 and 4 M3 inner-diameter screw-in (or melt-in) inserts in which to screw the Pi and the V2 Connector Board. The specific inserts are M2.5*4*3.5 and M3*4*5 inserts, and the mounting screws are M2.5x6mm and M3x6mm bolts.
If you want to instead simply use self-threading screws, change the values in the Monitor Chassis Parameters spreadsheet in rows 104 (GsPi5MountingHoleDiameter) and 110 (GSConnectorBoardMountingHoleDiameter) as per the comments in those rows.
-See the [main assembly instructions](https://pitraclm.github.io/PiTrac/hardware/assembly-guide.html).
+See the [main assembly instructions](https://docs.pitrac.org/hardware/v3-enclosure/assembly/).
Ultimately, the four parts will be glued together with something like thick, slower-drying super-glue such as Starbond Gap Filler Thick High Performance Super Glue and then screwed together with
12 M2 x 6 self-tapping screws for additional strength in the lap joint (if desired).
diff --git a/A Note On Images.md b/A Note On Images.md
deleted file mode 100644
index d1bae4f8..00000000
--- a/A Note On Images.md
+++ /dev/null
@@ -1 +0,0 @@
-One note on images in the documentation. We don't currently have a good pipeline to convert the documentation we're writing into markdown (.md) files with embedded images. As a short term work-around for now, we're releasing the documentation in .rtf format--with embedded images--to make it easier for folks to download and view them. We will add images inline into documents as we can.
diff --git a/README.md b/README.md
index 1f2c77ea..38e17321 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Introducing [PiTrac](https://hackaday.io/project/195042-pitrac-the-diy-golf-laun
PiTrac uses low-cost Raspberry Pi(\*) computers and cameras to determine golf ball launch speed, angles and spin in three dimensions. PiTrac interfaces with both GSPro and E6/TruGolf simulators, and its output is also accessible on a stand-alone web-based app. \[We’ve reached out to 2k/TopGolf, but no response yet.\]
-PiTrac uses off-the-shelf hardware, and includes a [parts list](https://pitraclm.github.io/PiTrac/hardware/parts-list.html) with links to potential suppliers. The only custom part is a small printed circuit board. The fabrication instructions for that PCB are included in the open-source distribution and it can be manufactured for a few dollars. The two Pi computers and cameras are the most expensive parts, and cost around $250 in total.
+PiTrac uses off-the-shelf hardware, and includes a [parts list](https://docs.pitrac.org/hardware/parts-list/) with links to potential suppliers. The only custom part is a small printed circuit board. The fabrication instructions for that PCB are included in the open-source distribution and it can be manufactured for a few dollars. The two Pi computers and cameras are the most expensive parts, and cost around $250 in total.
PiTrac is not a commercial product for sale–the full design is being released as open source on GitHub for folks to build themselves. It’s not easy, but if you’re handy with a soldering iron, can figure out how to 3D print the parts, and are willing to burrow into the Linux operating system to compile and install software, you should be able to create your own PiTrac\!
@@ -26,10 +26,10 @@ Finally, any help at our [support page](https://ko-fi.com/Pitrac) would be appre
(\*) Raspberry Pi is a trademark of Raspberry Pi Ltd. The PiTrac project is not endorsed, sponsored by or associated with Raspberry Pi or Raspberry Pi products or services.
-## [Getting Started](https://pitraclm.github.io/PiTrac/build-guide.html)
+## [Getting Started](https://docs.pitrac.org/build-guide/)
The process of building your own PiTrac DIY Launch Monitor is described here at a high level. There are several more-detailed instruction documents elsewhere in the PiTrac repository that are referred to below for various sub-assemblies and tasks like compiling the code and preparing the build environment.
-## [Setup and Configuration](https://pitraclm.github.io/PiTrac/software/pi-setup.html)
+## [Setup and Configuration](https://docs.pitrac.org/software/pi-setup/)
The instructions which are targeted toward getting setup on a step-by-step basis. These instructions start with a Raspberry Pi with nothing on it, and are meant to describe all the steps to get from that point to a working, compiled version of PiTrac. A single RPi5 is currently our recommended path for everyone, however the path to stereoscopic vision may require two (if/when we head down that path).
## [Join the Discord](https://discord.gg/gMQcBBQYHT)
diff --git a/Software/CalibrateCameraDistortions/CAM1_cameraDistortion.txt b/Software/CalibrateCameraDistortions/CAM1_cameraDistortion.txt
deleted file mode 100755
index 5905195a..00000000
--- a/Software/CalibrateCameraDistortions/CAM1_cameraDistortion.txt
+++ /dev/null
@@ -1 +0,0 @@
--5.323350228082535107e-01,3.171607772519656199e-01,7.282375091653870043e-04,7.032344616124524064e-03,-9.732216388053896439e-02
diff --git a/Software/CalibrateCameraDistortions/CAM1_cameraMatrix.txt b/Software/CalibrateCameraDistortions/CAM1_cameraMatrix.txt
deleted file mode 100755
index 8aded5a3..00000000
--- a/Software/CalibrateCameraDistortions/CAM1_cameraMatrix.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-1.748506644661262953e+03,0.000000000000000000e+00,6.325374407393054526e+02
-0.000000000000000000e+00,1.743341748687922745e+03,4.075677927449370941e+02
-0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00
diff --git a/Software/CalibrateCameraDistortions/CAM2_cameraDistortion.txt b/Software/CalibrateCameraDistortions/CAM2_cameraDistortion.txt
deleted file mode 100755
index a9e106db..00000000
--- a/Software/CalibrateCameraDistortions/CAM2_cameraDistortion.txt
+++ /dev/null
@@ -1,2 +0,0 @@
--6.948635618535150549e-01,7.029040186611693608e-01,2.925955790297951262e-03,
--1.668301926579529105e-03,-6.406782685787516529e-01
diff --git a/Software/CalibrateCameraDistortions/CAM2_cameraMatrix.txt b/Software/CalibrateCameraDistortions/CAM2_cameraMatrix.txt
deleted file mode 100755
index 276c42fd..00000000
--- a/Software/CalibrateCameraDistortions/CAM2_cameraMatrix.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-2.026993214521951359e+03,0.000000000000000000e+00,7.447811698165936605e+02
-0.000000000000000000e+00,2.038030194859141375e+03,5.953631744844495870e+02
-0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00
diff --git a/Software/CalibrateCameraDistortions/CameraCalibration.py b/Software/CalibrateCameraDistortions/CameraCalibration.py
deleted file mode 100755
index 41765cea..00000000
--- a/Software/CalibrateCameraDistortions/CameraCalibration.py
+++ /dev/null
@@ -1,123 +0,0 @@
-
-import numpy as np
-import cv2 as cv
-import glob
-import pickle
-
-
-
-################ FIND CHESSBOARD CORNERS - OBJECT POINTS AND IMAGE POINTS #############################
-
-chessboardSize = (9,6)
-# frameSize = (2592,1944)
-#frameSize = (4056,3040)
-frameSize = (1456,1088)
-
-
-
-# termination criteria
-criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
-
-
-# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
-objp = np.zeros((chessboardSize[0] * chessboardSize[1], 3), np.float32)
-objp[:,:2] = np.mgrid[0:chessboardSize[0],0:chessboardSize[1]].T.reshape(-1,2)
-
-size_of_chessboard_squares_mm = 20
-objp = objp * size_of_chessboard_squares_mm
-
-
-# Arrays to store object points and image points from all the images.
-objpoints = [] # 3d point in real world space
-imgpoints = [] # 2d points in image plane.
-
-
-# Change this as needed to point to the ~20 or so calibration pictures
-images = glob.glob('./images/cam1/*.png')
-
-for image in images:
-
- print("Processing Image: " + image)
- img = cv.imread(image)
- gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
-
- # Find the chess board corners
- ret, corners = cv.findChessboardCorners(gray, chessboardSize, None)
-
- # If found, add object points, image points (after refining them)
- if ret == True:
-
- objpoints.append(objp)
- corners2 = cv.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
- imgpoints.append(corners)
-
- # Draw and display the corners
- # cv.drawChessboardCorners(img, chessboardSize, corners2, ret)
- # cv.imshow('img', img)
- # cv.waitKey(1000)
-
-
-# cv.destroyAllWindows()
-
-
-
-
-############## CALIBRATION #######################################################
-
-ret, cameraMatrix, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, frameSize, None, None)
-
-# Save the camera calibration result for later use (we won't worry about rvecs / tvecs)
-# Most people won't use the .pkl files, just the .txt files
-pickle.dump((cameraMatrix, dist), open( "calibration.pkl", "wb" ))
-pickle.dump(cameraMatrix, open( "cameraMatrix.pkl", "wb" ))
-pickle.dump(dist, open( "dist.pkl", "wb" ))
-
-np.savetxt('cameraMatrix.txt', cameraMatrix, "%10f");
-np.savetxt('distortion.txt', dist, "%10f");
-
-############## UNDISTORTION #####################################################
-
-# NOTE - Before running, pick on of the checkerboard images as a test image on which
-# to try the undistortion. Put a copy of that file in the filename below
-img = cv.imread('./test_image_for_undistortion.png')
-h, w = img.shape[:2]
-newCameraMatrix, roi = cv.getOptimalNewCameraMatrix(cameraMatrix, dist, (w,h), 1, (w,h))
-
-
-
-# Undistort first with no remapping to see how that looks.
-dst = cv.undistort(img, cameraMatrix, dist, None, newCameraMatrix)
-
-# crop the image
-# x, y, w, h = roi
-# dst = dst[y:y+h, x:x+w]
-cv.imwrite('caliResult1.png', dst)
-
-
-
-# Undistort with Remapping
-mapx, mapy = cv.initUndistortRectifyMap(cameraMatrix, dist, None, newCameraMatrix, (w,h), 5)
-dst = cv.remap(img, mapx, mapy, cv.INTER_LINEAR)
-
-# crop the image
-x, y, w, h = roi
-dst = dst[y:y+h, x:x+w]
-cv.imwrite('caliResult2.png', dst)
-
-# TBD - try this again now with commas to minimize the re-editing the user has to do.
-file1 = "cameraMatrix.txt"
-np.savetxt(file1,cameraMatrix,delimiter=',')
-file2 = "cameraDistortion.txt"
-np.savetxt(file2,dist,delimiter=',')
-
-
-
-# Determine reprojection Error
-mean_error = 0
-
-for i in range(len(objpoints)):
- imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], cameraMatrix, dist)
- error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2)
- mean_error += error
-
-print( "total error: {}".format(mean_error/len(objpoints)) )
diff --git a/Software/CalibrateCameraDistortions/CameraCalibration.pyproj b/Software/CalibrateCameraDistortions/CameraCalibration.pyproj
deleted file mode 100755
index 095c4310..00000000
--- a/Software/CalibrateCameraDistortions/CameraCalibration.pyproj
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
- Debug
- 2.0
- 8a143eac-2fbe-4bed-b0bf-8be63192d2f8
- .
- CameraCalibration.py
-
-
- .
- .
- CameraCalibration
- CameraCalibration
-
-
- true
- false
-
-
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Software/CalibrateCameraDistortions/CameraCalibration.sln b/Software/CalibrateCameraDistortions/CameraCalibration.sln
deleted file mode 100755
index 80ac7580..00000000
--- a/Software/CalibrateCameraDistortions/CameraCalibration.sln
+++ /dev/null
@@ -1,23 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.4.33403.182
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "CameraCalibration", "CameraCalibration.pyproj", "{8A143EAC-2FBE-4BED-B0BF-8BE63192D2F8}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8A143EAC-2FBE-4BED-B0BF-8BE63192D2F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8A143EAC-2FBE-4BED-B0BF-8BE63192D2F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {9FEA2091-3020-46B3-BD8A-980C5440A1E2}
- EndGlobalSection
-EndGlobal
diff --git a/Software/CalibrateCameraDistortions/Thumbs.db b/Software/CalibrateCameraDistortions/Thumbs.db
deleted file mode 100755
index 3e4b64a3..00000000
Binary files a/Software/CalibrateCameraDistortions/Thumbs.db and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/caliResult1.png b/Software/CalibrateCameraDistortions/caliResult1.png
deleted file mode 100755
index be092a17..00000000
Binary files a/Software/CalibrateCameraDistortions/caliResult1.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/caliResult2.png b/Software/CalibrateCameraDistortions/caliResult2.png
deleted file mode 100755
index 47b03976..00000000
Binary files a/Software/CalibrateCameraDistortions/caliResult2.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/calibration.pkl b/Software/CalibrateCameraDistortions/calibration.pkl
deleted file mode 100755
index 7447940c..00000000
Binary files a/Software/CalibrateCameraDistortions/calibration.pkl and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/cameraDistortion.txt b/Software/CalibrateCameraDistortions/cameraDistortion.txt
deleted file mode 100755
index 3b540923..00000000
--- a/Software/CalibrateCameraDistortions/cameraDistortion.txt
+++ /dev/null
@@ -1 +0,0 @@
--5.469873041306134720e-01,4.323292678398480415e-01,-6.606921423690257332e-03,8.144843384932815358e-03,-3.443895940391311083e-01
diff --git a/Software/CalibrateCameraDistortions/cameraMatrix.pkl b/Software/CalibrateCameraDistortions/cameraMatrix.pkl
deleted file mode 100755
index e66e2ba8..00000000
Binary files a/Software/CalibrateCameraDistortions/cameraMatrix.pkl and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/cameraMatrix.txt b/Software/CalibrateCameraDistortions/cameraMatrix.txt
deleted file mode 100755
index 3097bcfa..00000000
--- a/Software/CalibrateCameraDistortions/cameraMatrix.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-1.825268110451985876e+03,0.000000000000000000e+00,6.560920394665909043e+02
-0.000000000000000000e+00,1.827901989005196810e+03,5.319678162262430305e+02
-0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00
diff --git a/Software/CalibrateCameraDistortions/checkerboard.png b/Software/CalibrateCameraDistortions/checkerboard.png
deleted file mode 100755
index 1f9112c3..00000000
Binary files a/Software/CalibrateCameraDistortions/checkerboard.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/checkerboard_test_image_for_undistortion.png b/Software/CalibrateCameraDistortions/checkerboard_test_image_for_undistortion.png
deleted file mode 100755
index 6dce2a5a..00000000
Binary files a/Software/CalibrateCameraDistortions/checkerboard_test_image_for_undistortion.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/dist.pkl b/Software/CalibrateCameraDistortions/dist.pkl
deleted file mode 100755
index 1bf7f47c..00000000
Binary files a/Software/CalibrateCameraDistortions/dist.pkl and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/distortion.txt b/Software/CalibrateCameraDistortions/distortion.txt
deleted file mode 100755
index 4fec98dd..00000000
--- a/Software/CalibrateCameraDistortions/distortion.txt
+++ /dev/null
@@ -1 +0,0 @@
- -0.546987 0.432329 -0.006607 0.008145 -0.344390
diff --git a/Software/CalibrateCameraDistortions/generate_charuco_board.py b/Software/CalibrateCameraDistortions/generate_charuco_board.py
deleted file mode 100755
index b2b5ddf4..00000000
--- a/Software/CalibrateCameraDistortions/generate_charuco_board.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python3
-"""Generate a printable ChArUco calibration board compatible with OpenCV 4.6+."""
-
-import cv2
-import numpy as np
-
-
-DPI = 300
-PX_PER_MM = DPI / 25.4
-
-A4_WIDTH_MM = 210
-A4_HEIGHT_MM = 297
-A4_WIDTH_PX = round(A4_WIDTH_MM * PX_PER_MM)
-A4_HEIGHT_PX = round(A4_HEIGHT_MM * PX_PER_MM)
-
-
-def get_opencv_version():
- version = cv2.__version__
- major, minor, patch = version.split('.')[:3]
- return (int(major), int(minor), int(patch.split('-')[0]))
-
-
-def is_new_api():
- return get_opencv_version() >= (4, 7, 0)
-
-
-def generate_charuco_board(
- squares_x=8,
- squares_y=11,
- square_length=0.023,
- marker_length=0.017,
- output_path="charuco_board_8x11.png",
- dict_type=cv2.aruco.DICT_4X4_50
-):
- print(f"OpenCV version: {cv2.__version__}")
- print(f"Using {'NEW' if is_new_api() else 'OLD'} API")
-
- if is_new_api():
- aruco_dict = cv2.aruco.getPredefinedDictionary(dict_type)
- else:
- aruco_dict = cv2.aruco.Dictionary_get(dict_type)
-
- if is_new_api():
- board = cv2.aruco.CharucoBoard(
- (squares_x, squares_y),
- square_length,
- marker_length,
- aruco_dict
- )
- else:
- board = cv2.aruco.CharucoBoard_create(
- squares_x, squares_y,
- square_length, marker_length,
- aruco_dict
- )
-
- square_mm = square_length * 1000
- square_px = round(square_mm * PX_PER_MM)
- board_width_px = squares_x * square_px
- board_height_px = squares_y * square_px
-
- actual_square_mm = square_px / PX_PER_MM
- board_width_mm = squares_x * actual_square_mm
- board_height_mm = squares_y * actual_square_mm
-
- if board_width_px > A4_WIDTH_PX or board_height_px > A4_HEIGHT_PX:
- raise ValueError(
- f"Board ({board_width_mm:.1f} x {board_height_mm:.1f} mm) "
- f"exceeds A4 ({A4_WIDTH_MM} x {A4_HEIGHT_MM} mm). "
- f"Reduce square_length or grid dimensions.")
-
- board_img = board.generateImage((board_width_px, board_height_px), marginSize=0)
-
- canvas = np.ones((A4_HEIGHT_PX, A4_WIDTH_PX), dtype=np.uint8) * 255
- x_off = (A4_WIDTH_PX - board_width_px) // 2
- y_off = (A4_HEIGHT_PX - board_height_px) // 2
- canvas[y_off:y_off + board_height_px, x_off:x_off + board_width_px] = board_img
-
- cv2.imwrite(output_path, canvas)
-
- print(f"\nChArUco board generated successfully!")
- print(f"Saved to: {output_path}")
- print(f"\nBoard Specifications:")
- print(f" Grid: {squares_x} x {squares_y} squares")
- print(f" Square size: {actual_square_mm:.2f} mm ({square_px} px at {DPI} DPI)")
- print(f" Marker size: {marker_length*1000:.1f} mm")
- print(f" Board size: {board_width_mm:.1f} mm x {board_height_mm:.1f} mm")
- print(f" Canvas: {A4_WIDTH_PX} x {A4_HEIGHT_PX} px (A4 @ {DPI} DPI)")
- print(f" Board offset: ({x_off}, {y_off}) px from top-left")
- print(f" Dictionary: DICT_4X4_50")
- print(f"\nPrinting Instructions:")
- print(f" 1. Print on A4 paper (210 x 297 mm)")
- print(f" 2. Use 'Actual Size' or '100%' scale (NO fit-to-page)")
- print(f" 3. Use high-quality printer settings")
- print(f" 4. Mount on flat, rigid surface (glass or aluminum preferred)")
- print(f" 5. VERIFY with a ruler: each square must be {actual_square_mm:.1f} mm")
-
- return board
-
-
-if __name__ == "__main__":
- board = generate_charuco_board(
- squares_x=8,
- squares_y=11,
- square_length=0.023,
- marker_length=0.017,
- output_path="charuco_board_8x11.png"
- )
diff --git a/Software/CalibrateCameraDistortions/get_tuning_file.sh b/Software/CalibrateCameraDistortions/get_tuning_file.sh
deleted file mode 100755
index 848fcfbf..00000000
--- a/Software/CalibrateCameraDistortions/get_tuning_file.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Determine what the correct img296 tuning file should be on
-# this machine. Only returns the _noir version.
-#
-
-model=$(tr -d '\0' < /sys/firmware/devicetree/base/model)
-
-if [[ "$model" == *"Raspberry Pi 4"* ]]; then
- echo "/usr/share/libcamera/ipa/rpi/vc4/imx296.json"
-elif [[ "$model" == *"Raspberry Pi 5"* ]]; then
- echo "/usr/share/libcamera/ipa/rpi/pisp/imx296.json"
-else
- echo "This is not a Raspberry Pi 4 or 5, model is: $model"
- exit;
-fi
-
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/Thumbs.db b/Software/CalibrateCameraDistortions/images/ProblemPix/Thumbs.db
deleted file mode 100755
index bd2d15be..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/Thumbs.db and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_1.png b/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_1.png
deleted file mode 100755
index 6dce2a5a..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_1.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_2.png b/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_2.png
deleted file mode 100755
index 01569392..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_2.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_3.png b/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_3.png
deleted file mode 100755
index 28ec627c..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_3.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_4.png b/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_4.png
deleted file mode 100755
index cf6d8780..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_4.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_5.png b/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_5.png
deleted file mode 100755
index fb693f42..00000000
Binary files a/Software/CalibrateCameraDistortions/images/ProblemPix/gs_calibation_5.png and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/Thumbs.db b/Software/CalibrateCameraDistortions/images/Thumbs.db
deleted file mode 100755
index 264de666..00000000
Binary files a/Software/CalibrateCameraDistortions/images/Thumbs.db and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/cam1/Thumbs.db b/Software/CalibrateCameraDistortions/images/cam1/Thumbs.db
deleted file mode 100755
index 7f9a50b4..00000000
Binary files a/Software/CalibrateCameraDistortions/images/cam1/Thumbs.db and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/images/cam2/Thumbs.db b/Software/CalibrateCameraDistortions/images/cam2/Thumbs.db
deleted file mode 100755
index bf0ce15e..00000000
Binary files a/Software/CalibrateCameraDistortions/images/cam2/Thumbs.db and /dev/null differ
diff --git a/Software/CalibrateCameraDistortions/take_calibration_shots.sh b/Software/CalibrateCameraDistortions/take_calibration_shots.sh
deleted file mode 100755
index 8d64f9e2..00000000
--- a/Software/CalibrateCameraDistortions/take_calibration_shots.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-#
-# Takes numPics pictures, each about 1 second apart
-# Before running, make sure the system is setup to NOT require
-# external triggering (particularly for camera 2).
-# If running in single-pi mode, the /boot/firmware/config.txt
-# file should have the following lines commented out:
-# dtoverlay=imx296,cam0
-# dtoverlay=imx296,sync-sink
-#
-# In addition, if using camera 2, the IR filter must be removed because
-# there will be no strobing.
-#
-
-cam_tuning_file=$(./get_tuning_file.sh)
-
-if [[ $# -lt 3 ]]; then echo Format: "$0" baseFName numPics camera_number\(0 or 1\); exit; fi
- echo "====================== WILL START IN 5 SECONDS ======================="
-sleep 5
-for((m=1; m<=${2}; ++m))
-do
- echo "====================== GET READY FOR ANOTHER PICTURE - No. $m ======================="
- sleep 2
- rpicam-still --camera ${3} --timeout 1000 --gain 1.3 --nopreview --verbose 0 --tuning-file=$cam_tuning_file --shutter 11000 --width 1456 --height 1088 --denoise cdn_off -o ${1}${m}.png
-done
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/CMakeLists.txt b/Software/LMSourceCode/ImageProcessing/Camera/CMakeLists.txt
deleted file mode 100644
index 24de4682..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-# Camera Bounded Context
-project(camera_context)
-
-# Set C++ standard
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# Header-only library for camera abstractions
-add_library(camera_abstractions INTERFACE)
-
-# Include directories for the bounded context
-target_include_directories(camera_abstractions INTERFACE
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-# Platform-specific compile definitions
-if(UNIX)
- target_compile_definitions(camera_abstractions INTERFACE CAMERA_UNIX_PLATFORM)
-elseif(WIN32)
- target_compile_definitions(camera_abstractions INTERFACE CAMERA_WINDOWS_PLATFORM)
-endif()
-
-# Enable testing
-option(BUILD_CAMERA_TESTS "Build Camera bounded context unit tests" ON)
-if(BUILD_CAMERA_TESTS)
- add_subdirectory(tests)
-endif()
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/MIGRATION_GUIDE.md b/Software/LMSourceCode/ImageProcessing/Camera/MIGRATION_GUIDE.md
deleted file mode 100644
index 506ba8cf..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/MIGRATION_GUIDE.md
+++ /dev/null
@@ -1,516 +0,0 @@
-# Camera Bounded Context - Migration Guide
-
-## Overview
-Migrate from monolithic `GolfSimCamera` to a clean Camera bounded context architecture.
-
-### Current Status
-✅ **Foundation exists**: Domain objects, infrastructure abstractions, tests, and build system are ready
-🔄 **Next step**: Namespace alignment and legacy integration
-
-### Key Decision
-**Use `golf_sim::camera` namespace** - aligns with existing codebase patterns rather than creating inconsistency.
-
-## Legacy Codebase Issues
-
-### Naming Inconsistencies
-The legacy code mixes multiple naming conventions, **with patterns related to access levels**:
-
-**Public vs Private Patterns Discovered:**
-- **Public Constants**: Consistently use `kConstantCase` (good pattern)
-- **Public Methods**: Mixed `camelCase` (`getNextFrame()`) and `PascalCase` (`GetCalibratedBall()`)
-- **Private Methods**: Mostly `camelCase` (`getExpectedBallRadiusPixels()`, `getBallDistance()`)
-- **Variables**: `camera_number_` (snake_case_) and `exposureTime` (camelCase) mixed together
-- **Namespaces**: Uses `golf_sim::camera::domain` aligned with existing `golf_sim` pattern
-
-**Root Cause**: The inconsistency appears to follow **intended conventions** where:
-- Private methods tend toward `camelCase`
-- Public methods mix both conventions inconsistently
-- Constants are consistently `kConstantCase`
-
-### Strategic Decision: Use `golf_sim::camera`
-- **Why**: `golf_sim` represents the domain function, not the brand
-- **Benefit**: No massive refactoring needed across codebase
-- **Consistency**: 99% of existing code already uses `golf_sim` namespace
-
-## Migration Strategy
-
-### Phase 0: Foundation Assessment (COMPLETED ✅)
-- ✅ **Complete**: Domain value objects exist (`Size`, `Transform`, `PixelFormat`, `ColorSpace`)
-- ✅ **Complete**: Infrastructure abstraction layer established
-- ✅ **Complete**: Test framework with Boost Test configured
-- ✅ **Complete**: CMake build system ready
-- ✅ **Complete**: Namespace alignment from `libcamera_domain` to `golf_sim::camera::domain`
-- 🔄 **Next**: Integration with legacy `GolfSimCamera` class
-
-### Phase 1: Namespace Alignment and Integration Preparation (COMPLETED ✅)
-
-#### Step 1: Update Existing Domain Namespace ✅
-```cpp
-// COMPLETED (in domain/camera_domain.hpp)
-namespace golf_sim::camera::domain {
- struct Size { /*...*/ };
- struct Transform { /*...*/ };
- // ...
-}
-
-// VALIDATION: All tests pass (25 test cases)
-namespace golf_sim::camera::domain {
- struct Size { /*...*/ };
- struct Transform { /*...*/ };
- // ...
-}
-```
-
-#### Step 2: Extend Domain with Business Logic
-Add camera entities and use cases to existing domain:
-```cpp
-namespace golf_sim::camera::domain {
- // Existing value objects...
- struct Size { /*...*/ };
-
- // NEW: Business entities
- class CameraEntity {
- // Camera state and behavior
- };
-
- // NEW: Domain services
- class CameraCalibrationService {
- // Calibration algorithms
- };
-}
-
-namespace golf_sim::camera::application {
- // NEW: Use cases and commands
- class CaptureImageUseCase { /*...*/ };
- class CalibrateCommand { /*...*/ };
-}
-```
-
-#### Step 3: Create Legacy Integration Layer
-```cpp
-namespace golf_sim::camera::integration {
- class LegacyCameraAdapter {
- // Bridge to existing GolfSimCamera
- };
-}
-```
-
-### Phase 2: Incremental Migration (RECOMMENDED NEXT STEPS)
-
-#### Step 1: Update IPC Integration
-Replace the camera usage in `gs_ipc_system.cpp`:
-
-```cpp
-// OLD (in gs_ipc_system.cpp)
-#include "gs_camera.h"
-GolfSimCamera* camera = GetCameraInstance();
-int result = camera->TakeStillPicture();
-
-// NEW
-#include "ImageProcessing/Camera/integration/CameraContext.h"
-auto cameraContext = golf_sim::camera::integration::CameraContext::Create();
-auto adapter = std::make_unique(cameraContext);
-int result = adapter->TakeStillPicture();
-```
-
-#### Step 2: Update FSM Event Handling
-Replace camera calls in `gs_fsm.cpp`:
-
-```cpp
-// OLD
-void ProcessCameraEvent(const CameraEvent& event) {
- auto camera = GetGolfSimCamera();
- camera->TakeStillPicture();
-}
-
-// NEW
-void ProcessCameraEvent(const CameraEvent& event) {
- // Use command pattern
- using namespace golf_sim::camera::application;
- commands::CaptureImageCommand command(
- event.exposureTime,
- event.gain,
- event.resolution
- );
- cameraContext_->ExecuteCommand(command);
-}
-```
-
-#### Step 3: Replace Direct Hardware Calls
-Update any direct hardware access:
-
-```cpp
-// OLD (scattered throughout codebase)
-#ifdef __unix__
- // Unix-specific camera code
-#else
- // Windows fallback
-#endif
-
-// NEW (all handled by factory)
-auto cameraContext = CameraContext::Create(); // Automatically selects platform
-```
-
-### Phase 3: Event-Driven Integration
-
-#### Subscribe to Camera Events
-```cpp
-// In main application setup
-auto eventBus = cameraContext->GetEventBus();
-
-// Subscribe to image capture events
-eventBus->Subscribe(
- [](const auto& event) {
- // Process captured image
- const auto& result = event.GetResult();
- if (result.IsSuccess()) {
- // Send to ball tracking system
- ProcessBallImage(result.GetImageData());
- }
- }
-);
-
-// Subscribe to error events
-eventBus->Subscribe(
- [](const auto& event) {
- // Log error and notify monitoring system
- LogError("Camera error: " + event.GetError());
- NotifyMonitoringSystem(event.GetError());
- }
-);
-```
-
-### Phase 4: Remove Legacy Code
-
-#### Files to Remove After Migration:
-1. Remove conditional compilation from business logic
-2. Clean up `gs_camera.cpp/.h` (keep only what's needed for other bounded contexts)
-3. Remove platform-specific `#ifdef` blocks
-4. Consolidate hardware interfaces
-
-#### Dependencies to Update:
-1. Update CMakeLists.txt to include new Camera module
-2. Update include paths
-3. Remove deprecated header includes
-
-## Integration Examples
-
-### Example 1: Basic Camera Usage
-```cpp
-#include "ImageProcessing/Camera/integration/CameraContext.h"
-
-// Create camera context
-auto cameraContext = golf_sim::camera::integration::CameraContext::Create();
-
-// Configure settings
-golf_sim::camera::domain::CameraSettings settings;
-settings.exposureTime = 0.001; // 1ms
-settings.gain = 2.0;
-settings.resolution = {1920, 1080};
-cameraContext->UpdateSettings(settings);
-
-// Capture image
-golf_sim::camera::domain::CaptureSettings captureSettings{
- settings.exposureTime,
- settings.gain,
- settings.resolution,
- golf_sim::camera::domain::TriggerMode::SOFTWARE
-};
-
-auto result = cameraContext->TakeStillPicture(captureSettings);
-if (result.IsSuccess()) {
- // Process image data
- ProcessImageData(result.GetImageData());
-}
-```
-
-### Example 2: Event-Driven Processing
-```cpp
-// Set up event handling
-auto eventBus = cameraContext->GetEventBus();
-
-// Handle image capture completion
-eventBus->Subscribe(
- [&ballTracker](const auto& event) {
- const auto& result = event.GetResult();
- if (result.IsSuccess()) {
- // Forward to ball tracking bounded context
- ballTracker.ProcessImage(result.GetImageData());
- }
- }
-);
-
-// Handle camera errors
-eventBus->Subscribe(
- [&logger](const auto& event) {
- logger.LogError("Camera failure: " + event.GetError());
- // Trigger recovery procedures
- }
-);
-```
-
-### Example 3: Command Pattern Usage
-```cpp
-using namespace golf_sim::camera::application;
-
-// Create capture command
-commands::CaptureImageCommand captureCmd(
- 0.001, // exposure time
- 2.0, // gain
- {1920, 1080}, // resolution
- golf_sim::camera::domain::TriggerMode::EXTERNAL
-);
-
-// Execute command
-cameraContext->ExecuteCommand(captureCmd);
-
-// Create calibration command
-commands::CalibrateCommand calibrateCmd(
- commands::CalibrateCommand::CalibrationType::FULL
-);
-
-cameraContext->ExecuteCommand(calibrateCmd);
-```
-
-## Testing Strategy
-
-### Unit Tests
-- Test each bounded context component in isolation
-- Mock hardware interfaces for reliable testing
-- Test command/query handlers independently
-
-### Integration Tests
-- Test camera context with real hardware
-- Test event publishing/subscription
-- Test legacy adapter compatibility
-
-### Migration Tests
-- Run existing system alongside new system
-- Compare outputs to ensure functional equivalence
-- Performance benchmarking
-
-## Benefits After Migration
-
-### 1. Platform Independence
-- No more `#ifdef __unix__` in business logic
-- Clean separation of platform-specific code
-- Easier to add new platforms (ARM, different Linux distros, etc.)
-
-### 2. Testability
-- Mock hardware interfaces for unit testing
-- Test business logic without hardware dependencies
-- Faster test execution
-
-### 3. Maintainability
-- Single Responsibility Principle enforced
-- Clear separation of concerns
-- Easier to understand and modify
-
-### 4. Extensibility
-- Easy to add new camera features
-- Plugin architecture for different camera types
-- Event-driven architecture enables loose coupling
-
-### 5. Performance
-- Reduced conditional compilation overhead
-- Better compiler optimizations
-- More efficient resource usage
-
-## TODO LIST AND REFACTORING STRATEGY
-
-### Complexity Identified During Investigation
-
-#### 1. Namespace Architecture Issues
-**Problem**: Should we follow existing `golf_sim` namespace convention or modernize to brand-specific namespaces?
-
-**Revised Solution Strategy** (Domain-Focused Approach):
-- **Embrace `golf_sim::camera` namespace** for new bounded context (domain-aligned, not brand-aligned)
-- **Rationale**:
- - `golf_sim` represents the **system domain** (golf simulation) not the brand
- - Brand names can change (PiTrac today, could be different tomorrow)
- - Domain functions are more stable than product branding
- - Minimal disruption to existing codebase patterns
- - Follows established conventions throughout the codebase
-- **Implementation**: All new Camera bounded context code uses `golf_sim::camera` namespace
-- **Legacy Integration**: No namespace translation needed - seamless integration
-
-#### 2. Naming Convention Standards for New Code
-**Decision**: Establish consistent naming standards to address legacy inconsistencies
-
-**Adopted Standards** (based on analysis of legacy codebase patterns):
-```cpp
-// Classes: PascalCase
-class CameraEntity { };
-class CaptureCommand { };
-class HardwareCameraInterface { };
-
-// Methods: PascalCase (following existing Format(), Configure() pattern)
-class CameraService {
-public:
- void CaptureImage(); // NOT captureImage()
- std::string Format() const; // Consistent with legacy
- void Configure(); // Consistent with legacy
-};
-
-// Member Variables: snake_case_ (following existing member pattern)
-class Camera {
-private:
- double exposure_time_; // Consistent with existing
- int camera_number_; // Consistent with existing
- std::string device_path_; // Consistent with existing
-};
-
-// Constants: kConstantCase (following existing kCamera1, kTest pattern)
-namespace Constants {
- static constexpr double kDefaultExposureTime = 0.001;
- static constexpr int kMaxRetryAttempts = 3;
- static constexpr std::string_view kDefaultDevice = "/dev/video0";
-}
-
-// Enums: PascalCase with scoped values
-enum class TriggerMode {
- Software, // NOT SOFTWARE or kSoftware
- Hardware,
- External
-};
-
-// Namespaces: Domain-aligned hierarchical (following existing patterns)
-namespace golf_sim::camera::domain { }
-namespace golf_sim::camera::application { }
-namespace golf_sim::camera::infrastructure { }
-```
-
-**Integration with Legacy Code**:
-```cpp
-// Seamless integration - no namespace translation needed
-namespace golf_sim::camera {
- class CameraService {
- // New code uses consistent naming within established namespace
- void CaptureImage() {
- // Direct integration with legacy code in same namespace
- legacy_camera_->takeStillPicture(); // camelCase legacy method
- }
-
- private:
- golf_sim::GolfSimCamera* legacy_camera_; // Same namespace
- };
-}
-```
-
-#### 3. Interface Design Philosophy
-**Decision Needed**: How to handle domain vs application interfaces
-- Option A: Single interface serving both domain and application needs
-- Option B: Separate domain and application interfaces with adapters
-- **Recommendation**: Option A for simplicity in this context
-
-#### 4. Error Handling Strategy
-**Decision Needed**: How to propagate errors through layers
-- Option A: Exceptions throughout
-- Option B: Result pattern
-- Option C: Error codes and error callbacks
-- **Recommendation**: Option A for consistency with existing code
-
-#### 5. Threading Model
-**Critical Performance Requirement**: Spin rate detection is performance-critical
-- **Current Performance**: ~2 seconds, optimized for multi-core processing
-- **High Impact**: Improving this performance would be very valuable
-- **Risk**: Degrading this performance would be undesirable
-
-**Strategic Threading Approach**:
-- **Preserve**: Existing multi-core spin analysis (don't break what works)
-- **Enhance**: Add async camera capture to improve overall system responsiveness
-- **Avoid**: Any threading changes that could slow down the core spin detection
-
-**Threading Strategy**:
-- **Option A**: Synchronous operations with multi-threaded image processing
-- **Option B**: Async capture with parallel spin analysis pipelines
-- **Option C**: Full async/await with thread pools for compute-heavy operations
-- **Recommendation**: Option B - Preserve multi-core spin processing, add async capture
-
-### IMMEDIATE NEXT STEPS
-
-#### Critical: Hardware-Independent Testing Strategy
-**Open Source Success Requirement**: Automated testing without external hardware dependencies is **critical** for:
-- **PR Validation**: Confidence that pull requests don't break existing functionality
-- **Release Quality**: Assurance that code can be safely released to end users
-- **Contributor Onboarding**: New developers can run tests without specialized hardware
-- **CI/CD Pipeline**: Automated builds and tests in cloud environments
-
-**Testing Architecture Requirements**:
-```cpp
-// Hardware abstraction enables testing without cameras
-namespace golf_sim::camera::testing {
- class MockCameraHardware : public ICameraHardware {
- // Simulate camera behavior with deterministic responses
- };
-
- class ImageSimulator {
- // Generate synthetic golf ball images for testing
- };
-}
-```
-
-#### Implementation Priorities
-
-1. **Start with Hardware Abstraction**
- - Create `ICameraHardware` interface first
- - Implement mock camera for testing
- - Generate synthetic test images
- - **Validate**: All tests pass without real hardware
-
-2. **Minimal Bounded Context Extension**
- - Implement ONLY value objects first
- - Test compilation and unit tests
- - Add ONE interface with stub implementation
- - **Validate**: Clean build + passing tests
-
-3. **Incremental Growth with Test Coverage**
- - Add one method at a time
- - Write tests BEFORE implementation
- - Don't move to next layer until current layer has 100% test coverage
- - **Do not change any code not covered by an automated test unless it is changed using a provable refactoring**
- - **Validate**: Each increment maintains test suite health
-
-**Provable Refactoring Resources**:
-- **Arlo Belshee's Provable Refactorings**:
-https://github.com/digdeeproots/provable-refactorings
-
-- **Arlo Belshee's Risk Aware Commit Notation**:
-[Arlo's Commit Notation](https://github.com/RefactoringCombos/ArlosCommitNotation) - A notation for small commits messages that show the risk involved in each step
-
-- **Martin Fowler's Refactoring**: [Catalog of Refactorings](https://refactoring.com/catalog/) - Authoritative reference for safe transformations
-
-- **Michael Feathers' "Working Effectively with Legacy Code"** - [Essential techniques for adding tests to untested code](https://archive.org/details/working-effectively-with-legacy-code)
-
-#### Success Criteria for Each Phase
-- **Phase 1**: All files compile without errors
-- **Phase 2**: All unit tests pass
-- **Phase 3**: Integration tests pass
-- **Phase 4**: One legacy usage successfully replaced
-
-### RISK MITIGATION
-
-#### Build Failures
-- Make many small and reversible changes
-- Test on a clean environment regularly
-- Aim to improve the [pipeline](https://github.com/pitraclm/pitrac/blob/a3b3f1baad0ded3066b0c9585ce4879ef6314d18/.github/workflows/camera-tests.yml) test coverage
-- Maintain a working baseline with frequent small pull requests and short lived branches
-
-#### Integration Issues
-- Create comprehensive test coverage before migration
-- Use feature flags to enable/disable new implementation
-- Maintain legacy code until migration complete
-
-#### Performance Issues
-- Benchmark existing performance before migration
-- Monitor performance after each migration step
-- Have a rollback plan for any performance regressions
-
----
-
-
-## **Next Steps:**
-1. Execute Phase 1: Namespace alignment and business logic extension
-2. Create integration adapters for legacy `GolfSimCamera`
-3. Begin incremental migration of specific usage points
-4. Leverage existing test framework for validation
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/README.md b/Software/LMSourceCode/ImageProcessing/Camera/README.md
deleted file mode 100644
index 29d0f9ea..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/README.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Camera Bounded Context Tests - Quick Start
-
-## Prerequisites
-
-- CMake (3.6 or later)
-- C++ compiler (Visual Studio, MinGW, or Clang)
-- Boost libraries with unit_test_framework
-
-## Quick Start
-
-### Option 1: Simple PowerShell Script (Recommended)
-```powershell
-# From Camera directory
-.\build_tests.ps1
-```
-
-### Option 2: Manual CMake
-```powershell
-# Create and enter build directory
-mkdir build
-cd build
-
-# Configure
-cmake ..
-
-# Build
-cmake --build .
-
-# Run tests
-.\Debug\camera_tests.exe
-# or
-.\camera_tests.exe
-```
-
-### Option 3: Using CTest
-```powershell
-cd build\tests
-ctest -C Debug -V
-```
-
-## What Gets Tested
-
-- **Domain Types**: Size, Transform, PixelFormat, ColorSpace
-- **Platform Selection**: Automatic platform detection
-- **Cross-Platform**: Works on both Windows and Unix
-- **Performance**: Basic timing benchmarks
-- **Parametric**: Tests with comprehensive data sets
-
-## Test Output Example
-```
-Running 15 test cases...
-Setting up domain type test fixture
-*** No errors detected
-Tearing down domain type test fixture
-
-===============================================================================
-Test suite "CameraBoundedContextTests" passed with:
-15 test cases out of 15 passed
-```
-
-## Troubleshooting
-
-### Boost Not Found
-If CMake can't find Boost:
-```powershell
-# Option 1: Set environment variable
-$env:BOOST_ROOT = "C:\path\to\boost"
-.\build_tests.ps1
-
-# Option 2: Specify during configure
-mkdir build
-cd build
-cmake .. -DBOOST_DIR=C:\path\to\boost
-cmake --build .
-```
-
-### Different Compiler
-```powershell
-# For Visual Studio
-cmake .. -G "Visual Studio 16 2019"
-
-# For MinGW
-cmake .. -G "MinGW Makefiles"
-```
-
-The test framework is completely self-contained and doesn't require the full PiTrac build system!
-
-## Continuous Integration
-
-The Camera tests run automatically on GitHub Actions:
-- **Triggers**: Push to any branch, Pull Requests
-- **Platform**: Windows (Visual Studio 2019)
-- **Path Filter**: Only runs when Camera code changes
-- **Test Suites**: All 25 test cases across 4 test suites
-
-View test results in the [Actions tab](../../actions) of the repository.
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/build_tests.ps1 b/Software/LMSourceCode/ImageProcessing/Camera/build_tests.ps1
deleted file mode 100644
index de503d87..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/build_tests.ps1
+++ /dev/null
@@ -1,67 +0,0 @@
-# Simple Camera Test Build Script for Windows
-# Builds and runs Camera bounded context tests using CMake and Boost
-
-Write-Host "Camera Bounded Context Tests" -ForegroundColor Green
-Write-Host "============================" -ForegroundColor Green
-
-$CameraDir = Get-Location
-$BuildDir = "$CameraDir\build"
-
-# Check if we're in the Camera directory
-if (!(Test-Path "domain\camera_domain.hpp")) {
- Write-Host "Error: Run this script from the Camera directory" -ForegroundColor Red
- exit 1
-}
-
-# Create and clean build directory
-if (Test-Path $BuildDir) {
- Remove-Item -Recurse -Force $BuildDir
-}
-New-Item -ItemType Directory -Path $BuildDir | Out-Null
-
-# Build and test
-Push-Location $BuildDir
-
-Write-Host "Configuring..." -ForegroundColor Cyan
-& cmake .. | Out-Null
-if ($LASTEXITCODE -ne 0) {
- Write-Host "CMake failed. Try: cmake .. -DBOOST_DIR=C:\path\to\boost" -ForegroundColor Red
- Pop-Location
- exit 1
-}
-
-Write-Host "Building..." -ForegroundColor Cyan
-& cmake --build . | Out-Null
-if ($LASTEXITCODE -ne 0) {
- Write-Host "Build failed" -ForegroundColor Red
- Pop-Location
- exit 1
-}
-
-Write-Host "Running tests..." -ForegroundColor Cyan
-
-# Find and run the test executable
-$testExe = @(
- ".\tests\Debug\camera_tests.exe",
- ".\tests\camera_tests.exe",
- ".\Debug\camera_tests.exe",
- ".\camera_tests.exe"
-) | Where-Object { Test-Path $_ } | Select-Object -First 1
-
-if (!$testExe) {
- Write-Host "Test executable not found!" -ForegroundColor Red
- Pop-Location
- exit 1
-}
-
-& $testExe
-$testResult = $LASTEXITCODE
-Pop-Location
-
-if ($testResult -eq 0) {
- Write-Host "✓ All tests passed!" -ForegroundColor Green
-} else {
- Write-Host "✗ Tests failed" -ForegroundColor Red
-}
-
-exit $testResult
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/camera_platform.hpp b/Software/LMSourceCode/ImageProcessing/Camera/camera_platform.hpp
deleted file mode 100644
index 67b46666..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/camera_platform.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Camera Platform Selector
- *
- * This header automatically includes the appropriate camera implementation
- * based on the target platform. Use this single include throughout the
- * codebase instead of platform-specific headers.
- * * Example usage:
- * #include "Camera/camera_platform.hpp"
- * // Now you can use golf_sim::camera::domain types and platform-specific implementations
- */
-
-#pragma once
-
-// Always include the domain interface first
-#include "domain/camera_domain.hpp"
-
-// Include platform-specific implementation
-#ifdef __unix__
- #include "infrastructure/unix/libcamera_unix_impl.hpp"
-#elif defined(_WIN32) || defined(WIN32)
- // Windows implementation will be added here
- // #include "infrastructure/windows/libcamera_windows_impl.hpp"
-#else
- #error "Unsupported platform for camera operations"
-#endif
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/domain/camera_domain.hpp b/Software/LMSourceCode/ImageProcessing/Camera/domain/camera_domain.hpp
deleted file mode 100644
index 3102a5e2..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/domain/camera_domain.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Domain interface for Camera bounded context
- *
- * This file defines the common interface for camera operations,
- * independent of platform implementation.
- *
- * Step 1 of incremental refactoring: Define domain interface only.
- * No existing files are modified in this step.
- */
-
-#pragma once
-
-namespace golf_sim::camera::domain {
-
- // Domain types that abstract platform-specific implementations
- // These provide a clean interface for the application layer
-
- struct Size {
- unsigned int width, height;
- Size(unsigned int w = 0, unsigned int h = 0) : width(w), height(h) {}
- };
-
- struct Transform {
- int value = 0;
- Transform(int v = 0) : value(v) {}
- };
-
- struct PixelFormat {
- unsigned int fourcc = 0;
- PixelFormat(unsigned int f = 0) : fourcc(f) {}
- };
-
- struct ColorSpace {
- int value = 0;
- ColorSpace(int v = 0) : value(v) {}
- };
-
-} // namespace golf_sim::camera::domain
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/infrastructure/unix/libcamera_unix_impl.hpp b/Software/LMSourceCode/ImageProcessing/Camera/infrastructure/unix/libcamera_unix_impl.hpp
deleted file mode 100644
index b527f7de..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/infrastructure/unix/libcamera_unix_impl.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Unix/Linux infrastructure implementation for camera operations
- *
- * This file provides the actual libcamera implementations for Unix/Linux platforms.
- * It bridges between our domain interface and the real libcamera library.
- *
- * Unix infrastructure layer.
- * This will allow Unix builds to continue using real libcamera while we prepare
- * for eventual migration to domain interface.
- */
-
-#pragma once
-
-#ifdef __unix__
-
-// Include actual libcamera headers for Unix/Linux
-#include
-#include
-#include
-#include
-#include
-#include
-
-// Include our domain interface
-#include "../../domain/camera_domain.hpp"
-
-namespace golf_sim::camera::infrastructure {
-
- // Unix implementation uses actual libcamera types directly
- // This namespace provides the bridge between domain and infrastructure
-
- // For now, we simply alias the real types
- // Later, we can add conversion functions if needed
- using CameraSize = libcamera::Size;
- using CameraTransform = libcamera::Transform;
- using CameraPixelFormat = libcamera::PixelFormat;
- using CameraColorSpace = libcamera::ColorSpace;
- using CameraControlList = libcamera::ControlList; using CameraRequest = libcamera::Request;
-
-} // namespace golf_sim::camera::infrastructure
-
-#endif // __unix__
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/CMakeLists.txt b/Software/LMSourceCode/ImageProcessing/Camera/tests/CMakeLists.txt
deleted file mode 100644
index 950edb73..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/CMakeLists.txt
+++ /dev/null
@@ -1,133 +0,0 @@
-# Camera Bounded Context - Unit Tests
-# Using Boost Test Framework with xUnit Arrange-Act-Assert pattern
-
-# Configure Boost detection
-set(Boost_USE_STATIC_LIBS OFF)
-set(Boost_USE_MULTITHREADED ON)
-set(Boost_USE_STATIC_RUNTIME OFF)
-
-# Debug information
-message(STATUS "Looking for Boost Test framework...")
-message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
-message(STATUS "Boost_ROOT: ${Boost_ROOT}")
-message(STATUS "BOOST_ROOT: $ENV{BOOST_ROOT}")
-
-# Try different Boost component names based on platform and version
-if(WIN32)
- # On Windows, try different naming conventions
- find_package(Boost QUIET COMPONENTS unit_test_framework)
- if(NOT Boost_unit_test_framework_FOUND)
- message(STATUS "unit_test_framework not found, trying 'test'")
- find_package(Boost QUIET COMPONENTS test)
- if(NOT Boost_test_FOUND)
- message(STATUS "test not found, trying 'test_exec_monitor'")
- find_package(Boost QUIET COMPONENTS test_exec_monitor)
- if(NOT Boost_test_exec_monitor_FOUND)
- message(STATUS "No test libraries found, falling back to header-only")
- # Try header-only approach as fallback
- find_package(Boost REQUIRED)
- set(BOOST_TEST_HEADER_ONLY TRUE)
- endif()
- endif()
- endif()
-else()
- # On Unix systems, standard naming should work
- find_package(Boost REQUIRED COMPONENTS unit_test_framework)
-endif()
-
-# Debug what we found
-message(STATUS "Boost_FOUND: ${Boost_FOUND}")
-message(STATUS "Boost_VERSION: ${Boost_VERSION}")
-message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
-message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
-message(STATUS "BOOST_TEST_HEADER_ONLY: ${BOOST_TEST_HEADER_ONLY}")
-
-# Create the test executable target
-add_executable(camera_tests
- test_main.cpp
- domain/test_camera_domain.cpp
- domain/test_advanced_domain.cpp
- infrastructure/test_platform_selection.cpp
-)
-
-# Configure linking based on what we found
-if(BOOST_TEST_HEADER_ONLY)
- # Header-only mode - no linking required
- target_compile_definitions(camera_tests
- PRIVATE
- BOOST_TEST_HEADER_ONLY=1
- )
- target_include_directories(camera_tests
- PRIVATE
- ${Boost_INCLUDE_DIRS}
- )
-else()
- # Linked library mode
- if(TARGET Boost::unit_test_framework)
- target_link_libraries(camera_tests PRIVATE Boost::unit_test_framework)
- target_compile_definitions(camera_tests PRIVATE BOOST_TEST_DYN_LINK)
- elseif(TARGET Boost::test)
- target_link_libraries(camera_tests PRIVATE Boost::test)
- target_compile_definitions(camera_tests PRIVATE BOOST_TEST_DYN_LINK)
- elseif(TARGET Boost::test_exec_monitor)
- target_link_libraries(camera_tests PRIVATE Boost::test_exec_monitor)
- target_compile_definitions(camera_tests PRIVATE BOOST_TEST_DYN_LINK)
- else()
- # Fallback to old-style variables
- target_link_libraries(camera_tests PRIVATE ${Boost_LIBRARIES})
- target_include_directories(camera_tests PRIVATE ${Boost_INCLUDE_DIRS})
- target_compile_definitions(camera_tests PRIVATE BOOST_TEST_DYN_LINK)
- endif()
-endif()
-
-# Include paths for testing
-target_include_directories(camera_tests
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/.. # Camera bounded context root
- ${CMAKE_CURRENT_SOURCE_DIR} # Test directory
-)
-
-# Enable testing for this directory
-enable_testing()
-
-# Register the test with CTest
-add_test(
- NAME camera_unit_tests
- COMMAND camera_tests
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-)
-
-# Set test properties for better output
-set_tests_properties(camera_unit_tests
- PROPERTIES
- TIMEOUT 30
- LABELS "unit;camera"
-)
-
-# Create test groups for selective running
-add_test(
- NAME camera_domain_tests
- COMMAND camera_tests --run_test=DomainTests
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-)
-
-add_test(
- NAME camera_infrastructure_tests
- COMMAND camera_tests --run_test=InfrastructureTests
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-)
-
-# Platform-specific conditional tests
-if(UNIX)
- add_test(
- NAME camera_unix_tests
- COMMAND camera_tests --run_test=UnixTests
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- )
-elseif(WIN32)
- add_test(
- NAME camera_windows_tests
- COMMAND camera_tests --run_test=WindowsTests
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- )
-endif()
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_advanced_domain.cpp b/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_advanced_domain.cpp
deleted file mode 100644
index 1efb5c08..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_advanced_domain.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Advanced Domain Tests
- *
- * Parametric tests for camera domain types using test utilities.
- */
-
-#include
-#include "test_utilities.hpp"
-
-BOOST_AUTO_TEST_SUITE(AdvancedDomainTests)
-
-BOOST_FIXTURE_TEST_CASE(size_parametric_construction_test, camera_test_utils::DomainTypeFixture) {
- // Arrange
- auto test_sizes = camera_test_utils::CommonTestData::getValidSizes();
-
- // Act & Assert
- camera_test_utils::runParametricTest(test_sizes, [this](const auto& size_pair) {
- // Arrange
- unsigned int width = size_pair.first;
- unsigned int height = size_pair.second;
-
- // Act
- golf_sim::camera::domain::Size size(width, height);
-
- // Assert
- assertSizeEquals(size, width, height);
- });
-}
-
-BOOST_FIXTURE_TEST_CASE(transform_parametric_construction_test, camera_test_utils::DomainTypeFixture) {
- // Arrange
- auto test_transforms = camera_test_utils::CommonTestData::getValidTransforms();
-
- // Act & Assert
- camera_test_utils::runParametricTest(test_transforms, [this](int transform_value) {
- // Arrange
- // (transform_value provided by parametric test)
-
- // Act
- golf_sim::camera::domain::Transform transform(transform_value);
-
- // Assert
- assertTransformEquals(transform, transform_value);
- });
-}
-
-BOOST_FIXTURE_TEST_CASE(pixel_format_parametric_construction_test, camera_test_utils::DomainTypeFixture) {
- // Arrange
- auto test_formats = camera_test_utils::CommonTestData::getValidPixelFormats();
-
- // Act & Assert
- camera_test_utils::runParametricTest(test_formats, [this](unsigned int fourcc_value) {
- // Arrange
- // (fourcc_value provided by parametric test)
-
- // Act
- golf_sim::camera::domain::PixelFormat format(fourcc_value);
-
- // Assert
- assertPixelFormatEquals(format, fourcc_value);
- });
-}
-
-BOOST_FIXTURE_TEST_CASE(color_space_parametric_construction_test, camera_test_utils::DomainTypeFixture) {
- // Arrange
- auto test_colorspaces = camera_test_utils::CommonTestData::getValidColorSpaces();
-
- // Act & Assert
- camera_test_utils::runParametricTest(test_colorspaces, [this](int colorspace_value) {
- // Arrange
- // (colorspace_value provided by parametric test)
-
- // Act
- golf_sim::camera::domain::ColorSpace colorspace(colorspace_value);
-
- // Assert
- assertColorSpaceEquals(colorspace, colorspace_value);
- });
-}
-
-BOOST_FIXTURE_TEST_CASE(domain_types_performance_test, camera_test_utils::PerformanceFixture) {
- // Arrange
- const size_t iteration_count = 100000;
- std::vector sizes;
- std::vector transforms;
- sizes.reserve(iteration_count);
- transforms.reserve(iteration_count);
-
- // Act
- for (size_t i = 0; i < iteration_count; ++i) {
- sizes.emplace_back(1920, 1080);
- transforms.emplace_back(90);
- }
-
- // Assert
- BOOST_CHECK_EQUAL(sizes.size(), iteration_count);
- BOOST_CHECK_EQUAL(transforms.size(), iteration_count);
-
- // Verify first and last elements
- BOOST_CHECK_EQUAL(sizes[0].width, 1920);
- BOOST_CHECK_EQUAL(sizes[iteration_count - 1].height, 1080);
- BOOST_CHECK_EQUAL(transforms[0].value, 90);
- BOOST_CHECK_EQUAL(transforms[iteration_count - 1].value, 90);
-}
-
-BOOST_AUTO_TEST_CASE(domain_types_memory_layout_test) {
- // Arrange
- // (Testing memory layout and size of domain types)
-
- // Act & Assert
- // Verify that domain types have expected memory characteristics
- BOOST_CHECK(sizeof(golf_sim::camera::domain::Size) >= sizeof(unsigned int) * 2);
- BOOST_CHECK(sizeof(golf_sim::camera::domain::Transform) >= sizeof(int));
- BOOST_CHECK(sizeof(golf_sim::camera::domain::PixelFormat) >= sizeof(unsigned int));
- BOOST_CHECK(sizeof(golf_sim::camera::domain::ColorSpace) >= sizeof(int));
-
- // Verify types are not excessively large (should be simple value types)
- BOOST_CHECK(sizeof(golf_sim::camera::domain::Size) <= 16); // Allow some padding
- BOOST_CHECK(sizeof(golf_sim::camera::domain::Transform) <= 8);
- BOOST_CHECK(sizeof(golf_sim::camera::domain::PixelFormat) <= 8);
- BOOST_CHECK(sizeof(golf_sim::camera::domain::ColorSpace) <= 8);
-}
-
-BOOST_AUTO_TEST_CASE(domain_types_assignment_test) {
- // Arrange
- golf_sim::camera::domain::Size size1(640, 480);
- golf_sim::camera::domain::Size size2(1920, 1080);
- golf_sim::camera::domain::Transform transform1(0);
- golf_sim::camera::domain::Transform transform2(90);
-
- // Act
- size1 = size2;
- transform1 = transform2;
-
- // Assert
- BOOST_CHECK_EQUAL(size1.width, size2.width);
- BOOST_CHECK_EQUAL(size1.height, size2.height);
- BOOST_CHECK_EQUAL(transform1.value, transform2.value);
-}
-
-BOOST_AUTO_TEST_CASE(domain_types_in_arrays_test) {
- // Arrange
- const size_t array_size = 5;
- golf_sim::camera::domain::Size sizes[array_size];
- golf_sim::camera::domain::Transform transforms[array_size];
-
- // Act
- for (size_t i = 0; i < array_size; ++i) {
- sizes[i] = golf_sim::camera::domain::Size(static_cast(i * 100),
- static_cast(i * 100));
- transforms[i] = golf_sim::camera::domain::Transform(static_cast(i * 90));
- }
-
- // Assert
- for (size_t i = 0; i < array_size; ++i) {
- BOOST_CHECK_EQUAL(sizes[i].width, i * 100);
- BOOST_CHECK_EQUAL(sizes[i].height, i * 100);
- BOOST_CHECK_EQUAL(transforms[i].value, static_cast(i * 90));
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_camera_domain.cpp b/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_camera_domain.cpp
deleted file mode 100644
index 8d40272a..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/domain/test_camera_domain.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Camera Domain Tests
- *
- * Unit tests for the camera domain interface.
- * Tests the domain types and their behavior without platform dependencies.
- */
-
-#include
-#include "domain/camera_domain.hpp"
-
-BOOST_AUTO_TEST_SUITE(DomainTests)
-
-BOOST_AUTO_TEST_CASE(size_default_construction) {
- // Arrange
- // (No setup needed for default construction)
-
- // Act
- golf_sim::camera::domain::Size size;
-
- // Assert
- BOOST_CHECK_EQUAL(size.width, 0);
- BOOST_CHECK_EQUAL(size.height, 0);
-}
-
-BOOST_AUTO_TEST_CASE(size_parameterized_construction) {
- // Arrange
- const unsigned int expected_width = 1920;
- const unsigned int expected_height = 1080;
-
- // Act
- golf_sim::camera::domain::Size size(expected_width, expected_height);
-
- // Assert
- BOOST_CHECK_EQUAL(size.width, expected_width);
- BOOST_CHECK_EQUAL(size.height, expected_height);
-}
-
-BOOST_AUTO_TEST_CASE(size_copy_construction) {
- // Arrange
- golf_sim::camera::domain::Size original(800, 600);
-
- // Act
- golf_sim::camera::domain::Size copy(original);
-
- // Assert
- BOOST_CHECK_EQUAL(copy.width, original.width);
- BOOST_CHECK_EQUAL(copy.height, original.height);
-}
-
-BOOST_AUTO_TEST_CASE(transform_default_construction) {
- // Arrange
- // (No setup needed for default construction)
-
- // Act
- golf_sim::camera::domain::Transform transform;
-
- // Assert
- BOOST_CHECK_EQUAL(transform.value, 0);
-}
-
-BOOST_AUTO_TEST_CASE(transform_parameterized_construction) {
- // Arrange
- const int expected_value = 90; // Typical rotation value
-
- // Act
- golf_sim::camera::domain::Transform transform(expected_value);
-
- // Assert
- BOOST_CHECK_EQUAL(transform.value, expected_value);
-}
-
-BOOST_AUTO_TEST_CASE(pixel_format_default_construction) {
- // Arrange
- // (No setup needed for default construction)
-
- // Act
- golf_sim::camera::domain::PixelFormat format;
-
- // Assert
- BOOST_CHECK_EQUAL(format.fourcc, 0);
-}
-
-BOOST_AUTO_TEST_CASE(pixel_format_parameterized_construction) {
- // Arrange
- const unsigned int expected_fourcc = 0x32315659; // YV12 format
-
- // Act
- golf_sim::camera::domain::PixelFormat format(expected_fourcc);
-
- // Assert
- BOOST_CHECK_EQUAL(format.fourcc, expected_fourcc);
-}
-
-BOOST_AUTO_TEST_CASE(color_space_default_construction) {
- // Arrange
- // (No setup needed for default construction)
-
- // Act
- golf_sim::camera::domain::ColorSpace colorSpace;
-
- // Assert
- BOOST_CHECK_EQUAL(colorSpace.value, 0);
-}
-
-BOOST_AUTO_TEST_CASE(color_space_parameterized_construction) {
- // Arrange
- const int expected_value = 1; // Typical color space identifier
-
- // Act
- golf_sim::camera::domain::ColorSpace colorSpace(expected_value);
-
- // Assert
- BOOST_CHECK_EQUAL(colorSpace.value, expected_value);
-}
-
-BOOST_AUTO_TEST_CASE(domain_types_are_value_types) {
- // Arrange
- golf_sim::camera::domain::Size size1(1920, 1080);
- golf_sim::camera::domain::Size size2(1920, 1080);
- golf_sim::camera::domain::Transform transform1(90);
- golf_sim::camera::domain::Transform transform2(90);
-
- // Act & Assert - Test that objects with same values behave as value types
- BOOST_CHECK_EQUAL(size1.width, size2.width);
- BOOST_CHECK_EQUAL(size1.height, size2.height);
- BOOST_CHECK_EQUAL(transform1.value, transform2.value);
-}
-
-BOOST_AUTO_TEST_CASE(size_supports_zero_dimensions) {
- // Arrange
- // (Testing edge case of zero dimensions)
-
- // Act
- golf_sim::camera::domain::Size zero_size(0, 0);
- golf_sim::camera::domain::Size zero_width(0, 480);
- golf_sim::camera::domain::Size zero_height(640, 0);
-
- // Assert
- BOOST_CHECK_EQUAL(zero_size.width, 0);
- BOOST_CHECK_EQUAL(zero_size.height, 0);
- BOOST_CHECK_EQUAL(zero_width.width, 0);
- BOOST_CHECK_EQUAL(zero_width.height, 480);
- BOOST_CHECK_EQUAL(zero_height.width, 640);
- BOOST_CHECK_EQUAL(zero_height.height, 0);
-}
-
-BOOST_AUTO_TEST_CASE(types_support_large_values) {
- // Arrange
- const unsigned int max_dimension = 4294967295U; // Close to UINT_MAX
- const int max_transform = 2147483647; // Close to INT_MAX
- const unsigned int max_fourcc = 4294967295U; // Close to UINT_MAX
-
- // Act
- golf_sim::camera::domain::Size large_size(max_dimension, max_dimension);
- golf_sim::camera::domain::Transform large_transform(max_transform);
- golf_sim::camera::domain::PixelFormat large_format(max_fourcc);
- golf_sim::camera::domain::ColorSpace large_colorspace(max_transform);
-
- // Assert
- BOOST_CHECK_EQUAL(large_size.width, max_dimension);
- BOOST_CHECK_EQUAL(large_size.height, max_dimension);
- BOOST_CHECK_EQUAL(large_transform.value, max_transform);
- BOOST_CHECK_EQUAL(large_format.fourcc, max_fourcc);
- BOOST_CHECK_EQUAL(large_colorspace.value, max_transform);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/infrastructure/test_platform_selection.cpp b/Software/LMSourceCode/ImageProcessing/Camera/tests/infrastructure/test_platform_selection.cpp
deleted file mode 100644
index 1363fcae..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/infrastructure/test_platform_selection.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Platform Selection Tests
- *
- * Unit tests for the camera platform selection mechanism.
- * Tests that the correct platform implementation is selected and basic integration works.
- */
-
-#include
-#include "camera_platform.hpp"
-#include
-
-BOOST_AUTO_TEST_SUITE(InfrastructureTests)
-
-BOOST_AUTO_TEST_CASE(platform_header_includes_domain) {
- // Arrange
- // (Testing that including camera_platform.hpp provides domain types)
-
- // Act
- golf_sim::camera::domain::Size size(640, 480);
- golf_sim::camera::domain::Transform transform(90);
- golf_sim::camera::domain::PixelFormat format(0x32315659);
- golf_sim::camera::domain::ColorSpace colorSpace(1);
-
- // Assert
- BOOST_CHECK_EQUAL(size.width, 640);
- BOOST_CHECK_EQUAL(size.height, 480);
- BOOST_CHECK_EQUAL(transform.value, 90);
- BOOST_CHECK_EQUAL(format.fourcc, 0x32315659);
- BOOST_CHECK_EQUAL(colorSpace.value, 1);
-}
-
-BOOST_AUTO_TEST_CASE(single_include_provides_complete_interface) {
- // Arrange
- // (Testing that single include provides all necessary types)
-
- // Act - Create instances of all domain types
- golf_sim::camera::domain::Size test_size;
- golf_sim::camera::domain::Transform test_transform;
- golf_sim::camera::domain::PixelFormat test_format;
- golf_sim::camera::domain::ColorSpace test_colorspace;
-
- // Assert - Verify types are available and constructible
- BOOST_CHECK_NO_THROW(test_size = golf_sim::camera::domain::Size(1280, 720));
- BOOST_CHECK_NO_THROW(test_transform = golf_sim::camera::domain::Transform(180));
- BOOST_CHECK_NO_THROW(test_format = golf_sim::camera::domain::PixelFormat(0x56595559));
- BOOST_CHECK_NO_THROW(test_colorspace = golf_sim::camera::domain::ColorSpace(2));
-
- // Verify the values were set correctly
- BOOST_CHECK_EQUAL(test_size.width, 1280);
- BOOST_CHECK_EQUAL(test_size.height, 720);
- BOOST_CHECK_EQUAL(test_transform.value, 180);
- BOOST_CHECK_EQUAL(test_format.fourcc, 0x56595559);
- BOOST_CHECK_EQUAL(test_colorspace.value, 2);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-// Platform-specific test suites
-#ifdef __unix__
-BOOST_AUTO_TEST_SUITE(UnixTests)
-
-BOOST_AUTO_TEST_CASE(unix_platform_implementation_available) {
- // Arrange
- // (Testing Unix platform-specific functionality when available)
-
- // Act & Assert
- // On Unix, we should have access to both domain and infrastructure types
- golf_sim::camera::domain::Size domain_size(1920, 1080);
- BOOST_CHECK_EQUAL(domain_size.width, 1920);
- BOOST_CHECK_EQUAL(domain_size.height, 1080);
-
- // Note: Additional Unix-specific tests can be added here
- // when the Unix infrastructure implementation provides more functionality
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-#elif defined(_WIN32) || defined(WIN32)
-BOOST_AUTO_TEST_SUITE(WindowsTests)
-
-BOOST_AUTO_TEST_CASE(windows_platform_implementation_available) {
- // Arrange
- // (Testing Windows platform-specific functionality when available)
-
- // Act & Assert
- // On Windows, we should have access to domain types
- golf_sim::camera::domain::Size domain_size(1920, 1080);
- BOOST_CHECK_EQUAL(domain_size.width, 1920);
- BOOST_CHECK_EQUAL(domain_size.height, 1080);
-
- // Note: Additional Windows-specific tests will be added here
- // when the Windows infrastructure implementation is created
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-#endif
-
-// Integration tests that should work on all platforms
-BOOST_AUTO_TEST_SUITE(CrossPlatformTests)
-
-BOOST_AUTO_TEST_CASE(platform_abstraction_provides_consistent_interface) {
- // Arrange
- const unsigned int test_width = 800;
- const unsigned int test_height = 600;
- const int test_transform = 270;
- const unsigned int test_fourcc = 0x32315559; // YUV format
- const int test_colorspace = 3;
-
- // Act
- golf_sim::camera::domain::Size size(test_width, test_height);
- golf_sim::camera::domain::Transform transform(test_transform);
- golf_sim::camera::domain::PixelFormat format(test_fourcc);
- golf_sim::camera::domain::ColorSpace colorSpace(test_colorspace);
-
- // Assert - Same interface works regardless of platform
- BOOST_CHECK_EQUAL(size.width, test_width);
- BOOST_CHECK_EQUAL(size.height, test_height);
- BOOST_CHECK_EQUAL(transform.value, test_transform);
- BOOST_CHECK_EQUAL(format.fourcc, test_fourcc);
- BOOST_CHECK_EQUAL(colorSpace.value, test_colorspace);
-}
-
-BOOST_AUTO_TEST_CASE(domain_types_work_in_collections) {
- // Arrange
- std::vector sizes;
- std::vector transforms;
-
- // Act
- sizes.push_back(golf_sim::camera::domain::Size(640, 480));
- sizes.push_back(golf_sim::camera::domain::Size(1280, 720));
- sizes.push_back(golf_sim::camera::domain::Size(1920, 1080));
-
- transforms.push_back(golf_sim::camera::domain::Transform(0));
- transforms.push_back(golf_sim::camera::domain::Transform(90));
- transforms.push_back(golf_sim::camera::domain::Transform(180));
- transforms.push_back(golf_sim::camera::domain::Transform(270));
-
- // Assert
- BOOST_CHECK_EQUAL(sizes.size(), 3);
- BOOST_CHECK_EQUAL(transforms.size(), 4);
-
- BOOST_CHECK_EQUAL(sizes[0].width, 640);
- BOOST_CHECK_EQUAL(sizes[0].height, 480);
- BOOST_CHECK_EQUAL(sizes[2].width, 1920);
- BOOST_CHECK_EQUAL(sizes[2].height, 1080);
-
- BOOST_CHECK_EQUAL(transforms[1].value, 90);
- BOOST_CHECK_EQUAL(transforms[3].value, 270);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/test_main.cpp b/Software/LMSourceCode/ImageProcessing/Camera/tests/test_main.cpp
deleted file mode 100644
index 55fb2974..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/test_main.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Camera Bounded Context - Test Main Entry Point
- *
- * Boost Test framework main for Camera bounded context unit tests.
- */
-
-#define BOOST_TEST_MODULE CameraBoundedContextTests
-
-// Support both header-only and linked Boost Test modes
-#ifdef BOOST_TEST_HEADER_ONLY
- #include
-#else
- #include
-#endif
-
-// Global test setup and teardown can be added here if needed
-struct GlobalTestFixture {
- GlobalTestFixture() {
- // Global test initialization
- BOOST_TEST_MESSAGE("Starting Camera Bounded Context Tests");
- }
-
- ~GlobalTestFixture() {
- // Global test cleanup
- BOOST_TEST_MESSAGE("Completed Camera Bounded Context Tests");
- }
-};
-
-BOOST_GLOBAL_FIXTURE(GlobalTestFixture);
diff --git a/Software/LMSourceCode/ImageProcessing/Camera/tests/test_utilities.hpp b/Software/LMSourceCode/ImageProcessing/Camera/tests/test_utilities.hpp
deleted file mode 100644
index 71a36e47..00000000
--- a/Software/LMSourceCode/ImageProcessing/Camera/tests/test_utilities.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Test Utilities for Camera Bounded Context
- *
- * Common utilities and fixtures for Camera unit tests.
- * Provides reusable helpers and test data.
- */
-
-#pragma once
-
-#include
-#include "camera_platform.hpp"
-#include
-#include
-#include
-#include
-
-namespace camera_test_utils {
-
- // Common test data for camera domain types
- struct CommonTestData {
- static std::vector> getValidSizes() {
- return {
- {640, 480}, // VGA
- {800, 600}, // SVGA
- {1024, 768}, // XGA
- {1280, 720}, // HD 720p
- {1920, 1080}, // Full HD 1080p
- {3840, 2160}, // 4K UHD
- {0, 0}, // Edge case: zero size
- {1, 1}, // Edge case: minimum size
- {4294967295U, 4294967295U} // Edge case: maximum size
- };
- }
-
- static std::vector getValidTransforms() {
- return {0, 90, 180, 270, -90, -180, -270, 360, 450};
- }
-
- static std::vector getValidPixelFormats() {
- return {
- 0x32315659, // YV12
- 0x32315559, // YUV
- 0x56595559, // YUYV
- 0x50424752, // RGBP
- 0x42475224, // RGB4
- 0, // Edge case: no format
- 4294967295U // Edge case: maximum value
- };
- } static std::vector getValidColorSpaces() {
- return {0, 1, 2, 3, -1, 100, 2147483647, -2147483647-1};
- }
- };
-
- // Test fixture for domain type testing
- struct DomainTypeFixture {
- DomainTypeFixture() {
- BOOST_TEST_MESSAGE("Setting up domain type test fixture");
- }
-
- ~DomainTypeFixture() {
- BOOST_TEST_MESSAGE("Tearing down domain type test fixture");
- }
-
- // Helper methods for common assertions
- void assertSizeEquals(const golf_sim::camera::domain::Size& actual,
- unsigned int expected_width,
- unsigned int expected_height) {
- BOOST_CHECK_EQUAL(actual.width, expected_width);
- BOOST_CHECK_EQUAL(actual.height, expected_height);
- }
-
- void assertTransformEquals(const golf_sim::camera::domain::Transform& actual,
- int expected_value) {
- BOOST_CHECK_EQUAL(actual.value, expected_value);
- }
-
- void assertPixelFormatEquals(const golf_sim::camera::domain::PixelFormat& actual,
- unsigned int expected_fourcc) {
- BOOST_CHECK_EQUAL(actual.fourcc, expected_fourcc);
- }
-
- void assertColorSpaceEquals(const golf_sim::camera::domain::ColorSpace& actual,
- int expected_value) {
- BOOST_CHECK_EQUAL(actual.value, expected_value);
- }
- };
-
- // Parametric test helper for testing multiple values
- template
- void runParametricTest(const std::vector& testValues, TestFunc testFunction) {
- for (const auto& value : testValues) {
- testFunction(value);
- }
- }
-
- // Performance test helper for measuring basic operations
- struct PerformanceFixture {
- PerformanceFixture() : start_time(std::chrono::high_resolution_clock::now()) {}
-
- ~PerformanceFixture() {
- auto end_time = std::chrono::high_resolution_clock::now();
- auto duration = std::chrono::duration_cast(
- end_time - start_time).count();
- BOOST_TEST_MESSAGE("Test completed in " << duration << " microseconds");
- }
-
- private:
- std::chrono::high_resolution_clock::time_point start_time;
- };
-
-} // namespace camera_test_utils
diff --git a/Software/LMSourceCode/ImageProcessing/CameraTools/discoverPiCamLocation.sh b/Software/LMSourceCode/ImageProcessing/CameraTools/discoverPiCamLocation.sh
index eaa1bc07..99f061f8 100755
--- a/Software/LMSourceCode/ImageProcessing/CameraTools/discoverPiCamLocation.sh
+++ b/Software/LMSourceCode/ImageProcessing/CameraTools/discoverPiCamLocation.sh
@@ -1,16 +1,15 @@
#!/bin/bash
rm -f discover_media.txt discover_device.txt discover_result.txt $PITRAC_ROOT/test.txt
-for((m=0; m<=5; ++m))
-do
+for ((m = 0; m <= 5; ++m)); do
rm -f discover_result.txt
- media-ctl -d "/dev/media$m" --print-dot | grep imx > discover_media.txt
- awk -F"imx296 " '{print $2}' < discover_media.txt | cut -d- -f1 > discover_device.txt
- echo -n -e "Camera is at /dev/media$m on device number " > discover_result.txt
- cat discover_device.txt >> discover_result.txt
-
-# If we found a camera, save the results. Don't stop -- there might be more than one camera
- if grep imx discover_media.txt > /dev/null ; then cat discover_result.txt >> $PITRAC_ROOT/test.txt ; fi
+ media-ctl -d "/dev/media$m" --print-dot | grep imx >discover_media.txt
+ awk -F"imx296 " '{print $2}' discover_device.txt
+ echo -n -e "Camera is at /dev/media$m on device number " >discover_result.txt
+ cat discover_device.txt >>discover_result.txt
+
+ # If we found a camera, save the results. Don't stop -- there might be more than one camera
+ if grep imx discover_media.txt >/dev/null; then cat discover_result.txt >>$PITRAC_ROOT/test.txt; fi
done
rm -f discover_media.txt discover_device.txt discover_result.txt
diff --git a/Software/LMSourceCode/ImageProcessing/CameraTools/get_tuning_file.sh b/Software/LMSourceCode/ImageProcessing/CameraTools/get_tuning_file.sh
index 848fcfbf..7ff0908a 100755
--- a/Software/LMSourceCode/ImageProcessing/CameraTools/get_tuning_file.sh
+++ b/Software/LMSourceCode/ImageProcessing/CameraTools/get_tuning_file.sh
@@ -4,7 +4,7 @@
# this machine. Only returns the _noir version.
#
-model=$(tr -d '\0' < /sys/firmware/devicetree/base/model)
+model=$(tr -d '\0' /dev/null; then echo -e "/dev/media$m\n"; break; fi
+if [[ $# -lt 4 ]]; then
+ echo Format: "$0" width height startX StartY
+ exit
+fi
+if [[ $# -gt 4 ]]; then SHTR="--shutter"; else SHTR=""; fi
+for ((m = 1; m <= 5; ++m)); do
+ if media-ctl -d "/dev/media$m" --set-v4l2 "'imx296 10-001a':0 [fmt:SBGGR10_1X10/${1}x$2 crop:($(($3)),$(($4)))/${1}x$2]" >/dev/null; then
+ echo -e "/dev/media$m\n"
+ break
+ fi
done
-libcamera-hello --list-cameras ;echo
+libcamera-hello --list-cameras
+echo
# rm -f /dev/shm/tst.pts
-# libcamera-vid --width "$1" --height "$2" --denoise cdn_off --framerate "$3" --save-pts /dev/shm/tst.pts -t "$4" "$SHTR" "$5" -o /dev/shm/tst.h264 -n ;echo
+# libcamera-vid --width "$1" --height "$2" --denoise cdn_off --framerate "$3" --save-pts /dev/shm/tst.pts -t "$4" "$SHTR" "$5" -o /dev/shm/tst.h264 -n ;echo
# rm -f tstamps.csv && ptsanalyze /dev/shm/tst.pts
diff --git a/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerExternal.sh b/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerExternal.sh
index cf4ec697..f12f87cc 100755
--- a/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerExternal.sh
+++ b/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerExternal.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-echo 1 > /sys/module/imx296/parameters/trigger_mode
+echo 1 >/sys/module/imx296/parameters/trigger_mode
diff --git a/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerInternal.sh b/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerInternal.sh
index f4902bd0..bffe6591 100755
--- a/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerInternal.sh
+++ b/Software/LMSourceCode/ImageProcessing/CameraTools/setCameraTriggerInternal.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-echo 0 > /sys/module/imx296/parameters/trigger_mode
+echo 0 >/sys/module/imx296/parameters/trigger_mode
diff --git a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/CMakeLists.txt b/Software/LMSourceCode/ImageProcessing/ImageAnalysis/CMakeLists.txt
deleted file mode 100644
index caa21341..00000000
--- a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/CMakeLists.txt
+++ /dev/null
@@ -1,304 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Copyright (C) 2022-2025, Verdant Consultants, LLC.
-
-cmake_minimum_required(VERSION 3.16)
-project(ImageAnalysis)
-
-# Handle CMake policy for FindBoost module removal in newer CMake versions
-if(POLICY CMP0167)
- cmake_policy(SET CMP0167 OLD) # Keep old behavior for compatibility
- # TODO: Migrate to new Boost discovery when upgrading CMake
-endif()
-
-# Handle CMake policy for BOOST_ROOT variable
-if(POLICY CMP0144)
- cmake_policy(SET CMP0144 NEW)
-endif()
-
-# Set C++ standard
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# Set default build type if not specified
-if(NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
- message(STATUS "Build type not specified, defaulting to Release")
-endif()
-
-# Find required packages
-# Configure OpenCV detection - require explicit OPENCV_DIR
-if(NOT DEFINED ENV{OPENCV_DIR} AND NOT DEFINED OPENCV_DIR)
- message(FATAL_ERROR
- "OPENCV_DIR must be set. Please set environment variable or pass -DOPENCV_DIR= to CMake.\n"
- "Example: $env:OPENCV_DIR = \"C:/opencv\" (PowerShell)\n"
- "Or: cmake -DOPENCV_DIR=\"C:/opencv\" .."
- )
-endif()
-
-# Use environment variable if set, otherwise use CMake variable
-if(DEFINED ENV{OPENCV_DIR} AND NOT DEFINED OPENCV_DIR)
- set(OPENCV_DIR $ENV{OPENCV_DIR})
- message(STATUS "Using OPENCV_DIR from environment: ${OPENCV_DIR}")
-elseif(DEFINED OPENCV_DIR)
- message(STATUS "Using OPENCV_DIR from CMake: ${OPENCV_DIR}")
-endif()
-
-# Validate the path exists
-if(NOT EXISTS "${OPENCV_DIR}")
- message(FATAL_ERROR "OPENCV_DIR path does not exist: ${OPENCV_DIR}")
-endif()
-
-# Add OpenCV directory to the prefix path so find_package can find it
-# The path should point directly to the directory containing OpenCVConfig.cmake
-list(APPEND CMAKE_PREFIX_PATH "${OPENCV_DIR}")
-message(STATUS "Looking for OpenCVConfig.cmake in: ${OPENCV_DIR}")
-
-find_package(OpenCV REQUIRED)
-
-# Configure Boost detection - require explicit BOOST_ROOT
-if(NOT DEFINED ENV{BOOST_ROOT} AND NOT DEFINED BOOST_ROOT)
- message(FATAL_ERROR
- "BOOST_ROOT must be set. Please set environment variable or pass -DBOOST_ROOT= to CMake.\n"
- "Example: $env:BOOST_ROOT = \"C:/Dev_Libs/boost\" (PowerShell)\n"
- "Or: cmake -DBOOST_ROOT=\"C:/Dev_Libs/boost\" .."
- )
-endif()
-
-# Use environment variable if set, otherwise use CMake variable
-if(DEFINED ENV{BOOST_ROOT} AND NOT DEFINED BOOST_ROOT)
- set(BOOST_ROOT $ENV{BOOST_ROOT})
- message(STATUS "Using BOOST_ROOT from environment: ${BOOST_ROOT}")
-elseif(DEFINED BOOST_ROOT)
- message(STATUS "Using BOOST_ROOT from CMake: ${BOOST_ROOT}")
-endif()
-
-# Validate the path exists
-if(NOT EXISTS "${BOOST_ROOT}")
- message(FATAL_ERROR "BOOST_ROOT path does not exist: ${BOOST_ROOT}")
-endif()
-
-# Configure Boost detection - Traditional FindBoost for compatibility with static libraries
-set(Boost_USE_STATIC_LIBS ON) # Use static libraries (consistent across environments)
-set(Boost_USE_MULTITHREADED ON) # Enable multithreaded libraries
-set(Boost_USE_STATIC_RUNTIME OFF) # Don't use static runtime (avoids conflicts)
-set(Boost_NO_BOOST_CMAKE ON) # Use traditional FindBoost module for better static lib support
-set(Boost_NO_SYSTEM_PATHS ON) # Only look in specified paths
-
-# Add Boost library directory to help CMake find the libraries
-if(BOOST_ROOT)
- list(APPEND CMAKE_PREFIX_PATH "${BOOST_ROOT}")
-
- # Set additional hints for modern CMake
- set(Boost_ROOT "${BOOST_ROOT}")
- set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib64-msvc-14.3")
- set(BOOST_INCLUDEDIR "${BOOST_ROOT}/include")
-
- # Fallback if include is in root directory
- if(NOT EXISTS "${BOOST_INCLUDEDIR}")
- set(BOOST_INCLUDEDIR "${BOOST_ROOT}")
- endif()
-endif()
-
-# Find Boost with unit test framework
-find_package(Boost REQUIRED COMPONENTS unit_test_framework)
-
-# Source files for the bounded context
-set(IMAGE_ANALYSIS_SOURCES
- infrastructure/opencv_image_analyzer.cpp
-)
-
-set(IMAGE_ANALYSIS_HEADERS
- domain/value_objects.hpp
- domain/analysis_results.hpp
- domain/interfaces.hpp
- application/image_analysis_service.hpp
- infrastructure/opencv_image_analyzer.hpp
- infrastructure/ml_image_analyzer.hpp
-)
-
-# Approval testing framework sources
-set(APPROVAL_FRAMEWORK_SOURCES
- tests/approval/approval_test_config.cpp
- tests/approval/result_formatter.cpp
- tests/approval/visualization_service.cpp
- tests/approval/comparison_service.cpp
- tests/approval/diff_launcher.cpp
- tests/approval/approval_test_orchestrator.cpp
-)
-
-set(APPROVAL_FRAMEWORK_HEADERS
- tests/approval/approval_test_config.hpp
- tests/approval/result_formatter.hpp
- tests/approval/visualization_service.hpp
- tests/approval/comparison_service.hpp
- tests/approval/diff_launcher.hpp
- tests/approval/approval_test_orchestrator.hpp
-)
-
-# Create static library for the bounded context
-add_library(image_analysis STATIC ${IMAGE_ANALYSIS_SOURCES})
-
-# Link libraries using modern CMake targets
-target_link_libraries(image_analysis
- PUBLIC ${OpenCV_LIBS} # Use OpenCV_LIBS for consistency
-)
-
-# Set include directories for the library
-target_include_directories(image_analysis
- PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/.. # For access to existing headers
- PRIVATE
- ${OpenCV_INCLUDE_DIRS}
-)
-
-# Include approval framework headers for tests that need them
-target_include_directories(image_analysis
- PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/tests/approval # For approval testing framework
-)
-
-# Compiler flags
-if(MSVC)
- target_compile_options(image_analysis PRIVATE
- /W4 # High warning level
- $<$:/Od /Zi>
- $<$:/O2 /DNDEBUG>
- )
-else()
- target_compile_options(image_analysis PRIVATE
- -Wall -Wextra -Wpedantic
- $<$:-g -O0>
- $<$:-O3 -DNDEBUG>
- )
-endif()
-
-# Function to configure Boost Test linking for a target
-function(configure_boost_test_target target_name)
- target_link_libraries(${target_name} PRIVATE
- Boost::unit_test_framework
- image_analysis
- ${OpenCV_LIBS} # Use OpenCV_LIBS variable for consistency
- )
- # Note: No BOOST_TEST_DYN_LINK definition needed for static linking
-endfunction()
-
-enable_testing()
-
-# =============================================================================
-# Test Executables and Configuration
-# =============================================================================
-
-# Domain tests (no external dependencies)
-add_executable(test_image_analysis_domain tests/test_image_analysis_domain.cpp)
-configure_boost_test_target(test_image_analysis_domain)
-add_test(NAME DomainTests COMMAND test_image_analysis_domain)
-
-# Domain validation tests (input validation and invariant enforcement)
-add_executable(test_domain_validation tests/test_domain_validation.cpp)
-configure_boost_test_target(test_domain_validation)
-add_test(NAME DomainValidationTests COMMAND test_domain_validation)
-
-# OpenCV integration tests
-add_executable(test_opencv_analyzer tests/test_opencv_analyzer.cpp)
-configure_boost_test_target(test_opencv_analyzer)
-add_test(NAME OpenCVTests COMMAND test_opencv_analyzer)
-
-# Application service tests (input validation, configuration)
-add_executable(test_image_analysis_service tests/test_image_analysis_service.cpp)
-configure_boost_test_target(test_image_analysis_service)
-add_test(NAME ApplicationServiceTests COMMAND test_image_analysis_service)
-
-# Approval tests using clean architecture framework
-add_executable(test_approval_with_pitrac_images
- tests/test_approval_with_pitrac_images.cpp
- ${APPROVAL_FRAMEWORK_SOURCES}
-)
-configure_boost_test_target(test_approval_with_pitrac_images)
-add_test(NAME ApprovalTests COMMAND test_approval_with_pitrac_images)
-
-# Set test properties
-set_tests_properties(DomainTests PROPERTIES
- TIMEOUT 30
- LABELS "unit;domain"
-)
-
-set_tests_properties(DomainValidationTests PROPERTIES
- TIMEOUT 30
- LABELS "unit;domain;validation"
-)
-
-set_tests_properties(OpenCVTests PROPERTIES
- TIMEOUT 60
- LABELS "integration;opencv"
-)
-
-set_tests_properties(ApplicationServiceTests PROPERTIES
- TIMEOUT 30
- LABELS "unit;application;validation"
-)
-
-set_tests_properties(ApprovalTests PROPERTIES
- TIMEOUT 120
- LABELS "approval;pitrac;images;clean-architecture"
-)
-
-# Install rules
-install(TARGETS image_analysis
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
- RUNTIME DESTINATION bin
-)
-
-install(FILES ${IMAGE_ANALYSIS_HEADERS}
- DESTINATION include/ImageAnalysis
-)
-
-# Install approval testing framework headers (for reuse in other projects)
-install(FILES ${APPROVAL_FRAMEWORK_HEADERS}
- DESTINATION include/ImageAnalysis/approval
-)
-
-# Development convenience targets
-add_custom_target(run_tests
- COMMAND ctest --output-on-failure
- DEPENDS test_image_analysis_domain test_opencv_analyzer test_image_analysis_service test_approval_with_pitrac_images
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
- COMMENT "Running all image analysis tests"
-)
-
-add_custom_target(run_domain_tests
- COMMAND test_image_analysis_domain
- DEPENDS test_image_analysis_domain
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
- COMMENT "Running domain tests only"
-)
-
-# TEMPORARILY DISABLED: Domain validation tests convenience target (Boost linking issue)
-# add_custom_target(run_domain_validation_tests
-# COMMAND test_domain_validation
-# DEPENDS test_domain_validation
-# WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-# COMMENT "Running domain validation tests only"
-# )
-
-add_custom_target(run_integration_tests
- COMMAND test_opencv_analyzer
- DEPENDS test_opencv_analyzer
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
- COMMENT "Running integration tests only"
-)
-
-add_custom_target(run_approval_tests
- COMMAND test_approval_with_pitrac_images
- DEPENDS test_approval_with_pitrac_images
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
- COMMENT "Running approval tests with clean architecture framework"
-)
-
-# Print configuration summary
-message(STATUS "Image Analysis Bounded Context Configuration:")
-message(STATUS " OpenCV version: ${OpenCV_VERSION}")
-message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
-message(STATUS " C++ standard: ${CMAKE_CXX_STANDARD}")
-message(STATUS " Tests enabled: ${Boost_FOUND}")
diff --git a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/DEMO_SCRIPT.md b/Software/LMSourceCode/ImageProcessing/ImageAnalysis/DEMO_SCRIPT.md
deleted file mode 100644
index e7e7dbd8..00000000
--- a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/DEMO_SCRIPT.md
+++ /dev/null
@@ -1,489 +0,0 @@
-# ImageAnalysis Bounded Context - 20 Minute Demo Script
-
-## Demo Overview
-**Audience**: Development team, stakeholders
-**Duration**: 20 minutes
-**Goal**: Showcase clean DDD architecture, robustness, and migration strategy for golf ball image analysis
-
----
-
-## 🎯 Demo Flow (20 minutes)
-
-### **Part 1: Introduction & Problem Statement** (3 minutes)
-
-#### The Legacy Challenge
-> *"We have sophisticated golf ball analysis in `gs_camera.cpp` - 400+ lines of complex physics achieving ±1-2% accuracy. But it's tightly coupled to hardware, platform-specific, and nearly impossible to unit test."*
-
-**Show the problem:**
-```bash
-# Navigate to legacy code
-cd c:\kata\PiTrac\Software\LMSourceCode\ImageProcessing
-code gs_camera.cpp
-```
-
-**Point out platform portability issues:**
-
-**Hardware Dependencies:**
-- **Line 1-20**: `#include "libcamera_interface.h"` - Linux-only libcamera library
-- **Line 1-20**: `#include "pulse_strobe.h"` - GPIO (Gen Purpose IO) hardware for LED strobes
-- **Throughout**: Raspberry Pi-specific GPIO pins (`BCM GPIO25`, SPI (serial) interfaces)
-
-**Platform-Specific Code:**
-```bash
-# Show the conditional compilation
-grep -n "#ifdef __unix__" pulse_strobe.cpp libcamera_interface.h
-```
-- **All camera code**: Wrapped in `#ifdef __unix__` - doesn't compile on Windows
-- **GPIO libraries**: `lgpio.h`, hardware SPI communication
-- **Pi-specific**: RPi4 vs RPi5 chip differences, hardware timing dependencies
-
-**Testing Impossibilities:**
-- **No unit tests**: Everything requires physical camera hardware
-- **Hardware coupling**: Cannot mock GPIO, SPI, or camera interfaces
-- **Integration-only**: Tests need full Pi setup with strobes and cameras
-- **Platform lock-in**: Development must happen on actual Raspberry Pi hardware
-
-**Maintenance Problems:**
-- **Line 768**: `CalculateBallVelocity()` - Ball speed calculations from position deltas
-- **Line 785**: `GetTotalDistance()` - 3D distance calculations using Pythagorean theorem
-- **Line 1006**: `ComputeXyzDistanceFromOrthoCamPerspective()` - Critical 3D coordinate transformations
-- **Line 1284**: `AdjustDistanceForSlowing()` usage - Friction compensation for ball physics
-- **Line 2468**: `AdjustDistanceForSlowing()` implementation - Ball deceleration physics
-
-**Physics Algorithm Migration Status:**
-
-✅ **Already Has Placeholder Implementation:**
-- **Ball detection** - Current `OpenCVImageAnalyzer::AnalyzeTeedBall()` uses basic Hough circles
-- **Movement detection** - Current optical flow implementation exists
-
-❌ **Still Needs Domain Services + Value Objects + OpenCV Implementation:**
-
-1. **Line 1006: `ComputeXyzDistanceFromOrthoCamPerspective`** (HIGHEST PRIORITY)
- - **Domain Service**: `ICoordinateTransformationService`
- - **Value Objects**: `WorldPosition`, `CameraCalibration`, `CoordinateTransformResult`
- - **OpenCV Implementation**: `OpenCVCoordinateTransformer` with full spherical coordinate math
- - **Critical**: Foundation for all other ball positioning calculations
-
-2. **Line 768: `CalculateBallVelocity`**
- - **Domain Service**: `IVelocityCalculationService`
- - **Value Objects**: `VelocityVector`, `PositionDelta`
- - **OpenCV Implementation**: Time-based position delta calculations
-
-3. **Line 2468: `AdjustDistanceForSlowing`**
- - **Domain Service**: `IBallPhysicsService`
- - **Value Objects**: `BallDeceleration`, `FrictionCoefficient`
- - **OpenCV Implementation**: Club-specific friction compensation algorithms
-
-4. **Line 785: `GetTotalDistance`**
- - **Simple utility** - Can be a static method in `MathUtils` (no service needed)
-
-> **Implementation Order**: The 3D coordinate transformation (#1) should be implemented first as it's the foundation that velocity calculations and physics simulations depend on.
-- **Monolithic design**: Physics calculations intertwined with GPIO timing
-- **No separation**: Business logic cannot be extracted from hardware dependencies
-
-#### The DDD Solution Preview
-> *"We're introducing a bounded context with clean architecture that will allow us to protect the physics sophistication while making it testable and maintainable."*
-
----
-
-### **Part 2: Clean Architecture Tour** (5 minutes)
-
-#### Navigate to the New Structure
-```bash
-cd ImageAnalysis
-tree /f
-```
-
-**Explain the layers:**
-
-#### **Domain Layer** (Technology-Agnostic Business Rules)
-```bash
-code domain/value_objects.hpp
-```
-
-**Key talking points:**
-- **Immutable value objects**: `BallPosition`, `ImageBuffer` - no setters, construction validation
-- **Rich domain models**: `DistanceFrom()`, `IsValidPosition()` - behavior with data
-- **No external dependencies**: Pure C++, no OpenCV/boost in domain
-
-```cpp
-// Show this example in value_objects.hpp
-class BallPosition {
- // Immutable - no setters
- // Rich behavior - DistanceFrom(), IsValidPosition()
- // Validation in constructor - prevents invalid states
-};
-```
-
-#### **Application Layer** (Use Cases & Orchestration)
-```bash
-code application/image_analysis_service.hpp
-```
-
-**Key talking points:**
-- **Service orchestration**: Coordinates between domain and infrastructure
-- **Configuration management**: Handles analyzer selection and parameters
-- **Technology abstraction**: Business logic independent of OpenCV/ML frameworks
-
-#### **Infrastructure Layer** (Implementation Details)
-```bash
-code infrastructure/opencv_image_analyzer.hpp
-```
-
-**Key talking points:**
-- **Adapter pattern**: Wraps existing `BallImageProc` in clean interface
-- **Dependency inversion**: Implements domain interfaces
-- **Framework isolation**: OpenCV details contained here
-
----
-
-### **Part 3: Practical Code Demonstration** (6 minutes)
-
-#### **Demo 1: Creating and Using the Service**
-```bash
-# Open the public API
-code image_analysis.hpp
-```
-
-**Show the clean API:**
-```cpp
-// Simple factory pattern
-auto service = CreateAnalysisService("opencv");
-
-// Clean domain objects
-domain::ImageBuffer image = LoadTestImage();
-auto result = service->AnalyzeTeedBall(image);
-
-if (result.state == domain::BallState::TEED) {
- // Rich result objects with behavior
- std::cout << "Ball at: " << result.position->ToString() << std::endl;
-}
-```
-
-#### **Demo 1b: Feature Switch Integration Pattern**
-```bash
-# Show how this integrates with legacy code
-code ../gs_camera.cpp
-# Navigate to line 768 (CalculateBallVelocity)
-```
-
-**Show the integration approach:**
-```cpp
-// Example integration pattern in gs_camera.cpp
-double CalculateBallVelocity(/* existing parameters */) {
- if (golf_sim_config.enable_new_image_analysis) {
- // Route to new bounded context
- auto service = ImageAnalysis::CreateAnalysisService("opencv");
- domain::ImageBuffer imageBuffer = ConvertFromLegacy(image_data);
- auto result = service->AnalyzeMovement(imageBuffer);
-
- if (result.has_velocity) {
- return result.velocity->magnitude();
- }
- // Fallback to legacy if new system fails
- }
-
- // Original legacy implementation stays completely untouched
- return OriginalCalculateBallVelocity(/* existing parameters */);
-}
-```
-
-**Key talking points:**
-- **Zero risk**: Legacy code path remains completely unchanged
-- **Instant rollback**: Single configuration flag disables new system
-- **Graceful degradation**: New system failure automatically falls back to legacy
-- **No deployment needed**: Configuration changes take effect immediately
-
-#### **Demo 2: Domain Logic Robustness**
-```bash
-# Show domain validation tests
-code tests/test_image_analysis_domain.cpp
-```
-
-**Run the tests live:**
-```bash
-cd build
-cmake --build . --target test_domain_validation
-./test_domain_validation
-```
-
-**Key talking points:**
-- **100% pass rate**: All 15 domain validation tests passing
-- **Edge case handling**: NaN, infinity, negative values all validated
-- **Immutable guarantees**: Construction-time validation prevents invalid states
-
-#### **Demo 3: Infrastructure Adapter**
-```bash
-code infrastructure/opencv_image_analyzer.cpp
-```
-
-**Highlight improvements:**
-- **Named constants**: `MOVEMENT_THRESHOLD`, `VELOCITY_SCALING_FACTOR` instead of magic numbers
-- **Error handling**: Comprehensive OpenCV exception handling
-- **Input validation**: Empty images, parameter range checks
-- **Performance**: Memory preallocation, efficient algorithms
-
----
-
-### **Part 4: Test Framework Robustness** (4 minutes)
-
-#### **Approval Tests with Real Images**
-```bash
-# Show the approval test framework
-code tests/test_approval_with_pitrac_images.cpp
-```
-
-**Key talking points:**
-- **Real image validation**: Uses actual PiTrac camera images
-- **Regression protection**: Any algorithm changes are immediately visible
-- **Cross-platform consistency**: Same results on dev box and CI
-
-#### **Run Tests Locally**
-```bash
-cd build
-cmake --build . --target test_approval
-./test_approval
-```
-
-**Show the output:**
-- ✅ **Ball detection consistency**: Same results across runs
-- ✅ **Algorithm stability**: No unexpected changes in behavior
-- ✅ **Performance metrics**: Execution time tracking
-
-#### **GitHub Actions Integration**
-```bash
-# Show the CI configuration (if available)
-cat ../.github/workflows/imaganalysis.yml
-```
-
-**Demonstrate robustness:**
-> *"These same tests run in GitHub Actions on every PR. No physical camera required - we use test images and mock calibration data."*
-
-**Key talking points:**
-- **No hardware dependencies**: Tests run in containerized environment
-- **Fast feedback**: Developers get immediate validation
-- **Regression prevention**: Breaking changes caught before merge
-
-#### **Live Demo: Proving Test Sensitivity**
-> *"Let's prove these tests actually catch changes by intentionally breaking something and watching the approval tests fail."*
-
-**Step 1: Make a deliberate algorithm change**
-```bash
-# Open the OpenCV analyzer implementation
-code infrastructure/opencv_image_analyzer.cpp
-```
-
-**Find the ball detection parameters (around line 45-50):**
-```cpp
-// Current values (show these)
-const double MOVEMENT_THRESHOLD = 5.0;
-const int MIN_RADIUS = 8;
-const int MAX_RADIUS = 25;
-```
-
-**Change the detection sensitivity:**
-```cpp
-// Temporarily change MIN_RADIUS to make detection less sensitive
-const int MIN_RADIUS = 15; // Changed from 8 to 15
-```
-
-**Step 2: Rebuild and run approval tests**
-```bash
-cd build
-cmake --build . --target test_approval
-./test_approval
-```
-
-**Expected output (show this to audience):**
-```
-❌ APPROVAL TEST FAILED: Ball detection results changed!
-Expected: Ball detected at (145, 230) with radius 12
-Actual: No ball detected (radius 12 < MIN_RADIUS 15)
-
-Diff saved to: test_results/approval_diff_20250710_143022.txt
-```
-
-**Step 3: Show the diff file**
-```bash
-# Display the detailed differences
-Get-Content test_results/approval_diff_20250710_143022.txt
-```
-
-**Step 4: Revert the change and prove tests pass again**
-```cpp
-// Revert back to original value
-const int MIN_RADIUS = 8; // Back to original
-```
-
-```bash
-# Rebuild and test again
-cmake --build . --target test_approval
-./test_approval
-```
-
-**Expected output:**
-```
-✅ All approval tests passed!
-✅ Ball detection: 5/5 images processed correctly
-✅ Algorithm behavior unchanged from baseline
-```
-
-**Key demonstration points:**
-- **Immediate feedback**: Change detected within seconds
-- **Detailed reporting**: Exact differences shown with context
-- **Regression prevention**: Any algorithm modification is immediately visible
-- **Confidence in deployment**: If tests pass, behavior is identical to baseline
-
----
-
-### **Part 5: Migration Strategy & Future Vision** (2 minutes)
-
-#### **Current State: Placeholder Algorithms**
-```bash
-# Show current implementation
-grep -n "TEMPORAL_SPACING_US" infrastructure/opencv_image_analyzer.cpp
-```
-
-**Explain the strategy:**
-> *"Current algorithms are intentionally simplified placeholders. They validate our architecture while we prepare the physics migration."*
-
-- **±10-20% accuracy**: Sufficient for architectural validation
-- **2D calculations**: Placeholder for 3D world coordinates
-- **Fixed timing**: Hardcoded 1ms intervals (temporary)
-
-#### **Future State: Feature Switch Integration**
-```bash
-# Show the integration strategy
-code gs_camera.cpp
-# Look for the integration points around lines 768, 1006, 2468
-```
-
-**Feature Switch Architecture:**
-```cpp
-// Example integration in gs_camera.cpp
-if (config.UseNewImageAnalysis()) {
- // Route to new bounded context
- auto service = ImageAnalysis::CreateAnalysisService("opencv");
- auto result = service->AnalyzeTeedBall(imageBuffer);
- return ConvertToLegacyFormat(result);
-} else {
- // Keep existing legacy implementation untouched
- return OriginalCalculateBallVelocity(/* existing parameters */);
-}
-```
-
-**Migration phases:**
-1. **Phase 1** (Current): DDD foundation with placeholder algorithms
-2. **Phase 2**: Feature switch integration points in `gs_camera.cpp`
-3. **Phase 3**: Port sophisticated 3D physics with side-by-side validation
-4. **Phase 4**: Gradual switch enablement (per-algorithm feature flags)
-5. **Phase 5**: Legacy code removal after confidence period
-
-**Target outcomes:**
-- **±1-2% accuracy**: Match legacy system performance exactly
-- **Zero deployment risk**: Instant rollback via configuration
-- **Clean architecture**: Maintain testability and maintainability
-- **No regression**: Legacy code remains as fallback safety net
-
----
-
-## 🗨️ Key Talking Points for Q&A
-
-### **Architecture Benefits**
-- **Testability**: 100% of domain logic is unit tested
-- **Maintainability**: Clear separation of concerns, easy to modify
-- **Extensibility**: Can add ML implementations without changing existing code
-- **Performance**: Same underlying algorithms, just better organized
-
-### **Migration Safety**
-- **Feature switch architecture**: Legacy code remains completely untouched
-- **Zero-risk rollback**: Instant switch back to working legacy implementation
-- **No deployment required**: Toggle switches via configuration without code changes
-- **Gradual transition**: Can enable per-feature (ball detection, velocity calculation, etc.)
-- **A/B testing capability**: Compare legacy vs new results side-by-side
-- **Regression testing**: Approval tests validate exact behavioral equivalence
-- **Parallel execution**: Run both systems simultaneously for validation
-
-### **Platform Portability Issues**
-- **Hardware lock-in**: All development requires physical Raspberry Pi with cameras
-- **No Windows development**: Cannot compile or test on developer machines
-- **GPIO dependencies**: LED strobe timing tied to specific Linux GPIO libraries
-- **Integration-only testing**: No unit tests possible due to hardware coupling
-
-### **Technical Decisions**
-- **Why DDD?**: Complex domain logic benefits from explicit modeling
-- **Why immutable objects?**: Thread safety, easier reasoning, fewer bugs
-- **Why placeholder algorithms?**: Validate architecture before complex physics migration
-- **Why approval tests?**: Real-world validation with actual camera images
-
-### **Common Questions & Answers**
-
-**Q: "Will this slow down the system?"**
-A: No performance impact. Same underlying algorithms, just better organized. Infrastructure benchmarks show <5% overhead.
-
-**Q: "How do we know the migration won't break anything?"**
-A: **Feature switches provide instant rollback safety.** Legacy code stays completely untouched - we simply route requests to the new bounded context when the feature switch is enabled. If anything goes wrong, we flip the switch back to legacy with zero deployment risk. Plus, approval tests validate exact behavioral equivalence between old and new implementations.
-
-**Q: "Why not just refactor the existing code?"**
-A: Legacy code has fundamental platform portability issues. All camera/strobe code is wrapped in `#ifdef __unix__` and requires:
-- Linux-only libcamera library
-- Raspberry Pi GPIO hardware (lgpio.h)
-- Physical SPI interfaces for LED strobes
-- Hardware timing dependencies
-- Cannot be unit tested on development machines
-- DDD approach enables cross-platform development and proper unit testing while preserving the sophisticated physics.
-
-**Q: "What about the complex physics calculations?"**
-A: They'll be preserved exactly - just moved into proper domain services with better structure and full test coverage.
-
-**Q: "How long until we can deprecate gs_camera.cpp?"**
-A: **We never have to.** With feature switches, legacy code becomes our permanent safety net. Phase 2-3 implementation is estimated at 2-3 weeks, but legacy code stays available indefinitely. After 6+ months of confidence with the new system, we can consider cleanup - but there's no pressure since the feature switch architecture maintains both paths safely.
-
----
-
-## 🎬 Demo Preparation Checklist
-
-### **Before the Demo:**
-- [ ] **Build the project**: Ensure all tests are passing
-- [ ] **Prepare test images**: Have sample images ready for live demo
-- [ ] **Set up terminal**: Multiple tabs with relevant directories open
-- [ ] **IDE setup**: Have key files bookmarked for quick navigation
-- [ ] **Backup plan**: Screenshots of test output in case live demo fails
-
-### **Terminal Setup:**
-```bash
-# Tab 1: Project root
-cd c:\kata\PiTrac\Software\LMSourceCode\ImageProcessing\ImageAnalysis
-
-# Tab 2: Build directory
-cd c:\kata\PiTrac\Software\LMSourceCode\ImageProcessing\ImageAnalysis\build
-
-# Tab 3: Legacy code for comparison
-cd c:\kata\PiTrac\Software\LMSourceCode\ImageProcessing
-```
-
-### **Key Files to Have Ready:**
-1. `domain/value_objects.hpp` - Show immutable design
-2. `infrastructure/opencv_image_analyzer.cpp` - Show improvements
-3. `tests/test_image_analysis_domain.cpp` - Show test robustness
-4. `README.md` - Show migration roadmap
-5. `gs_camera.cpp` - Show legacy complexity and feature switch integration points
-6. `golf_sim_config.json` - Show feature switch configuration
-
----
-
-## 🎯 Success Metrics for Demo
-
-**Technical audience should walk away understanding:**
-- How DDD principles improve code quality
-- Why the architecture supports future ML implementations
-- How approval tests provide regression protection
-- The clear migration path that preserves existing functionality
-
-**Business audience should walk away understanding:**
-- No risk to existing functionality
-- Improved maintainability and extensibility
-- Foundation for future AI/ML enhancements
-- Faster development cycles through better testing
-
----
diff --git a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/README.md b/Software/LMSourceCode/ImageProcessing/ImageAnalysis/README.md
deleted file mode 100644
index bb5c3a2a..00000000
--- a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/README.md
+++ /dev/null
@@ -1,263 +0,0 @@
-# Image Analysis Bounded Context
-
-This bounded context provides clean abstractions for golf ball image analysis capabilities, enabling the system to detect teed balls, movement, ball flight analysis, and ball reset detection. It follows Domain-Driven Design principles with a roadmap for porting over the physics-based speed detection.
-
-### Requires Camera Calibration Integration
-
-Once merged - the Camera bounded context can be used to create the calibration parameters. This will enable the 3D coordinate transformations found in gs_camera.cpp
-
-**Files to modify**: `domain/value_objects.hpp`, `domain/analysis_results.hpp`
-
-**Next Steps**: See [Implementation Roadmap](#implementation-roadmap) below for the complete TODO action plan.
-
-## Architecture
-
----
-
-## Architecture Detail
-
-### Clean Architecture Implementation
-
-The implementation follows Clean Architecture principles with layers for abstracting implementation details:
-
-```
-ImageAnalysis/
-├── domain/ # Business rules and entities (technology-agnostic)
-│ ├── value_objects.hpp # BallPosition, ImageBuffer, BallState, CameraCalibrationRef
-│ ├── analysis_results.hpp # TeedBallResult, MovementResult, FlightAnalysisResult
-│ └── interfaces.hpp # IImageAnalyzer interface
-├── application/ # Use cases and application services
-│ └── image_analysis_service.hpp # High-level service orchestration
-├── infrastructure/ # Implementation details (frameworks, external libraries)
-│ ├── opencv_image_analyzer.hpp/cpp # OpenCV/Hough circles implementation
-│ └── ml_image_analyzer.hpp # ML/AI framework (YOLO, TensorFlow, etc.)
-├── image_analysis.hpp # Public API (main entry point)
-└── image_analysis.cpp # API implementation
-
-External Dependencies:
-├── Camera/ # Camera bounded context (separate PR)
-│ └── calibration_service.hpp # Provides CameraCalibration objects
-```
-
-### Current Speed Detection Architecture
-
-**Current Implementation** (DDD Phase - Placeholder Algorithms):
-> **Note**: These are simplified placeholder algorithms designed to validate the approval test framework and clean DDD architecture. They provide example functionality until the existing 3D physics implementation is ported over.
-
-- **2D pixel-space calculations**: Simple x/y displacement over time (placeholder for 3D world coordinates)
-- **Fixed timing**: Hardcoded 1ms intervals (`TEMPORAL_SPACING_US = 1000`) (placeholder for dynamic hardware timing)
-- **No camera correction**: Direct pixel-to-meter conversion without perspective adjustment (placeholder for full 3D calibration)
-- **Basic physics**: Linear velocity calculation without spin (placeholder)
-
-**Target Implementation** (After Physics Integration):
-- **3D world coordinates**: Uses `gs_camera.cpp` coordinate transformation algorithms
-- **Dynamic timing**: Hardware strobe interval synchronization from `GetStrobeInterval()`
-- **Camera calibration**: 3D perspective correction using focal length and sensor dimensions
-- **Physics**: 3D Euclidean distance with air resistance compensation from gs_camera.cpp
-`GolfSimCamera::CalculateBallVelocity()`
-
-## Usage
-
-### Basic Usage
-
-```cpp
-#include "ImageAnalysis/image_analysis.hpp"
-
-using namespace golf_sim::image_analysis;
-
-// Create a service with OpenCV implementation
-auto service = CreateAnalysisService("opencv");
-
-// Analyze an image for teed ball
-domain::ImageBuffer image = ...; // Your image data
-auto result = service->AnalyzeTeedBall(image);
-
-if (result.state == domain::BallState::TEED) {
- std::cout << "Ball detected at ("
- << result.position->x_pixels << ", "
- << result.position->y_pixels << ")" << std::endl;
-}
-```
-
-### Advanced Configuration
-
-```cpp
-// Create factory and configure manually
-auto factory = CreateAnalyzerFactory();
-auto service = std::make_unique(std::move(factory));
-
-application::AnalyzerConfig config;
-config.type = "opencv";
-config.parameters["min_radius"] = "10";
-config.parameters["max_radius"] = "100";
-config.enable_debug_output = true;
-
-service->Configure(config);
-```
-
-### Movement Detection
-
-```cpp
-// Detect ball movement (shot in progress)
-std::vector image_sequence = ...;
-domain::BallPosition reference_position = ...;
-
-auto movement_result = service->DetectMovement(image_sequence, reference_position);
-if (movement_result.movement_detected) {
- std::cout << "Shot detected! Movement confidence: "
- << movement_result.movement_confidence << std::endl;
-}
-```
-
-### Current Ball Flight Analysis (2D Approach)
-
-**Current State**: Basic 2D pixel-space velocity calculation with fixed timing
-- Returns velocity vector in m/s with ±10-20% accuracy
-- Uses hardcoded temporal spacing assumptions
-- No camera perspective correction applied
-- Suitable for development and testing phases
-
-## Available Implementations
-
-### OpenCV Implementation (`opencv`)
-- **Technology**: OpenCV Hough Circle Detection
-- **Dependencies**: Existing `BallImageProc` and `GolfSimCamera` classes
-
-### Example of a theoretical alternative Implementation (`machine learning` )
-- **Technology**: YOLO v5/v8, TensorFlow Lite, PyTorch Mobile
-- **Use Cases**: Experimentation, challenging lighting/backgrounds
-- **Dependencies**: Model files, ML framework libraries
-
-## Adding or Testing New Implementations
-
-If you wanted to add a new analyzer implementation, but still keep existing logic working:
-For example using a trained model built from Machine Learning frameworks like TensorFlow:
-
-1. Create a class implementing `domain::IImageAnalyzer`
-2. Place it in `infrastructure/` folder
-3. Update the factory in `image_analysis.cpp`
-4. Add configuration support in application layer
-
-Example:
-
-```cpp
-namespace golf_sim::image_analysis::infrastructure {
-
- class CustomImageAnalyzer : public domain::IImageAnalyzer {
- public:
- domain::TeedBallResult AnalyzeTeedBall(
- const domain::ImageBuffer& image,
- const std::optional& expected_position
- ) override {
- // Your implementation here
- }
-
- // ... implement other methods
- };
-}
-```
-
-## Integration with Existing Code
-
-This bounded context is designed to integrate with the existing PiTrac system:
-
-- **OpenCV Implementation**: Wraps existing `BallImageProc` logic
-- **Camera Integration**: Compatible with `GolfSimCamera` strobed analysis
-- **Result Compatibility**: Can be converted to existing `GolfBall` objects
-- **Configuration**: Uses existing JSON configuration patterns
-
-## Testing
-
-```cpp
-// Unit tests should focus on domain logic
-TEST(ImageAnalysisTest, BallPositionCalculation) {
- domain::BallPosition pos1(100, 200, 15);
- domain::BallPosition pos2(105, 205, 15);
-
- EXPECT_NEAR(pos1.DistanceFrom(pos2), 7.07, 0.1);
-}
-
-// Integration tests should verify adapter behavior
-TEST(OpenCVAnalyzerTest, DetectsTeedBall) {
- infrastructure::OpenCVImageAnalyzer analyzer;
- domain::ImageBuffer test_image = LoadTestImage("teed_ball.jpg");
-
- auto result = analyzer.AnalyzeTeedBall(test_image);
- EXPECT_EQ(result.state, domain::BallState::TEED);
-}
-```
-
-## Performance Considerations
-
-- **Memory Usage**: Minimal overhead beyond underlying implementations
-- **Threading**: All implementations are thread-safe for read operations
-
-## Migration Guide
-
-### Migration Steps
-
-**Phase 1: Current Migration (Basic DDD)**
-- Replace `BallImageProc` direct usage with DDD service interface
-- Maintain existing algorithms during architectural transition
-- Clean separation of concerns with immutable value objects
-
-**Phase 2: Enhanced Migration (3D Physics Integration)**
-- Integrate Camera bounded context for calibration parameters
-- Port 3D coordinate transformation logic from `gs_camera.cpp`
-- Implement physics-based velocity calculations
-- Target: Preserve legacy system behavior
-
-### Migration Timeline
-
-1. **Immediate** (Current): Create DDD interface with enough logic to get automated tests running in pipelines
-2. **Phase 2**: Camera calibration integration after Camera bounded context PR
-3. **Phase 3**: Port existing behavior to Bounded Context
-4. **Phase 3a** Add Feature switching to divert code to new BC logic in NonProd or for UAT Testing
-5. **Phase 3b** Complete migration deprecating `gs_camera.cpp`
-
----
-
-## Additional Resources
-
-### Related Documentation
-- **Camera Bounded Context**:
-[Pull Request](https://github.com/pitraclm/pitrac/pull/87) Provides camera abstractions and calibration data.
-
-## Camera Bounded Context Integration
-
-### Architecture Decision: Separation of Concerns
-
-The Camera bounded context (separate PR) will handle:
-- **Camera hardware management** (initialization, configuration)
-- **Calibration parameters** (focal length, sensor dimensions, distortion coefficients)
-- **Camera-specific operations** (frame capture, timing synchronization)
-
-ImageAnalysis bounded context will:
-- **Consume calibration data** from Camera context via dependency injection
-- **Focus on ball detection and tracking** algorithms
-- **Perform coordinate transformations** using Camera-provided parameters
-- **Calculate velocities and trajectories** in world coordinates
-
-### Integration Pattern
-
-**Clean separation between bounded contexts:**
-- ImageAnalysis focuses on ball detection and velocity calculation algorithms
-- Camera context provides calibration data via dependency injection
-- Hardware timing integration through service interfaces
-- No duplication of camera management logic across contexts
-- No requirement for physical cameras or strobe capture of real ball flight when working on the code
-
-**Key Benefits:**
-1. **Single Responsibility**: Each context handles its domain expertise
-2. **Reduced Coupling**: Clean dependency direction (ImageAnalysis → Camera)
-3. **Reusability**: Camera calibration shared across multiple contexts
-4. **Testability**: Mock camera services for isolated testing
-
-### Success Criteria
-
-#### ✅ Phase 1 Complete When:
-- [ ] **Behavior maintained** algorithms in the legacy implementation can be duplicated
-- [ ] **Automated tests passing** Approval tests and unit tests give developer feedback to protect against regression
-- [ ] **Camera BC integrated** into analysis pipeline - no physical camera required in the build agents
-
----
diff --git a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/REFACTORING_PLAN.md b/Software/LMSourceCode/ImageProcessing/ImageAnalysis/REFACTORING_PLAN.md
deleted file mode 100644
index a491970f..00000000
--- a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/REFACTORING_PLAN.md
+++ /dev/null
@@ -1,164 +0,0 @@
-# OpenCV Image Analyzer Refactoring Plan
-
-## Overview
-The `OpenCVImageAnalyzer` class has grown too large and violates the Single Responsibility Principle. The `CalculateOpticalFlow` method is particularly long and complex. This document outlines a comprehensive refactoring plan to improve code organization, maintainability, and testability.
-
-## Current Issues Identified
-
-### 🔴 High Priority Issues
-- **Large Class**: `OpenCVImageAnalyzer` has too many responsibilities (detection, preprocessing, confidence calculation, optical flow)
-- **Long Method**: `CalculateOpticalFlow` is ~80 lines with complex logic and multiple fallback mechanisms
-- **Mixed Concerns**: Single class handles image preprocessing, circle detection, confidence calculation, and movement analysis
-- **Static Method Opportunities**: Several methods don't use instance variables and can be made static
-- **Code Duplication**: Similar error handling patterns repeated across methods
-
-### 🟡 Medium Priority Issues
-- **Magic Numbers**: Some hardcoded values scattered throughout the code
-- **Configuration Management**: Hough parameters managed directly as member variables
-- **Testing Challenges**: Large class makes unit testing individual components difficult
-
-## Refactoring Plan
-
-### Phase 1: Extract Utility Classes ✅ COMPLETED
-- [ ] **Create `OpticalFlowCalculator`** - Extract optical flow logic
- - [ ] `CalculateFlow()` - Main optical flow calculation
- - [ ] `CalculateMovementMagnitude()` - Movement magnitude calculation
- - [ ] `CalculateLucasKanadeFlow()` - Lucas-Kanade implementation
- - [ ] `CalculateFrameDifferenceFlow()` - Fallback method
- - [ ] Add proper error handling and logging
-
-- [ ] **Create `ImagePreprocessor`** - Extract image preprocessing logic
- - [ ] `PreprocessForDetection()` - Main preprocessing pipeline
- - [ ] `IsValidBallPosition()` - Position validation
- - [ ] `ConvertToGrayscale()` - Color space conversion
- - [ ] `ApplyNoiseReduction()` - Gaussian blur application
-
-- [ ] **Create `HoughCircleDetector`** - Extract circle detection logic
- - [ ] `DetectCircles()` - Hough circle detection
- - [ ] `SelectBestCandidate()` - Candidate selection logic
- - [ ] `ValidateParameters()` - Parameter validation
- - [ ] `ConvertCircleToBallPosition()` - Data conversion
-
-- [ ] **Create `ConfidenceCalculator`** - Extract confidence calculation logic
- - [ ] `CalculateConfidence()` - Main confidence calculation
- - [ ] `CalculateRadiusConfidence()` - Radius-based confidence
- - [ ] `CalculatePositionConfidence()` - Position-based confidence
- - [ ] `IsBallWithinBounds()` - Bounds checking
-
-### Phase 2: Refactor Main Analyzer Class
-- [ ] **Create `OpenCVImageAnalyzerRefactored`** - Smaller orchestrator class
- - [ ] Replace direct implementation with utility class calls
- - [ ] Maintain same public interface for compatibility
- - [ ] Simplify configuration management using parameter structs
- - [ ] Reduce class size from ~400 lines to ~150 lines
-
-- [ ] **Update Configuration Management**
- - [ ] Replace individual member variables with `HoughParameters` struct
- - [ ] Replace individual member variables with `ConfidenceParameters` struct
- - [ ] Add `SetConfidenceParameters()` method for advanced configuration
-
-- [ ] **Simplify Core Methods**
- - [ ] `AnalyzeTeedBall()` - Use `DetectBallsInImage()` helper
- - [ ] `DetectMovement()` - Use `OpticalFlowCalculator`
- - [ ] `AnalyzeBallFlight()` - Use utility classes for detection and confidence
- - [ ] `DetectBallReset()` - Simplified using new architecture
-
-### Phase 3: Update Build System and Tests
-- [ ] **Update CMakeLists.txt**
- - [ ] Add new utility class source files
- - [ ] Ensure proper header dependencies
- - [ ] Maintain backward compatibility
-
-- [ ] **Update Tests**
- - [ ] Create unit tests for each utility class
- - [ ] Update integration tests to use refactored analyzer
- - [ ] Add specific tests for error handling in utility classes
- - [ ] Verify all existing tests still pass
-
-- [ ] **Update Documentation**
- - [ ] Update class documentation to reflect new architecture
- - [ ] Add utility class documentation
- - [ ] Update usage examples if needed
-
-### Phase 4: Migration and Cleanup
-- [ ] **Gradual Migration**
- - [ ] Keep original `OpenCVImageAnalyzer` as deprecated
- - [ ] Add compatibility layer for existing code
- - [ ] Update factory to use refactored version by default
- - [ ] Add deprecation warnings to old class
-
-- [ ] **Validation and Performance Testing**
- - [ ] Run full test suite to ensure functionality preserved
- - [ ] Performance benchmarks to ensure no regression
- - [ ] Memory usage analysis of new architecture
- - [ ] Validate error handling improvements
-
-- [ ] **Final Cleanup**
- - [ ] Remove deprecated code after migration period
- - [ ] Clean up unused includes and dependencies
- - [ ] Final code review and formatting
-
-## Benefits of Refactoring
-
-### 🎯 Immediate Benefits
-- **Single Responsibility**: Each class has one clear purpose
-- **Easier Testing**: Utility classes can be tested independently
-- **Better Error Handling**: Centralized error handling in each utility
-- **Reduced Complexity**: Main analyzer becomes a simple orchestrator
-
-### 🚀 Long-term Benefits
-- **Maintainability**: Changes to specific algorithms isolated to relevant classes
-- **Extensibility**: Easy to add new detection algorithms or preprocessing steps
-- **Reusability**: Utility classes can be used by other analyzers (e.g., ML-based)
-- **Performance**: Easier to optimize individual components
-
-## Code Quality Improvements
-
-### 📏 Metrics Expected
-- **Class Size**: Reduce main analyzer from ~400 lines to ~150 lines
-- **Method Length**: Largest method reduced from ~80 lines to ~20 lines
-- **Cyclomatic Complexity**: Reduce complexity of individual methods
-- **Test Coverage**: Increase from integration-only to unit + integration testing
-
-### 🛡️ Error Handling
-- **Centralized Logging**: Each utility class has consistent error logging
-- **Robust Fallbacks**: Optical flow calculator has multiple fallback strategies
-- **Input Validation**: Parameter validation in each utility class
-- **Exception Safety**: Proper exception handling throughout
-
-## Migration Timeline
-
-### Week 1: Utility Classes ✅ COMPLETED
-- [x] Implement and test all utility classes
-- [x] Ensure proper error handling and logging
-- [x] Create unit tests for utility classes
-
-### Week 2: Refactored Analyzer
-- [ ] Implement refactored analyzer using utility classes
-- [ ] Update build system and dependencies
-- [ ] Ensure all existing tests pass
-
-### Week 3: Documentation and Testing
-- [ ] Complete documentation updates
-- [ ] Performance validation
-- [ ] Integration testing with full system
-
-### Week 4: Migration and Cleanup
-- [ ] Gradual migration of dependent code
-- [ ] Final cleanup and code review
-- [ ] Remove deprecated code
-
-## Success Criteria
-
-- [ ] All existing tests pass without modification
-- [ ] No performance regression (< 5% impact)
-- [ ] Main analyzer class reduced to < 200 lines
-- [ ] Each utility class has > 90% test coverage
-- [ ] Code review approval from team
-- [ ] Documentation updated and complete
-
----
-
-**Status**: Phase 1 Complete ✅
-**Next Step**: Begin Phase 2 - Refactor Main Analyzer Class
-**Last Updated**: 2025-07-07
diff --git a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/application/image_analysis_service.hpp b/Software/LMSourceCode/ImageProcessing/ImageAnalysis/application/image_analysis_service.hpp
deleted file mode 100644
index 19852d91..00000000
--- a/Software/LMSourceCode/ImageProcessing/ImageAnalysis/application/image_analysis_service.hpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2022-2025, Verdant Consultants, LLC.
- */
-
-/**
- * @file image_analysis_service.hpp
- * @brief Application service for image analysis operations
- *
- * High-level service that orchestrates image analysis operations,
- * manages analyzer selection, and handles cross-cutting concerns
- * like logging, caching, and error handling.
- */
-
-#pragma once
-
-#include "../domain/interfaces.hpp"
-#include "../domain/analysis_results.hpp"
-#include
-#include