From d182ed4cefe55ab76d36709260ce0739302e99ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Sep 2025 23:40:23 +0000 Subject: [PATCH 1/2] Initial plan From f632b42269eb40ea6298536a603325e310cfce99 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Sep 2025 23:45:10 +0000 Subject: [PATCH 2/2] Implement TouchDesigner random number generator with configurable parameters Co-authored-by: Tombkn <178416194+Tombkn@users.noreply.github.com> --- EXAMPLES.md | 76 +++++++++++++++++ README.md | 53 +++++++++++- TOUCHDESIGNER_SETUP.md | 103 +++++++++++++++++++++++ demo.py | 138 +++++++++++++++++++++++++++++++ random_number_generator.py | 95 ++++++++++++++++++++++ test_random_generator.py | 158 ++++++++++++++++++++++++++++++++++++ touchdesigner_dat_script.py | 33 ++++++++ 7 files changed, 654 insertions(+), 2 deletions(-) create mode 100644 EXAMPLES.md create mode 100644 TOUCHDESIGNER_SETUP.md create mode 100644 demo.py create mode 100644 random_number_generator.py create mode 100644 test_random_generator.py create mode 100644 touchdesigner_dat_script.py diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 0000000..c4751cf --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,76 @@ +# Example Parameter Configurations + +This file contains example parameter configurations for different use cases of the TouchDesigner Random Number Generator. + +## Configuration Examples + +### Basic Integer-like Numbers (0-100) +``` +Min Range: 0.0 +Max Range: 100.0 +Number of Rows: 10 +``` +Example Output: 23.45, 67.89, 12.34, 89.01, 45.67 + +### Percentage Values (0-1) +``` +Min Range: 0.0 +Max Range: 1.0 +Number of Rows: 5 +``` +Example Output: 0.23, 0.78, 0.45, 0.91, 0.12 + +### Temperature Range (Celsius) +``` +Min Range: -30.0 +Max Range: 40.0 +Number of Rows: 7 +``` +Example Output: -12.45, 23.78, 35.92, -5.14, 18.67 + +### Audio Level Simulation (dB) +``` +Min Range: -60.0 +Max Range: 0.0 +Number of Rows: 8 +``` +Example Output: -45.23, -12.78, -38.45, -5.91, -52.12 + +### Small Decimal Range +``` +Min Range: 0.1 +Max Range: 0.9 +Number of Rows: 6 +``` +Example Output: 0.34, 0.78, 0.23, 0.65, 0.41 + +### Large Number Range +``` +Min Range: 1000.0 +Max Range: 10000.0 +Number of Rows: 4 +``` +Example Output: 3456.78, 7891.23, 2345.67, 8901.45 + +## Parameter Guidelines + +### Min Range and Max Range +- Min Range must be less than Max Range +- Can be positive, negative, or mixed +- Supports decimal values +- No specific limits on range size + +### Number of Rows +- Must be a positive integer (greater than 0) +- Determines how many random numbers are generated +- Each number appears in its own row in the DAT table +- Typical values: 1-100 (depending on use case) + +## Common Use Cases + +1. **Animation Controllers**: Generate random values for position, rotation, or scale +2. **Audio Visualization**: Create random amplitude or frequency values +3. **Color Generation**: Generate RGB component values (0.0-1.0) +4. **Particle Systems**: Random positions, velocities, or lifetimes +5. **Generative Art**: Random parameters for artistic algorithms +6. **Testing/Debugging**: Generate test data with known ranges \ No newline at end of file diff --git a/README.md b/README.md index 9ca3ca5..403c74d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,51 @@ -# randomNumberTox -This TouchDesigner .tox contains a DAT Script that allows you to configure a min and max range, as well as the number of rows. Each time it is executed, the script generates random numbers within the defined range. The output values are written into a DAT table, with each row containing one random number. +# TouchDesigner Random Number Generator + +This TouchDesigner .tox contains a DAT Script that allows you to configure a min and max range, as well as the number of rows. Each time it is executed, the script generates random numbers within the defined range. The output values are written into a DAT table, with each row containing one random number rounded to two decimal places. + +## Features + +- **Configurable Range**: Set minimum and maximum values for random number generation +- **Variable Output Size**: Configure how many random numbers to generate (number of rows) +- **Precision Control**: All numbers are automatically rounded to 2 decimal places +- **Error Handling**: Validates parameters and provides error messages for invalid inputs +- **TouchDesigner Integration**: Designed specifically for TouchDesigner DAT operators + +## Files + +- `touchdesigner_dat_script.py` - Main script to copy into TouchDesigner DAT operator +- `random_number_generator.py` - Standalone Python version for testing and development +- `TOUCHDESIGNER_SETUP.md` - Detailed setup instructions for TouchDesigner +- `demo.py` - Demonstration script showing functionality +- `test_random_generator.py` - Unit tests for validation + +## Quick Start + +1. See `TOUCHDESIGNER_SETUP.md` for detailed TouchDesigner setup instructions +2. Copy the code from `touchdesigner_dat_script.py` into a Text DAT in TouchDesigner +3. Set up component parameters for Min Range, Max Range, and Number of Rows +4. Execute the script to generate random numbers + +## Example Output + +With Min Range: 10.0, Max Range: 50.0, Number of Rows: 5: + +``` +Random Numbers +23.45 +41.78 +15.92 +38.14 +29.67 +``` + +## Testing + +Run the test suite: +```bash +python3 test_random_generator.py +``` + +Run the demonstration: +```bash +python3 demo.py +``` diff --git a/TOUCHDESIGNER_SETUP.md b/TOUCHDESIGNER_SETUP.md new file mode 100644 index 0000000..8317189 --- /dev/null +++ b/TOUCHDESIGNER_SETUP.md @@ -0,0 +1,103 @@ +# TouchDesigner Random Number Generator Setup Guide + +## Overview +This TouchDesigner .tox component generates random numbers within a configurable range and outputs them to a DAT table. Each row contains one random number rounded to two decimal places. + +## Setup Instructions + +### 1. Create the TouchDesigner Component + +1. Open TouchDesigner +2. Create a new Component (right-click > Operators > Component) +3. Enter the component and set up the following structure: + +### 2. Add Parameters to the Component + +In the Component's parameters, add the following custom parameters: + +**Page: Random Generator** +- **Minrange** (Float) + - Name: `Minrange` + - Label: `Min Range` + - Default: `0.0` + - Description: Minimum value for random number generation + +- **Maxrange** (Float) + - Name: `Maxrange` + - Label: `Max Range` + - Default: `100.0` + - Description: Maximum value for random number generation + +- **Numrows** (Integer) + - Name: `Numrows` + - Label: `Number of Rows` + - Default: `10` + - Description: Number of random numbers to generate + +- **Generate** (Pulse) + - Name: `Generate` + - Label: `Generate Numbers` + - Description: Execute random number generation + +### 3. Create the DAT Network + +Inside the component, create the following operators: + +1. **Text DAT** (name it `randomNumbers`) + - This will hold the generated random numbers + - Copy the code from `touchdesigner_dat_script.py` into this DAT + +2. **Execute DAT** (name it `executeGenerator`) + - Set the Execute parameter to monitor `parent().par.Generate` + - In the Execute script, add: `op('randomNumbers').run()` + +### 4. Script Setup + +Copy the contents of `touchdesigner_dat_script.py` into the Text DAT operator. This script will: + +- Read the component's parameters (Min Range, Max Range, Number of Rows) +- Generate random numbers within the specified range +- Round all numbers to 2 decimal places +- Populate the DAT table with one number per row + +### 5. Usage + +1. Set your desired **Min Range** and **Max Range** values +2. Set the **Number of Rows** to specify how many random numbers to generate +3. Click the **Generate Numbers** button to execute the script +4. View the results in the `randomNumbers` DAT table + +## Features + +- **Configurable Range**: Set minimum and maximum values for random number generation +- **Variable Output Size**: Configure how many random numbers to generate +- **Precision Control**: All numbers are automatically rounded to 2 decimal places +- **Error Handling**: Validates parameters and provides error messages for invalid inputs +- **Real-time Generation**: Execute anytime by clicking the Generate button + +## Example Output + +With Min Range: 10.0, Max Range: 50.0, Number of Rows: 5, the output might look like: + +``` +Random Numbers +23.45 +41.78 +15.92 +38.14 +29.67 +``` + +## File Structure + +- `touchdesigner_dat_script.py` - The main script to copy into TouchDesigner DAT +- `random_number_generator.py` - Standalone Python version for testing +- `TOUCHDESIGNER_SETUP.md` - This setup guide +- `README.md` - General project information + +## Notes + +- The script uses Python's `random.uniform()` function for floating-point number generation +- Parameters are automatically read from the component's custom parameters +- The DAT table is cleared each time the script runs to ensure fresh output +- Error messages are displayed in the DAT table if invalid parameters are provided \ No newline at end of file diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..58cb09b --- /dev/null +++ b/demo.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +""" +Demonstration script for the TouchDesigner Random Number Generator. +This shows the functionality without requiring TouchDesigner. +""" + +import random + +class SimulatedDAT: + """Simulates TouchDesigner DAT functionality for demonstration""" + + def __init__(self): + self.table_data = [] + self.headers = [] + + def clear(self): + """Clear all data from the table""" + self.table_data = [] + self.headers = [] + + def appendCol(self, col_headers): + """Add column headers""" + self.headers.extend(col_headers) + + def appendRow(self, row_data): + """Add a row of data""" + self.table_data.append(row_data) + + def display(self): + """Display the table contents""" + if self.headers: + print(f"{'='*20}") + for header in self.headers: + print(f"{header:>15}") + print(f"{'='*20}") + + for row in self.table_data: + for item in row: + print(f"{item:>15}") + + if self.table_data: + print(f"{'='*20}") + print(f"Total rows: {len(self.table_data)}") + +def generate_random_numbers_demo(min_range, max_range, num_rows): + """ + Demonstrate the random number generation functionality. + + Args: + min_range (float): Minimum value for random numbers + max_range (float): Maximum value for random numbers + num_rows (int): Number of random numbers to generate + """ + print(f"\nGenerating {num_rows} random numbers between {min_range} and {max_range}") + print(f"All numbers will be rounded to 2 decimal places") + + # Create simulated DAT table + me = SimulatedDAT() + + # Validate parameters + if min_range >= max_range: + print("Error: min_range must be less than max_range") + me.clear() + me.appendCol(['Error']) + me.appendRow(['Invalid range parameters']) + me.display() + return + + if num_rows <= 0: + print("Error: num_rows must be greater than 0") + me.clear() + me.appendCol(['Error']) + me.appendRow(['Invalid number of rows']) + me.display() + return + + # Clear and set up the table + me.clear() + me.appendCol(['Random Numbers']) + + # Generate random numbers + generated_numbers = [] + for i in range(num_rows): + # Generate random number within range + random_num = random.uniform(min_range, max_range) + # Round to 2 decimal places + rounded_num = round(random_num, 2) + generated_numbers.append(rounded_num) + + # Add to DAT table + me.appendRow([str(rounded_num)]) + + # Display results + me.display() + + # Show statistics + print(f"\nStatistics:") + print(f"Average: {round(sum(generated_numbers) / len(generated_numbers), 2)}") + print(f"Minimum: {min(generated_numbers)}") + print(f"Maximum: {max(generated_numbers)}") + + return generated_numbers + +def main(): + """Run demonstration with various parameter sets""" + print("TouchDesigner Random Number Generator - Demonstration") + print("=" * 60) + + # Test cases to demonstrate functionality + test_cases = [ + (0.0, 100.0, 10), # Basic case + (-50.0, 50.0, 5), # Negative to positive range + (10.5, 20.5, 8), # Decimal range + (0.1, 0.9, 6), # Small decimal range + (1000.0, 2000.0, 4), # Large numbers + ] + + for i, (min_range, max_range, num_rows) in enumerate(test_cases, 1): + print(f"\n--- Test Case {i} ---") + generate_random_numbers_demo(min_range, max_range, num_rows) + + # Demonstrate error handling + print(f"\n--- Error Handling Demonstration ---") + print("\nTesting invalid range (min >= max):") + generate_random_numbers_demo(100.0, 50.0, 5) + + print("\nTesting invalid number of rows (0):") + generate_random_numbers_demo(0.0, 100.0, 0) + + print("\n" + "=" * 60) + print("Demonstration complete!") + print("\nTo use in TouchDesigner:") + print("1. Copy the code from 'touchdesigner_dat_script.py' into a Text DAT") + print("2. Set up component parameters as described in TOUCHDESIGNER_SETUP.md") + print("3. Execute the script to generate random numbers") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/random_number_generator.py b/random_number_generator.py new file mode 100644 index 0000000..5b80ac6 --- /dev/null +++ b/random_number_generator.py @@ -0,0 +1,95 @@ +""" +TouchDesigner DAT Script for Random Number Generation + +This script generates random numbers within a configurable range and outputs +them to a DAT table with each row containing one random number rounded to +two decimal places. + +Parameters to configure: +- min_range: Minimum value for random number generation +- max_range: Maximum value for random number generation +- num_rows: Number of random numbers to generate + +Usage: +1. Place this script in a DAT operator in TouchDesigner +2. Configure the parameters below +3. Execute the script to generate random numbers +4. The output will be written to the DAT table +""" + +import random + +# Configuration Parameters +# These would typically be exposed as TouchDesigner parameters +min_range = 0.0 # Minimum value for random numbers +max_range = 100.0 # Maximum value for random numbers +num_rows = 10 # Number of random numbers to generate + +def generate_random_numbers(): + """ + Generate random numbers within the specified range and write to DAT table. + + Returns: + list: List of generated random numbers rounded to 2 decimal places + """ + # Clear the DAT table first + me.clear() + + # Set table headers + me.appendCol(['Random Numbers']) + + # Generate random numbers + random_numbers = [] + for i in range(num_rows): + # Generate random number within range + random_num = random.uniform(min_range, max_range) + # Round to 2 decimal places + rounded_num = round(random_num, 2) + random_numbers.append(rounded_num) + + # Add to DAT table + me.appendRow([str(rounded_num)]) + + return random_numbers + +def get_parameters(): + """ + Get parameters from TouchDesigner parent component. + This function would be used to read parameter values in actual TouchDesigner environment. + """ + # In actual TouchDesigner, these would be: + # min_range = parent().par.Minrange.eval() + # max_range = parent().par.Maxrange.eval() + # num_rows = parent().par.Numrows.eval() + + global min_range, max_range, num_rows + + # For now, return the configured values + return min_range, max_range, num_rows + +def main(): + """ + Main execution function for the TouchDesigner DAT script. + """ + # Get current parameters + global min_range, max_range, num_rows + min_range, max_range, num_rows = get_parameters() + + # Validate parameters + if min_range >= max_range: + print("Error: min_range must be less than max_range") + return + + if num_rows <= 0: + print("Error: num_rows must be greater than 0") + return + + # Generate and display random numbers + random_numbers = generate_random_numbers() + + print(f"Generated {len(random_numbers)} random numbers between {min_range} and {max_range}") + print(f"Numbers: {random_numbers}") + +# Execute the main function when script is run +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test_random_generator.py b/test_random_generator.py new file mode 100644 index 0000000..4bc8e12 --- /dev/null +++ b/test_random_generator.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +""" +Test script for the random number generator functionality. +This tests the core logic without TouchDesigner dependencies. +""" + +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import random +import unittest +from unittest.mock import Mock + +class MockDAT: + """Mock DAT object to simulate TouchDesigner DAT functionality""" + def __init__(self): + self.data = [] + self.cols = [] + + def clear(self): + self.data = [] + self.cols = [] + + def appendCol(self, col_data): + self.cols.extend(col_data) + + def appendRow(self, row_data): + self.data.append(row_data) + + def get_data(self): + return self.data + + def get_cols(self): + return self.cols + +class TestRandomNumberGenerator(unittest.TestCase): + """Test cases for random number generator functionality""" + + def setUp(self): + """Set up test fixtures""" + self.mock_dat = MockDAT() + # Set random seed for predictable testing + random.seed(42) + + def test_generate_random_numbers_basic(self): + """Test basic random number generation""" + min_range = 0.0 + max_range = 100.0 + num_rows = 5 + + # Simulate the core logic + self.mock_dat.clear() + self.mock_dat.appendCol(['Random Numbers']) + + generated_numbers = [] + for i in range(num_rows): + random_num = random.uniform(min_range, max_range) + rounded_num = round(random_num, 2) + generated_numbers.append(rounded_num) + self.mock_dat.appendRow([str(rounded_num)]) + + # Verify results + self.assertEqual(len(generated_numbers), num_rows) + self.assertEqual(len(self.mock_dat.get_data()), num_rows) + self.assertEqual(self.mock_dat.get_cols(), ['Random Numbers']) + + # Verify all numbers are within range + for num in generated_numbers: + self.assertGreaterEqual(num, min_range) + self.assertLessEqual(num, max_range) + + def test_rounding_to_two_decimal_places(self): + """Test that numbers are properly rounded to 2 decimal places""" + min_range = 0.0 + max_range = 1.0 + num_rows = 10 + + generated_numbers = [] + for i in range(num_rows): + random_num = random.uniform(min_range, max_range) + rounded_num = round(random_num, 2) + generated_numbers.append(rounded_num) + + # Verify all numbers have at most 2 decimal places + for num in generated_numbers: + decimal_places = len(str(num).split('.')[-1]) if '.' in str(num) else 0 + self.assertLessEqual(decimal_places, 2) + + def test_parameter_validation(self): + """Test parameter validation logic""" + # Test invalid range + min_range = 100.0 + max_range = 50.0 + self.assertGreaterEqual(min_range, max_range) # Should be invalid + + # Test valid range + min_range = 10.0 + max_range = 50.0 + self.assertLess(min_range, max_range) # Should be valid + + # Test invalid number of rows + num_rows = 0 + self.assertLessEqual(num_rows, 0) # Should be invalid + + # Test valid number of rows + num_rows = 5 + self.assertGreater(num_rows, 0) # Should be valid + + def test_different_ranges(self): + """Test generation with different range values""" + test_cases = [ + (0.0, 10.0, 5), + (-50.0, 50.0, 3), + (100.0, 1000.0, 2), + (0.1, 0.9, 4) + ] + + for min_range, max_range, num_rows in test_cases: + with self.subTest(min_range=min_range, max_range=max_range, num_rows=num_rows): + generated_numbers = [] + for i in range(num_rows): + random_num = random.uniform(min_range, max_range) + rounded_num = round(random_num, 2) + generated_numbers.append(rounded_num) + + self.assertEqual(len(generated_numbers), num_rows) + for num in generated_numbers: + self.assertGreaterEqual(num, min_range) + self.assertLessEqual(num, max_range) + + def test_dat_table_structure(self): + """Test that DAT table is structured correctly""" + self.mock_dat.clear() + self.mock_dat.appendCol(['Random Numbers']) + + # Add some test data + test_numbers = [1.23, 4.56, 7.89] + for num in test_numbers: + self.mock_dat.appendRow([str(num)]) + + # Verify structure + self.assertEqual(self.mock_dat.get_cols(), ['Random Numbers']) + self.assertEqual(len(self.mock_dat.get_data()), len(test_numbers)) + + # Verify data content + for i, expected_num in enumerate(test_numbers): + self.assertEqual(self.mock_dat.get_data()[i], [str(expected_num)]) + +def run_tests(): + """Run all tests and display results""" + print("Running Random Number Generator Tests...") + print("=" * 50) + + unittest.main(argv=[''], exit=False, verbosity=2) + +if __name__ == "__main__": + run_tests() \ No newline at end of file diff --git a/touchdesigner_dat_script.py b/touchdesigner_dat_script.py new file mode 100644 index 0000000..342c4fe --- /dev/null +++ b/touchdesigner_dat_script.py @@ -0,0 +1,33 @@ +# TouchDesigner DAT Script - Random Number Generator +# Place this code directly in a DAT operator (Text DAT or Script DAT) + +import random + +# Get parameters from parent component +min_range = parent().par.Minrange.eval() if hasattr(parent(), 'par') and hasattr(parent().par, 'Minrange') else 0.0 +max_range = parent().par.Maxrange.eval() if hasattr(parent(), 'par') and hasattr(parent().par, 'Maxrange') else 100.0 +num_rows = int(parent().par.Numrows.eval()) if hasattr(parent(), 'par') and hasattr(parent().par, 'Numrows') else 10 + +# Clear the DAT table +me.clear() + +# Set table header +me.appendCol(['Random Numbers']) + +# Validate parameters +if min_range < max_range and num_rows > 0: + # Generate random numbers and populate DAT table + for i in range(num_rows): + # Generate random number within range + random_num = random.uniform(min_range, max_range) + # Round to 2 decimal places + rounded_num = round(random_num, 2) + # Add to DAT table + me.appendRow([str(rounded_num)]) +else: + # Add error message to table + me.appendRow(['Error: Invalid parameters']) + if min_range >= max_range: + me.appendRow(['Min range must be less than max range']) + if num_rows <= 0: + me.appendRow(['Number of rows must be greater than 0']) \ No newline at end of file