Initial commit

This commit is contained in:
2024-04-08 14:09:47 +01:00
commit 7b3ba10877
51 changed files with 6244 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
[codestyle]
indentation = True
edge_line = True
edge_line_columns = 79
[main]
version = 0.2.0

View File

@@ -0,0 +1,6 @@
[encoding]
text_encoding = utf-8
[main]
version = 0.2.0

View File

@@ -0,0 +1,7 @@
[vcs]
use_version_control = False
version_control_system =
[main]
version = 0.2.0

View File

@@ -0,0 +1,12 @@
[workspace]
restore_data_on_startup = True
save_data_on_exit = True
save_history = True
save_non_project_files = False
project_type = 'empty-project-type'
recent_files = ['model_gen\\main.py', 'setup.py', 'requirements.txt', 'model_gen\\translate_braille_2_scad.py', 'model_gen\\translate_msg_2_braille.py', 'model_gen\\translate_msg_2_braille_v2a.py', 'model_gen\\export_3d.py', '..\\xmas_turkey.py', '..\\monitor_stand_eng_anal.py', '..\\finance_v3.py', '..\\Fractal_Fortune_Teller\\setup.py']
[main]
version = 0.2.0
recent_files = []

View File

@@ -0,0 +1,8 @@
[codestyle]
indentation = True
edge_line = True
edge_line_columns = 79
[main]
version = 0.2.0

View File

@@ -0,0 +1,5 @@
[codestyle]
indentation = True
edge_line = True
edge_line_columns = 79

View File

@@ -0,0 +1,3 @@
[encoding]
text_encoding = utf-8

View File

@@ -0,0 +1,4 @@
[vcs]
use_version_control = False
version_control_system =

View File

@@ -0,0 +1,6 @@
[workspace]
restore_data_on_startup = True
save_data_on_exit = True
save_history = True
save_non_project_files = False

View File

@@ -0,0 +1,6 @@
[encoding]
text_encoding = utf-8
[main]
version = 0.2.0

View File

@@ -0,0 +1,7 @@
[vcs]
use_version_control = False
version_control_system =
[main]
version = 0.2.0

View File

@@ -0,0 +1,12 @@
[workspace]
restore_data_on_startup = True
save_data_on_exit = True
save_history = True
save_non_project_files = False
project_type = 'empty-project-type'
recent_files = ['model_gen\\main.py', 'setup.py', 'requirements.txt', 'model_gen\\translate_braille_2_scad.py', 'model_gen\\translate_msg_2_braille.py', 'model_gen\\translate_msg_2_braille_v2a.py', 'model_gen\\export_3d.py', '..\\xmas_turkey.py', '..\\monitor_stand_eng_anal.py', '..\\finance_v3.py', '..\\Fractal_Fortune_Teller\\setup.py']
[main]
version = 0.2.0
recent_files = []

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Edward Middleton-Smith
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
Makefile Normal file
View File

@@ -0,0 +1,7 @@
init:
pip install -r requirements.txt
test:
py.test module_tests
.PHONY: init test

8
README.rst Normal file
View File

@@ -0,0 +1,8 @@
Braille Model Generator
=====================================================================
Project details
Braille Model Generator is a python module built on openpyscad for translating a passage of text into Braille and export it as a text (.txt), OpenSCAD (.scad), stereolithography (.stl), and portable network graphic (.png) types.
The method of Braille translation can be varied to correspond to various chapters in the Standard English Braille pdf in the docs.
GitHub repository

Binary file not shown.

2252
model_gen/Braille.txt Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,928 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 27 12:33:59 2023
@author: Edward Middleton-Smith
Argument Validation
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
from typing import Optional
def error_msg_str(method, v_name, v, v_type, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# return error message string for output of invalid argument / attribute to user
# ARGUMENTS
# str method - name of parent method which calls this function
# str arg_name - name of argument throwing error
# ? v - erroneous variable
# str v_type - desired / expected variable type
# str arg_type - e.g. argument, attribute
# bool suppress_errors - should outputs not be raised as errors?
# bool suppress_console_outputs
# ARGUMENT VALIDATION
my_f = 'error_msg_str'
# suppress_errors
if not val_bool(suppress_errors, 'suppress_errors', my_f):
error_msg = error_msg_str(my_f, 'suppress_errors', suppress_errors, "<class 'bool'>")
raise ValueError(error_msg)
# suppress_console_outputs
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
error_msg = error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors)
if suppress_errors:
print(error_msg)
return error_msg
else:
raise ValueError(error_msg)
# method
if not val_str(method, 'method', my_f, suppress_errors=suppress_errors, suppress_console_outputs=suppress_console_outputs):
error_msg = error_msg_str(my_f, 'method', method, "<class 'str'>", suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return error_msg
else:
raise ValueError(error_msg)
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, -1, -1, suppress_errors, suppress_console_outputs):
error_msg = error_msg_str(my_f, 'v_name', v_name, "<class 'str'>", suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return error_msg
else:
raise ValueError(error_msg)
# v_type
if not val_str(v_type, 'v_type', my_f, -1, -1, suppress_errors, suppress_console_outputs):
error_msg = error_msg_str(my_f, 'v_type', v_type, "<class 'str'>", suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return error_msg
else:
raise ValueError(error_msg)
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, -1, -1, suppress_errors, suppress_console_outputs):
error_msg = error_msg_str(my_f, 'v_arg_type', v_arg_type, "<class 'str'>", suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return error_msg
else:
raise ValueError(error_msg)
# RETURNS
return f"Invalid {method} {v_type} {v_arg_type} {v_name}. Type = {str(type(v))}. Value = {v}"
def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that myinput is of type bool
# ARGUMENTS
# bool (hopefully) myinput
# str v_name
# str method
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
# validate bool inputs first
v_type = "<class 'bool'>"
my_f = 'val_bool'
if str(type(suppress_errors)) != v_type:
raise ValueError(error_msg_str(my_f, 'suppress_errors', suppress_errors, v_type))
if str(type(suppress_console_outputs)) != v_type:
error_msg = error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, v_type, suppress_errors)
if suppress_errors:
print(error_msg)
return False
raise ValueError(error_msg)
v_type = "<class 'str'>"
# method
valid = True
if str(type(method)) != v_type:
valid = False
else:
if len(method) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'method', method, v_type, suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
my_f = method + '.' + my_f
# v_name
valid = True
if str(type(v_name)) != v_type:
valid = False
else:
if len(v_name) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'v_name', v_name, v_type, suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# v_arg_type
valid = True
if str(type(v_arg_type)) != v_type:
valid = False
else:
if len(v_arg_type) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'v_arg_type', v_arg_type, v_type, suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
else:
raise ValueError(error_msg)
# v_input
v_type = "<class 'bool'>"
if (str(type(v_input)) != v_type):
error_msg = error_msg_str(method, v_name, v_input, v_type, suppress_errors, suppress_console_outputs)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# RETURNS
return True
def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is of type str
# ARGUMENTS
# str (hopefully) v_input
# str v_name
# str method
# optional int min_len
# optional int max_len
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_str'
v_type = "<class 'str'>"
# suppress_errors
val_bool(suppress_errors, 'suppress_errors', my_f)
# suppress_console_outputs
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
valid = True
if str(type(method)) != v_type:
valid = False
else:
if len(method) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'method', method, v_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
my_f = method + '.' + my_f
# v_name
valid = True
if str(type(v_name)) != v_type:
valid = False
else:
if len(v_name) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'v_name', v_name, v_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# v_arg_type
valid = True
if str(type(v_arg_type)) != v_type:
valid = False
else:
if len(v_arg_type) < 1:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'v_arg_type', v_arg_type, v_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# min_len
v_type = "<class 'int'>"
if str(type(min_len)) != v_type:
error_msg = error_msg_str(my_f, 'min_len', min_len, v_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# max_len
v_type = "<class 'int'>"
valid = True
if str(type(max_len)) != v_type:
valid = False
else:
if max_len != -1 and max_len < min_len:
valid = False
if not valid:
error_msg = error_msg_str(my_f, 'max_len', max_len, v_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# v_input
# VARIABLE INSTANTIATION
v_type = "<class 'str'>"
valid = True
# METHODS
if str(type(v_input)) != v_type:
valid = False
else:
L = len(v_input)
if min_len != -1 and L < min_len:
valid = False
print(f"Minimum str length {min_len} not met.")
if max_len != -1 and L > max_len:
print(f"Maximum str length {max_len} not met.")
valid = False
if not valid:
error_msg = error_msg_str(method, v_name, v_input, v_type, suppress_errors, suppress_console_outputs, v_arg_type)
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# RETURNS
return True
# def val_none(v_input, v_name, method, v_arg_type = 'argument', suppress_errors = False, suppress_console_outputs = False):
# # FUNCTION
# # evaluate if v_input is None
# # ARGUMENTS
# # ARGUMENT VALIDATION
# # VARIABLE INSTANTIATION
# # METHODS
# # RETURNS
def val_int(v_input, v_name, method, v_min: Optional[int] = None, v_max: Optional[int] = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that myinput is of type int, and if not None, limited by v_min and v_max
# ARGUMENTS
# int (hopefully) myinput
# str v_name
# str method
# optional int v_min
# optional int v_max
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_int'
# suppress_errors
val_bool(suppress_errors, 'suppress_errors', my_f)
# suppress_console_outputs
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_min
if (v_min != None):
if not val_int(v_min, 'v_min', my_f, None, None, suppress_errors, suppress_console_outputs):
return False
# v_max
if (v_max != None):
if not val_int(v_max, 'v_max', my_f, None, None, suppress_errors, suppress_console_outputs):
return False
# v_input
# VARIABLE INSTANTIATION
mytype = "<class 'int'>" # str(type(myinput))
error_msg = error_msg_str(method, v_name, v_input, mytype, suppress_errors, suppress_console_outputs, v_arg_type)
# METHODS
if not mytype == str(type(v_input)):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
if (v_min != None and v_max != None):
if (v_min > v_max):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
return False
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
if (v_min != None):
if (v_input < v_min):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nValue less than minimum {v_min}.")
return False
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
if (v_max != None):
if (v_input > v_max):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nValue greater than maximum {v_max}.")
return False
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
# RETURNS
return True
def val_float(v_input, v_name, method, v_min = None, v_max = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is of type float, and if not None, limited by v_min and v_max
# ARGUMENTS
# float (hopefully) v_input
# str v_name
# str method
# optional float v_min
# optional float v_max
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_float'
# suppress_errors
val_bool(suppress_errors, 'suppress_errors', my_f)
# suppress_console_outputs
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_min
if (v_min != None):
if not val_float(v_min, 'v_min', my_f, None, None, suppress_errors, suppress_console_outputs):
return False
# v_max
if (v_max != None):
if not val_float(v_max, 'v_max', my_f, None, None, suppress_errors, suppress_console_outputs):
return False
# v_input
# VARIABLE INSTANTIATION
mytype = "<class 'float'>" # str(type(myinput))
error_msg = error_msg_str(method, v_name, v_input, mytype, suppress_errors, suppress_console_outputs, v_arg_type)
# METHODS
if not mytype == str(type(v_input)):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
if (v_min != None and v_max != None):
if (v_min > v_max):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
return False
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
if (v_min != None):
if (v_input < v_min):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nValue less than minimum {v_min}.")
return False
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
if (v_max != None):
if (v_input > v_max):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"\nValue greater than maximum {v_max}.")
return False
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
# RETURNS
return True
def input_bool(v_input, v_name, method, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# input valid str, int, or bool representation of bool, or else None
# ARGUMENTS
# bool (hopefully) v_input
# str v_name
# str method
# optional str v_arg_type
# optional bool suppress_errors
# optional bool suppress_console_outputs
# ARGUMENT VALIDATION
my_f = 'input_bool'
# suppress_errors
val_bool(suppress_errors, 'suppress_errors', my_f)
# suppress_console_outputs
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return None
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
my_f = method + '.' + my_f
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# METHODS
if not val_bool(v_input, v_name, my_f, suppress_errors, suppress_console_outputs):
if not val_int(v_input, v_name, my_f, 0, 1, suppress_errors, suppress_console_outputs):
error_msg = error_msg_str(method, v_name, v_input, "<class 'bool'>", suppress_errors, suppress_console_outputs, v_arg_type)
if not val_str(v_input, v_name, my_f, suppress_errors, suppress_console_outputs):
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return None
raise ValueError(error_msg)
else:
my_truths = ['Y', 'YE', 'YES', 'YS', 'YESH', 'YEA', 'YEAH', 'TRUE', 'TRU', 'TRUTH', 'TURE', 'T']
my_falths = ['N', 'NO', 'FALSE', 'F', 'FAIL', 'FALS']
for i in range(len(my_truths)):
if my_truths[i] == v_input:
return True
for i in range(len(my_falths)):
if my_falths[i] == v_input:
return False
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return None
raise ValueError(error_msg)
else:
return False if v_input == 0 else True
# RETURNS
return v_input
def full_val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that bool input is bool or valid equivalent
# ARGUMENTS
# bool (hopefully) my_input
# str v_name
# str method
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'full_val_bool'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# RETURNS
return not (str(type(input_bool(v_input, v_name, method, suppress_errors, suppress_console_outputs, v_arg_type))) == "<class 'NoneType'>")
def input_int(v_input, v_name, method, v_min = None, v_max = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# input int or valid equivalent, or else None
# ARGUMENTS
# int or str v_input
# str v_name
# str method
# v_min
# v_min
# bool suppress_errors
# bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'input_int'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return None
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# v_min
if not str(type(v_min)) == "<class 'NoneType'>":
v_min = input_int(v_min, 'v_min', my_f, None, v_max, suppress_errors, suppress_console_outputs)
if str(type(v_min)) == "<class 'NoneType'>": return None
# v_max
if not str(type(v_max)) == "<class 'NoneType'>":
v_max = input_int(v_max, 'v_min', my_f, v_min, None, suppress_errors, suppress_console_outputs)
if str(type(v_max)) == "<class 'NoneType'>": return None
# METHODS
error_msg = error_msg_str(method, v_name, v_input, "<class 'int'>", suppress_errors, suppress_console_outputs, v_arg_type)
# v_input
try:
my_int = int(v_input)
except:
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return None
int(v_input)
if not str(type(v_min)) == "<class 'NoneType'>":
if my_int < v_min:
if suppress_errors:
if not suppress_console_outputs:
print(f"{error_msg}\nInt input less than minimum value. Value = {v_input}, minimum = {v_min}.")
return None
if not str(type(v_max)) == "<class 'NoneType'>":
if my_int > v_max:
if suppress_errors:
if not suppress_console_outputs:
print(f"{error_msg}\nInt input greater than maximum value. Value = {v_input}, maximum = {v_max}.")
return None
# RETURNS
return my_int
def full_val_int(v_input, v_name, method, v_min = None, v_max = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is int or equivalent, else False, limited by v_min and v_max
# ARGUMENTS
# int (hopefully) v_input
# str v_name
# str method
# optional float v_min
# optional float v_max
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'full_val_int'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_min
if not str(type(v_min)) == "<class 'NoneType'>":
v_min = input_int(v_min, 'v_min', method, None, v_max, suppress_errors, suppress_console_outputs)
if str(type(v_min)) == "<class 'NoneType'>": return False
# v_max
if not str(type(v_max)) == "<class 'NoneType'>":
v_max = input_int(v_max, 'v_min', method, v_min, None, suppress_errors, suppress_console_outputs)
if str(type(v_max)) == "<class 'NoneType'>": return False
# RETURNS
return not (str(type(input_int(v_input, v_name, method, v_min, v_max, suppress_errors, suppress_console_outputs))) == "<class 'NoneType'>")
def input_float(v_input, v_name, method, v_min = None, v_max = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# input float, else return None
# ARGUMENTS
# float/int/str(numeric) v_input
# str v_name
# str method
# optional float v_min
# optional float v_min
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'input_float'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return None
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return None
# v_min
if not str(type(v_min)) == "<class 'NoneType'>":
v_min = input_float(v_min, 'v_min', my_f, None, v_max, suppress_errors, suppress_console_outputs)
if str(type(v_min)) == "<class 'NoneType'>": return None
# v_max
if not str(type(v_max)) == "<class 'NoneType'>":
v_max = input_float(v_max, 'v_min', my_f, v_min, None, suppress_errors, suppress_console_outputs)
if str(type(v_max)) == "<class 'NoneType'>": return None
# METHODS
error_msg = error_msg_str(method, v_name, v_input, "<class 'float'>", suppress_errors, suppress_console_outputs, v_arg_type)
# v_input
try:
my_float = float(v_input)
except:
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return None
float(v_input)
if not str(type(v_min)) == "<class 'NoneType'>":
if v_input < v_min:
if suppress_errors:
if not suppress_console_outputs:
print(f"{error_msg}\nInt input less than minimum value. Value = {v_input}, minimum = {v_min}.")
return None
if not str(type(v_max)) == "<class 'NoneType'>":
if v_input > v_max:
if suppress_errors:
if not suppress_console_outputs:
print(f"{error_msg}\nInt input greater than maximum value. Value = {v_input}, maximum = {v_max}.")
return None
# RETURNS
return my_float
def full_val_float(v_input, v_name, method, v_min = None, v_max = None, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is numeric, and if not False, limited by v_min and v_max
# ARGUMENTS
# float (hopefully) v_input
# str v_name
# str method
# optional float v_min
# optional float v_max
# optional bool suppress_errors
# optional bool suppress_console_outputs
# ARGUMENT VALIDATION
my_f = 'full_val_float'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_min
if not str(type(v_min)) == "<class 'NoneType'>":
v_min = input_float(v_min, 'v_min', method, None, v_max, suppress_errors, suppress_console_outputs)
if str(type(v_min)) == "<class 'NoneType'>": return False
# v_max
if not str(type(v_max)) == "<class 'NoneType'>":
v_max = input_float(v_max, 'v_min', method, v_min, None, suppress_errors, suppress_console_outputs)
if str(type(v_max)) == "<class 'NoneType'>": return False
# RETURNS
return not (str(type(input_float(v_input, v_name, method, v_min, v_max, suppress_errors, suppress_console_outputs))) == "<class 'NoneType'>")
def make_ordinal(n):
# FUNCTION
# Get ordinal representation of number
# ARGUMENTS
# int n
# ARGUMENT VALIDATION
full_val_int(n, 'n', 'make_ordinal', 0)
# VARIABLE INSTANTIATION
n = int(n)
# METHODS
if 11 <= (n % 100):
suffix= 'th'
else:
suffix = ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]
# RETURNS
return str(n) + suffix
def val_type(v_input, v_type, v_name, method, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is of type v_type
# ARGUMENTS
# v_type (hopefully) v_input
# str v_type
# str v_name
# str method
# optional bool suppress_errors
# optional bool suppress_console_outputs
# str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_type'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_type
if not val_str(v_type, 'v_type', my_f, 6, -1, suppress_errors, suppress_console_outputs): return False
# v_input
error_message = error_msg_str(method, v_name, v_input, v_arg_type)
mytype = str(type(v_input))
# if not (v_type == 'int' or v_type == 'bool' or v_type == 'float' or v_type == 'complex' or v_type == 'str' or v_type == 'NoneType'):
if not mytype == v_type: # f"<class '{v_type}'>":
if suppress_errors:
if not suppress_console_outputs:
print(error_message)
return False
raise ValueError(error_message)
# RETURNS
return True
def val_list(v_input, v_name, method, v_type = '', min_len = -1, max_len = -1, suppress_errors = False, suppress_console_outputs: bool = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is of type list, and if defined: has v_len elements of type v_type
# ARGUMENTS
# list[v_type] (hopefully) v_input
# str v_name - variable name
# str method - parent method
# str v_type - type of list items
# int v_len - length of list
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_list'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>", suppress_errors))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_type
if not val_str(v_type, 'v_type', my_f, -1, -1, suppress_errors, suppress_console_outputs): return False
# min_len
if not full_val_int(min_len, 'min_len', my_f, None, None if max_len == -1 else max_len, suppress_errors, suppress_console_outputs): return False
# min_len = input_int(min_len, 'min_len', method, None, max_len, suppress_errors, suppress_console_outputs)
# if str(type(min_len)) == "<class 'NoneType'>": return False
# max_len
if not full_val_int(max_len, 'max_len', my_f, None if max_len == -1 else (None if min_len == -1 else min_len), None, suppress_errors, suppress_console_outputs): return False
# if not str(type(max_len)) == "<class 'NoneType'>":
# max_len = input_int(max_len, 'max_len', method, min_len, None, suppress_errors, suppress_console_outputs)
# if str(type(max_len)) == "<class 'NoneType'>": return False
# v_input
mytype = str(type(v_input))
error_msg = error_msg_str(method, v_name, v_input, "<class 'list'>")
if not mytype == "<class 'list'>":
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
L = len(v_input)
if max_len > -1 and L > max_len:
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f'\nInvalid list length. Maximum = {max_len}, length = {L}')
return False
raise ValueError(error_msg + f'\nInvalid list length. Maximum = {max_len}, length = {L}')
if L < min_len:
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f"Invalid list length. Minimum = {min_len}, length = {L}")
return False
raise ValueError(error_msg + f'\nInvalid list length. Minimum = {min_len}, length = {L}')
if v_type != '' and L > 0:
for i in range(L):
mytype = str(type(v_input[i]))
if not mytype == v_type:
error_msg = error_msg + '\n' + error_msg_str(my_f, v_name, v_input, v_type, False, False, 'list element')
if suppress_errors:
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# RETURNS
return True
def val_nested_list(v_input, depth_i, depth_max, v_name, method, v_type = '', v_min = -1, v_mins = [], v_max = -1, v_maxs: list = [], suppress_errors = False, suppress_console_outputs: bool = False, v_arg_type = 'argument'):
# FUNCTION
# validate that v_input is of type list, and if defined: has v_len elements of type v_type
# for nested list of nested-index i
# ARGUMENTS
# list[v_type] (hopefully) v_input
# int depth_i - current depth of nesting of lists
# int depth_max - maximum depth of nesting of lists - base 0
# str v_name
# str method
# Optional[str] v_type - type of list items
# Optional[int] v_min - minimum sublist size
# Optional[list[int]] v_mins - minimum list sizes
# Optional[int] v_max - maximum sublist size
# Optional[list[int]] v_maxs - maximum list sizes
# optional bool suppress_errors
# optional bool suppress_console_outputs
# optional str v_arg_type
# ARGUMENT VALIDATION
my_f = 'val_nested_list'
val_bool(suppress_errors, 'suppress_errors', my_f)
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
print(error_msg_str(my_f, 'suppress_console_outputs', suppress_console_outputs, "<class 'bool'>"))
return False
# method
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
my_f = method + '.' + my_f
# v_name
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_arg_type
if not val_str(v_arg_type, 'v_arg_type', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
# v_type
if not val_str(v_type, 'v_type', my_f, -1, -1, suppress_errors, suppress_console_outputs): return False
# v_min
if not val_int(v_min, 'v_min', my_f, -1, None, suppress_errors, suppress_console_outputs): return False
# v_max
if not val_int(v_max, 'v_max', my_f, -1, None, suppress_errors, suppress_console_outputs): return False
# v_mins
if not (val_list(v_mins, 'v_mins', my_f, "<class 'int'>", depth_max + 1, depth_max + 1, True, True) or v_mins == []):
error_msg = error_msg_str(my_f, 'v_mins', v_mins, "<class 'int'>")
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# v_maxs
if not (val_list(v_maxs, 'v_maxs', my_f, "<class 'int'>", depth_max + 1, depth_max + 1, True, True) or v_maxs == []):
error_msg = error_msg_str(my_f, 'v_maxs', v_maxs, "<class 'int'>")
if not suppress_console_outputs:
print(error_msg)
return False
raise ValueError(error_msg)
# v_input
mytype = v_type if depth_i == depth_max else "<class 'list'>"
error_msg = error_msg_str(method, v_name, v_input, mytype, suppress_errors, suppress_console_outputs, v_arg_type)
if not val_list(v_input, v_name, method, mytype, v_min, v_max, suppress_errors, suppress_console_outputs, v_arg_type):
if not suppress_console_outputs:
print(error_msg)
return False
# METHODS
L = len(v_input)
if L == 0:
if v_min > -1:
if suppress_errors:
if not suppress_console_outputs:
print(error_msg + f'\nMinimum length {v_min} not met.')
return False
raise ValueError(error_msg + f'\nMinimum length {v_min} not met.')
elif depth_i < depth_max:
for i in range(L):
if not (v_mins == [] or v_maxs == []):
if not val_nested_list(v_input[i], depth_i + 1, depth_max, v_name, method, v_type, v_mins[depth_i + 1], v_mins, v_maxs[depth_i + 1], v_maxs, suppress_errors, suppress_console_outputs, v_arg_type):
if not suppress_console_outputs:
print(error_msg)
return False
elif not v_mins == []:
if not val_nested_list(v_input[i], depth_i + 1, depth_max, v_name, method, v_type, v_mins[depth_i + 1], v_mins, -1, v_maxs, suppress_errors, suppress_console_outputs, v_arg_type):
if not suppress_console_outputs:
print(error_msg)
return False
elif not v_maxs == []:
if not val_nested_list(v_input[i], depth_i + 1, depth_max, v_name, method, v_type, -1, v_mins, v_maxs[depth_i + 1], v_maxs, suppress_errors, suppress_console_outputs, v_arg_type):
if not suppress_console_outputs:
print(error_msg)
return False
else:
if not val_nested_list(v_input[i], depth_i + 1, depth_max, v_name, method, v_type, -1, v_mins, -1, v_maxs, suppress_errors, suppress_console_outputs, v_arg_type):
if not suppress_console_outputs:
print(error_msg)
return False
# RETURNS
return True

152
model_gen/export_3d.py Normal file
View File

@@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
"""
Created on Mon May 1 03:35:45 2023
@author: Edward Middleton-Smith
Braille 3D Model Product Creation
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import openpyscad as ops
import system_commands as sc
import argument_validation as av
from translate_msg_2_braille import product, gen_braille_inputs_4_openscad
from translate_braille_2_scad import scrabble_dimensions, export_colour_theme, input_colour_themes, gen_openscad_braille, gen_path_braille_scrabble, input_product_size
from typing import Optional
def gen_product_permutations(my_product, szs_product, sz_perms = True, sz_index = 2):
# FUNCTION
# generate all colour / size permutations of product
# ARGUMENTS
# product my_product
# list[scrabble_dimensions] szs_product - different size profiles for products
# optional bool szs_perms
# optional int sz_index
# ARGUMENT VALIDATION
_m = 'gen_product_permutations'
av.val_type(my_product, "<class 'translate_msg_2_braille.product'>", 'my_product', _m)
av.val_list(szs_product, 'szs_product', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>", 1)
av.full_val_bool(sz_perms, 'sz_perms', _m)
# VARIABLE INSTANTIATION
mymsgs = [] # [msgin]
myszs = [] # [szs_scrabble[5]]
# METHODS
if not sz_perms:
my_size = input_product_size(szs_product, sz_index)
# create list of permutations of size profiles + letters
for j in range(len(szs_product) if sz_perms else 1):
for i in range(26 if my_product.name == 'Scrabble Alphabet of Tiles' else 1):
mymsgs.append(chr(65 + i) if my_product.name == 'Scrabble Character Tile' else my_product.msg)
myszs.append(szs_product[j] if sz_perms else my_size)
# RETURNS
return mymsgs, myszs
def gen_3d_models(braille_dict, myproduct, mymsgs, myszs, line_length, path_folder, path_cmd, mystyle, col_themes):
# FUNCTION
# create 3D models - SCAD, STL, PNG - from product input
# ARGUMENTS
# list[braille_trans] braille_dict
# product myproduct
# list[str] mymsgs
# list[scrabble_dimensions] myszs
# int line_length
# str path_folder
# style mystyle
# list [export_colour_themes] col_themes
# ARGUMENT VALIDATION
_m = 'gen_3d_models'
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', _m)
av.val_type(myproduct, "<class 'translate_msg_2_braille.product'>", 'myproduct', _m)
av.val_list(mymsgs, 'mymsgs', _m, "<class 'str'>", 1)
av.val_list(myszs, 'myszs', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>", 1) #:
# raise ValueError(av.error_msg_str(_m, 'myszs', myszs, "<class 'scrabble_dimensions'>"))
av.val_int(line_length, 'line_length', _m, 1)
av.val_str(path_folder, 'path_folder', _m)
av.val_str(path_cmd, 'path_cmd', _m, 1)
# av.val_int(show_braille, 'show_braille', _m)
# av.val_int(show_let, 'show_let', _m)
# av.val_int(show_num, 'show_num', _m)
# av.val_type(show_braille, "<enum 'elem_visibility'>", 'show_braille', _m)
# av.val_type(show_let, "<enum 'elem_visibility'>", 'show_let', _m)
# av.val_type(show_num, "<enum 'elem_visibility'>", 'show_num', _m)
av.val_type(mystyle, "<class 'translate_braille_2_scad.style'>", 'mystyle', _m)
av.val_list(col_themes, 'col_themes', _m, "<class 'translate_braille_2_scad.export_colour_theme'>", 1)
# VARIABLE INSTANTIATION
# METHODS
for col_y in range(len(col_themes)):
for msg_x in range(len(mymsgs)):
msg_x_str = mymsgs[msg_x]
cum, letters, numbers, braille, n_keys, n_rows = gen_braille_inputs_4_openscad(msg_x_str, line_length, braille_dict)
path_png, path_scad, path_stl = gen_openscad_braille(cum, letters, numbers, braille, n_keys, min(line_length, n_keys), n_rows, myszs[msg_x], mystyle, col_themes[col_y], msg_x_str, path_folder + myproduct.filename, quality = 100)
# sc.render_openscad(path_scad, path_stl, path_cmd)
# sc.render_openscad(path_scad, path_png, path_cmd)
# # RETURNS
# return col_themes
def gen_snippet_assembly(dx, dy, len_line, col_themes, myszs, my_product, path_folder, path_cmd, my_style): #, szs_product
# FUNCTION
# create png exports of openscad assembly of series of permutations of openscad components
# ARGUMENTS
# int dx - spacing along x
# int dy - spacing along y
# int len_line - number of components on row (along x)
# list[export_colour_theme] col_themes
# list[scrabble_dimensions] myszs
# translate_msg_2_braille.product my_product
# str path_folder
# str path_cmd
# style my_style
# # list[scrabble_dimensions] szs_product
# ARGUMENT VALIDATION
_m = 'gen_snippet_assembly'
av.val_int(dx, 'dx', _m)
av.val_int(dy, 'dy', _m)
av.val_int(len_line, 'len_line', _m, 1)
av.val_list(col_themes, 'col_themes', _m, "<class 'translate_braille_2_scad.export_colour_theme'>")
# av.val_list(szs_product, 'szs_product', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>", 1)
av.val_list(myszs, 'myszs', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>", 1)
av.val_type(my_product, "<class 'translate_msg_2_braille.product'>", 'my_product', _m)
av.val_str(path_folder, 'path_folder', _m)
av.val_str(path_cmd, 'path_cmd', _m, 1)
av.val_type(my_style, "<class 'translate_braille_2_scad.style'>", 'my_style', _m)
# VARIABLE INSTANTIATION
# mystyles = ['__l_0n'] # ['_0n', '_0l_0n', '_0b_0n', '__l_0n']
n_style = 1 # 3
d_pcs = [dx, dy]
# METHODS
for sz_i in range(len(myszs)):
ass_braille = ops.Union()
for let_i in range(1): # 26):
col_i = 0 # let_i % n_col
style_i = 0 # let_i % n_style
# mypath = gen_path_braille_scrabble(szs_scrabble[sz_i], let_i, col_themes[col_i], 'scad')
mypath = gen_path_braille_scrabble(myszs[sz_i], col_themes[col_i], my_style, path_folder + my_product.filename, 'scad')
# mypath = f"C:\\Users\\edwar\\OneDrive\\Documents\\Programming\\Python Scripts\\Braille_Scrabble_{szs_scrabble[sz_i].name}_{Chr(let_i + 65)}_{col_themes[col_i].name}"
ass_braille.append(ops.Scad(mypath).rotate([0, 180 * let_i, 0]).translate([4 * (let_i % 2), 0, -5 * (let_i % 2)]).translate([d_pcs[0] * myszs[sz_i].dp * (let_i % len_line), d_pcs[1] * myszs[sz_i].dp * (let_i // len_line), 0])) # , convexity = 3) .translate([d_pcs * (let_i % len_line), d_pcs * (let_i // len_line), 0])
# RETURNS
path_scad = gen_path_braille_scrabble(myszs[0], col_themes[col_i], my_style, path_folder + 'assy', 'scad')
path_stl = gen_path_braille_scrabble(myszs[0], col_themes[col_i], my_style, path_folder + 'assy', 'stl')
path_png = gen_path_braille_scrabble(myszs[0], col_themes[col_i], my_style, path_folder + 'assy', 'png')
ass_braille.write(path_scad) # , with_print=True
print(f"writing SCAD to {path_scad}")
# render_openscad(path_scad, path_stl)
sc.render_openscad(path_scad, path_png, path_cmd)

7
model_gen/init.py Normal file
View File

@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
"""
Created on Wed May 3 16:25:12 2023
@author: edwar
"""

108
model_gen/main.py Normal file
View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 24 14:26:02 2023
@author: Edward Middleton-Smith
Braille 3D Model Product Creation
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
from translate_msg_2_braille import get_braille_translations, gen_product_inputs, input_product
from translate_braille_2_scad import gen_scrabble_sizes, elem_visibility, input_colour_themes, style
from export_3d import gen_product_permutations, gen_3d_models, gen_snippet_assembly
import argument_validation as av
# PARAMETERS
path_folder_cmd = 'C:\\"Program Files"\\OpenSCAD\\openscad' # 'C:\\"Program Files (x86)"\\OpenSCAD\\openscad' # local environment variable path for openscad commands
path_folder = "C:\\Users\\edwar\\OneDrive\\Documents\\Programming\\Python Scripts\\" # file export parent directory
my_option = -1 # index of product option - if not valid, user console input will be required
my_select = '' # character selection for Braille tile(s) (if chosen)
size_permutations = False # generate models for all size options?
size_option = -1 # size option as int index - not required if size_permutations
colour_permutations = False # generate models for all colour options?
colour_option = '' # colour option as str or int index - not required if colour_permutations
show_braille = elem_visibility.VISIBLE # how should Braille be shown?
show_let = elem_visibility.VISIBLE # EMBOSSED # how should plaintext be shown?
show_num = elem_visibility.HIDDEN # how should ordinality be shown?
# assembly component spacing
dx = 5 # horizontnal
dy = 10 # vertical
# METHODS
def generate(my_option = -1, my_select = '', size_permutations = False, size_option = -1, colour_permutations = False, colour_option = 'Purple', show_braille = elem_visibility.VISIBLE, show_let = elem_visibility.VISIBLE, show_num = elem_visibility.HIDDEN, dx = 5, dy = 10, path_folder_cmd = 'C:\\"Program Files"\\OpenSCAD\\openscad', path_folder = "C:\\Users\\edwar\\OneDrive\\Documents\\Programming\\Python Scripts\\"):
# FUNCTION
# generate Braille model(s)
# ARGUMENTS
# int my_option - index of product option - if not valid, user console input will be required
# str my_select - character selection for Braille tile(s) (if chosen)
# bool size_permutation -
# int size_option - index of product_sizes option - ignored if size_permutations
# # bool colour_permutation
# elem_visibility show_braille
# elem_visibility show_let
# elem_visibility show_num
# float dx
# float dy
# str path_folder_cmd
# str path_folder
# VARIABLE INSTANTIATION
_m ='generate'
# ARGUMENT VALIDATION
av.val_int(my_option, 'my_option', _m)
av.val_str(my_select, 'my_select', _m)
av.val_bool(size_permutations, 'size_permutations', _m)
av.val_int(size_option, 'size_option', _m)
av.val_bool(colour_permutations, 'colour_permutations', _m)
# av.val_type(show_braille, "<enum 'translate_braille_2_scad.elem_visibility'>", 'show_braille', _m)
# av.val_type(show_let, "<enum 'translate_braille_2_scad.elem_visibility'>", 'show_let', _m)
# av.val_type(show_num, "<enum 'translate_braille_2_scad.elem_visibility'>", 'show_num', _m)
av.val_type(show_braille, "<enum 'elem_visibility'>", 'show_braille', _m)
av.val_type(show_let, "<enum 'elem_visibility'>", 'show_let', _m)
av.val_type(show_num, "<enum 'elem_visibility'>", 'show_num', _m)
av.val_int(dx, 'dx', _m)
av.val_int(dy, 'dy', _m)
av.val_str(path_folder_cmd, 'path_folder_cmd', _m)
av.val_str(path_folder, 'path_folder', _m)
# METHODS
mystyle = style(show_braille, show_let, show_num)
# Get Braille dictionary + delimiters
braille_translations = get_braille_translations()
# Get list of products that can be generated
products = gen_product_inputs(braille_translations)
# input product selection from user and translate to braille
my_product = input_product(braille_translations, products, my_option, my_select) # my_option)
# get list of product size configurations
sizes_product = gen_scrabble_sizes()
# generate product size (and content for Scrabble tile array) permutations
mymsgs, myszs = gen_product_permutations(my_product, sizes_product, size_permutations, size_option)
# get product colour selection
colour_themes = input_colour_themes(colour_permutations, colour_option)
# generate openscad, stl, and png files of selected product(s)
gen_3d_models(braille_translations, my_product, mymsgs, myszs, my_product.line_length, path_folder, path_folder_cmd, mystyle, colour_themes)
# generate assembly of products for promotional content, as scad + png
gen_snippet_assembly(dx, dy, my_product.line_length, colour_themes, myszs, my_product, path_folder, path_folder_cmd, mystyle)
# generate()
# generate(1, 'A')
generate(my_option, my_select, size_permutations, size_option, colour_permutations, colour_option, show_braille, show_let, show_num, dx, dy, path_folder_cmd, path_folder)
# generate(my_option, my_select, size_permutations, size_option, colour_permutations, colour_option, elem_visibility.VISIBLE, elem_visibility.VISIBLE, elem_visibility.VISIBLE, dx, dy, path_folder_cmd, path_folder)

View File

@@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 27 12:03:30 2023
@author: Edward Middleton-Smith
Procedural OpenSCAD Generation
https://github.com/taxpon/openpyscad/blob/develop/openpyscad/base.py
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import openpyscad as ops
import argument_validation as av
def bool_2_str(mybool):
# FUNCTION
# Convert boolean to lowercase string for openscad
# ARGUMENTS
# bool mybool
# ARGUMENT VALIDATION
if not av.val_bool(mybool):
return f'Error converting boolean to string.\nInput: {mybool}'
# RETURNS
return str(mybool).lower()
def neg_fillet(L, r, centre = True, q = 25):
# FUNCTION
# return negative-space fillet object for use with boolean operation
# ARGUMENTS
# int L - cylinder height
# double r - fillet radius
# bool centre - is fillet centred vertically?
# int q - quality / discretisation - number of points per edge
# ARGUMENT VALIDATION
if not (av.val_double(L, 0) and av.val_double(r, 0) and av.val_bool(centre) and av.val_int(q, 0)):
return None
# VARIABLE INSTANTIATION
fillet = ops.Difference()
# METHODS
fillet.append(ops.Cube([r, r, L], center = "false", _fn = q))
fillet.append(ops.Cylinder(L, r, center = "false"))
fillet.mirror([1, 1, 0])
fillet.translate([r, r, -L/2 if centre else 0])
# RETURNS
return fillet
def base_fillet_cube(a, b, c, f, q, centre = True):
# FUNCTION
# return openpyscad object of cube with base edges and corners filleted with radius f
# ARGUMENTS
# double a, b, c - cube dimensions x, y, z
# double f - fillet radius
# int q - quality / discretisation - number of points per edge
# bool centre - is base-filleted cube centred?
# ARGUMENT VALIDATION
if not (av.val_double(a, 0) and av.val_double(a, 0) and av.val_double(a, 0)):
return None
if not (av.val_double(f, 0, min(a, b, c)) and av.val_int(q, 1) and av.val_bool(centre)):
return None
# VARIABLE INSTANTIATION
my_dif = ops.Difference()
# METHODS
my_dif.append(ops.Cube([a, b, c], center = "true", _fn = q).translate([0, 0, c/2]))
my_dif.append(neg_fillet(a, f, True, q).rotate([90, 0, 0]))
my_dif.append(neg_fillet(a, f, True, q).rotate([90, 0, 0]).mirror([0, 1, 0]).translate([f + a, 0, 0]))
my_dif.append(neg_fillet(a, f, True, q).rotate([0, 90, 0]))
my_dif.append(neg_fillet(a, f, True, q).rotate([0, 90, 0]).mirror([1, 0, 0]).translate([0, f + b, 0]))
# RETURNS
return my_dif.translate([0 if centre else a/2, 0 if centre else b/2, -c/2 if centre else 0])
def triprism(a, L, centre = True):
# FUNCTION
# Triangular-based prism
# ARGUMENTS
# double a - triangle side-length
# double L - depth in Z-direction
# bool centre - is triprism centred by volume?
# ARGUMENT VALIDATION
if not (av.val_double(a, 0) and av.val_double(L, 0) and av.val_bool(centre)):
return None
# RETURNS
return ops.Polygon([[0,0], [0, a], [a, 0]]).linear_extrude(L, center = bool_2_str(centre)).translate([-a/2 if centre else 0, -a/3 if centre else 0, 0])
def gen_openscad_colours():
return [ # openscad_colours = [
"Lavender",
"Thistle",
"Plum",
"Violet",
"Orchid",
"Fuchsia",
"Magenta",
"MediumOrchid",
"MediumPurple",
"BlueViolet",
"DarkViolet",
"DarkOrchid",
"DarkMagenta",
"Purple",
"Indigo",
"DarkSlateBlue",
"SlateBlue",
"MediumSlateBlue",
"Pink",
"LightPink",
"HotPink",
"DeepPink",
"MediumVioletRed",
"PaleVioletRed",
"Aqua",
"Cyan",
"LightCyan",
"PaleTurquoise",
"Aquamarine",
"Turquoise",
"MediumTurquoise",
"DarkTurquoise",
"CadetBlue",
"SteelBlue",
"LightSteelBlue",
"PowderBlue",
"LightBlue",
"SkyBlue",
"LightSkyBlue",
"DeepSkyBlue",
"DodgerBlue",
"CornflowerBlue",
"RoyalBlue",
"Blue",
"MediumBlue",
"DarkBlue",
"Navy",
"MidnightBlue",
"IndianRed",
"LightCoral",
"Salmon",
"DarkSalmon",
"LightSalmon",
"Red",
"Crimson",
"FireBrick",
"DarkRed",
"GreenYellow",
"Chartreuse",
"LawnGreen",
"Lime",
"LimeGreen",
"PaleGreen",
"LightGreen",
"MediumSpringGreen",
"SpringGreen",
"MediumSeaGreen",
"SeaGreen",
"ForestGreen",
"Green",
"DarkGreen",
"YellowGreen",
"OliveDrab",
"Olive",
"DarkOliveGreen",
"MediumAquamarine",
"DarkSeaGreen",
"LightSeaGreen",
"DarkCyan",
"Teal",
"LightSalmon",
"Coral",
"Tomato",
"OrangeRed",
"DarkOrange",
"Orange",
"Gold",
"Yellow",
"LightYellow",
"LemonChiffon",
"LightGoldenrodYellow",
"PapayaWhip",
"Moccasin",
"PeachPuff",
"PaleGoldenrod",
"Khaki",
"DarkKhaki",
"Cornsilk",
"BlanchedAlmond",
"Bisque",
"NavajoWhite",
"Wheat",
"BurlyWood",
"Tan",
"RosyBrown",
"SandyBrown",
"Goldenrod",
"DarkGoldenrod",
"Peru",
"Chocolate",
"SaddleBrown",
"Sienna",
"Brown",
"Maroon",
"White",
"Snow",
"Honeydew",
"MintCream",
"Azure",
"AliceBlue",
"GhostWhite",
"WhiteSmoke",
"Seashell",
"Beige",
"OldLace",
"FloralWhite",
"Ivory",
"AntiqueWhite",
"Linen",
"LavenderBlush",
"MistyRose",
"Gainsboro",
"LightGrey",
"Silver",
"DarkGray",
"Gray",
"DimGray",
"LightSlateGray",
"SlateGray",
"DarkSlateGray",
"Black"
]

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 27 16:47:54 2023
@author: Edward Middleton-Smith
File Operations OpenSCAD, Cura Engine
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import os
def render_openscad(path_scad, path_stl, path_cmd = 'C:\\"Program Files (x86)"\\OpenSCAD\\openscad'):
# FUNCTION
# render openscad file and store as file type defined by path_stl
# ARGUMENTS
# str path_scad - filepath of openscad model
# str path_stl - filepath to store (stl)
# VARIABLE INSTANTIATION
cmd = f'{path_cmd} -o "{path_stl}" "{path_scad}"'
# METHODS
exec_oscmd(cmd)
def make_openscad(path_scad, path_stl, path_cmd = 'C:\\"Program Files (x86)"\\OpenSCAD\\openscad'):
# FUNCTION
# render openscad file and store as file type defined by path_stl
# ARGUMENTS
# str path_scad - filepath of openscad model
# str path_stl - filepath to store (stl)
# VARIABLE INSTANTIATION
cmd = f'{path_cmd} "{path_scad}"'
# METHODS
exec_oscmd(cmd)
def exec_oscmd(cmd):
# FUNCTION
# execute os system command
# - validation conducted by os system following python execution - NOT SAFE
# ARGUMENTS
# str cmd - command
# RETURNS
print()
print('command')
print(cmd)
# METHODS
# os.system('cd C:\\"Program Files (x86)"\\OpenSCAD\\') # pre-command for openscad commands, alt: os.system('C:\\"Program Files (x86)"\\OpenSCAD\\openscad ...')
os.system(cmd)
def slice_model(path_stl, path_gcode):
# FUNCTION
# slice stl file using Cura Engine
# ARGUMENTS
# str path_stl - filepath for input stl
# str path_stl - filepath to store gcode
# VARIABLE INSTANTIATION
cmd = f'C:\\"Program Files\\Ultimaker Cura 4.11.0\\CuraEngine ' # ToDo FINISH THIS
# METHODS
exec_oscmd(cmd)

View File

@@ -0,0 +1,664 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 26 17:11:57 2023
@author: Edward Middleton-Smith
Braille 3D Model Product Creation
Plaintext message translation into Braille for 3D modelling
Procedural OpenSCAD Generation
Braille Scrabble Pieces
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import openpyscad as ops
import numpy as np
import argument_validation as av
from openscad_objects import gen_openscad_colours
from typing import Optional
from prettytable import PrettyTable
from enum import Enum
class elem_visibility(Enum):
EMBOSSED = -1
HIDDEN = 0
VISIBLE = 1
def mini():
# FUNCTION
# Get minimum value in enumerator
# RETURNS
return min([e.value for e in elem_visibility])
def maxi():
# FUNCTION
# Get maximum value in enumerator
# RETURNS
return max([e.value for e in elem_visibility])
class style():
# ATTRIBUTE DECLARATION
braille: elem_visibility
letter: elem_visibility
number: elem_visibility
def __new__(cls, braille, letter, number):
_m = 'style.__new__'
av.val_type(braille, "<enum 'elem_visibility'>", 'braille', _m)
av.val_type(braille, "<enum 'elem_visibility'>", 'braille', _m)
av.val_type(braille, "<enum 'elem_visibility'>", 'braille', _m)
return super(style, cls).__new__(cls)
def __init__(self, braille, letter, number):
self.braille = braille
self.letter = letter
self.number = number
def gen_filetxt(mystyle):
# FUNCTION
# generate filename text for style settings
# ARGUMENTS
# style mystyle
# ARGUMENT VALIDATION
av.val_type(mystyle, "<class 'translate_braille_2_scad.style'>", 'mystyle', 'get_style_filetxt')
# VARIABLE INSTANTIATION
style_txt = '_0b' if (mystyle.braille == elem_visibility.HIDDEN) else ''
style_txt += '_0l' if (mystyle.letter == elem_visibility.HIDDEN) else ''
style_txt += '__l' if (mystyle.letter == elem_visibility.EMBOSSED) else ''
style_txt += '_0n' if (mystyle.number == elem_visibility.HIDDEN) else ''
# RETURNS
return style_txt
def base_fillet_cube(a, b, c, f, q, centre = "true"):
# fillets removed as they print horribly
# now just cube
my_dif = ops.Difference();
my_dif.append(ops.Cube([a, b, c], center = "true", _fn = q));
return my_dif.translate([0 if (centre == "true") else a/2, 0 if (centre == "true") else b/2, 0 if (centre == "true") else c/2])
def triprism(a, L, centre = "true"):
return ops.Polygon([[0,0], [0, a], [a, 0]]).linear_extrude(L, center = "true").translate([0, 0, 0 if (centre == "true") else L/2]);
class scrabble_dimensions:
# ATTRIBUTE DECLARATION
name: str
dp: float # distance between dots
hblock: float # height of
s: float # spacing between keys on keyboard
base_height: float # height of
hcyl: float # height of Braille dots
rcyl: float # base radius of Braille dots
rsphere: float # top radius of Braille dots
# METHODS
def __new__(cls, name, dp, hblock, s, base_height, hcyl, rcyl, rsphere):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str name - name size scheme
# float dp - distance between braille pins
# float hblock - height of base of each key
# float s - spacing
# float base_height - height of base block - board
# float hcyl - height of braille pins
# float rcyl - base radius of braille pins
# float rsphere - tip radius of braille pins
# ARGUMENT VALIDATION
_m = 'scrabble_dimensions.__new__'
v_arg_type = 'class attribute'
av.val_str(name, 'name', _m, 1, v_arg_type = v_arg_type)
av.full_val_float(dp, 'dp', _m, 0, v_arg_type = v_arg_type)
av.full_val_float(hblock, 'hblock', _m, v_arg_type = v_arg_type)
av.full_val_float(s, 's', _m, 0, v_arg_type = v_arg_type)
av.full_val_float(base_height, 'base_height', _m, 0, v_arg_type = v_arg_type)
av.full_val_float(hcyl, 'hcyl', _m, 0, v_arg_type = v_arg_type)
av.full_val_float(rcyl, 'rcyl', _m, 0, v_arg_type = v_arg_type)
av.full_val_float(rsphere, 'rsphere', _m, 0, v_arg_type = v_arg_type)
# RETURNS
return super(scrabble_dimensions, cls).__new__(cls)
def __init__(self, name, dp, hblock, s, base_height, hcyl, rcyl, rsphere):
# FUNCTION
# Construct class object
# ARGUMENTS
# str name
# float dp
# float hblock
# float s
# float base_height
# float hcyl
# float rcyl
# float rsphere
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE INSTANTIATION
self.name = name
self.dp = dp
self.hblock = hblock
self.s = s
self.base_height = base_height
self.hcyl = hcyl
self.rcyl = rcyl
self.rsphere = rsphere
def __repr__(self):
# FUNCTION
# Convert object to str representation
# RETURNS
return f"name = {self.name}, dp = {self.dp}, hblock = {self.hblock}, s = {self.s}, base_height = {self.base_height}, hcyl = {self.hcyl}, rcyl = {self.rcyl}, rsphere = {self.rsphere}"
def as_dict(self):
# FUNCTION
# Convert object attribute, value pairs to dictionary representation
# RETURNS
return {'name': self.name, 'dp': self.dp, 'hblock': self.hblock, 's': self.s, 'base_height': self.base_height, 'hcyl': self.hcyl, 'rcyl': self.rcyl, 'rsphere': self.rsphere}
# colour themes: # ToDo: include in arguments to generator!!
class export_colour_theme:
# ATTRIBUTE DECLARATION
name: str
coltop: str
colbase: str
# METHODS
def __new__(cls, name, coltop, colbase, openscad_colours):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str name - user reference to colour theme
# str coltop - a valid openSCAD colour e.g. '#010101'
# str colbase - a valid openSCAD colour e.g. 'blue'
# list[str] openscad_colours
# ARGUMENT VALIDATION
_m = 'export_colour_theme.__new__'
v_arg_type = 'class attribute'
av.val_str(name, 'name', _m, 1, v_arg_type = v_arg_type)
av.val_list(openscad_colours, 'openscad_colours', _m, "<class 'str'>", 1, v_arg_type = v_arg_type)
if not validate_openscad_colour(coltop, openscad_colours):
raise ValueError(f"Invalid export_colour_theme attribute coltop. Type = {str(type(coltop))}. Value = {coltop}")
if not validate_openscad_colour(colbase, openscad_colours):
raise ValueError(f"Invalid export_colour_theme attribute colbase. Type = {str(type(colbase))}. Value = {colbase}")
# RETURNS
return super(export_colour_theme, cls).__new__(cls)
def __init__(self, name, coltop, colbase, openscad_colours):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str name - user reference to colour theme
# str coltop - a valid openSCAD colour e.g. '#010101'
# str colbase - a valid openSCAD colour e.g. 'blue'
# list[str] openscad_colours # redundant in this function - used for argument validation
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE INSTANTIATION
self.name = name
self.top = coltop
self.base = colbase
def __repr__(self):
# FUNCTION
# Convert object to str representation
# RETURNS
return f"name = {self.name}, colour top = {self.top}, colour base = {self.base}" # , openscad_colours = {self.openscad_colours}
def as_dict(self):
# FUNCTION
# Convert object attribute, value pairs to dictionary representation
# RETURNS
return {'name': self.name, 'colour top': self.top, 'colour base': self.base} # , 'openscad_colours': self.openscad_colours
def as_row(self):
# FUNCTION
# Convert object values to list representation
# RETURNS
return [self.name, self.top, self.base] # , 'openscad_colours': self.openscad_colours
def gen_scrabble_sizes(s: Optional[float] = 0.5):
# default scrabble sizes
# s = 1/2
# def __init__(self, name, dp, hblock, s, base_height, hcyl, rcyl, rsphere):
k = 2.3622
szs_scrabble = []
szs_scrabble.append(scrabble_dimensions('sz_1', 2.5, 2*s, s, 4*s, 1.2, 2/3, 1/2))
szs_scrabble.append(scrabble_dimensions('sz_2', 4, 1.28, s, 4*s, 1.2, 3/2, 1))
szs_scrabble.append(scrabble_dimensions('sz_3', 8, 2.5, s, 6*s, 1.2, 3/2, 1))
szs_scrabble.append(scrabble_dimensions('sz_4', 10, 3, 1, 6*s, 1.2, 3/2, 1))
szs_scrabble.append(scrabble_dimensions('sz_5', 10, 1, 1, 6*s, 1.2, 3/2, 1))
szs_scrabble.append(scrabble_dimensions('keyboard', 2.5, 0.8, 0.5, 4, 1.2, 2/3, 0.5))
szs_scrabble.append(scrabble_dimensions('poster', 2.5, 0.8, 0.5, 2, 1.2, 2/3, 0.5))
szs_scrabble.append(scrabble_dimensions('poster_big', 2.5*k, 0.8, 0.5*k, 2, 1.2, 2/3*k, 0.5*k))
# print('szs_scrabble')
# print(szs_scrabble)
return szs_scrabble # pd.DataFrame([x.as_dict() for x in szs_scrabble])
def input_product_size(szs_product, v_size = 2):
# FUNCTION
# input valid product size from user
# ARGUMENTS
# list[scrabble_dimensions] szs_product
# int v_size
# ARGUMENT VALIDATION
_m = 'get_product_size'
av.val_list(szs_product, 'szs_product', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>")
av.val_int(v_size, 'v_size', _m)
# VARIABLE INSTANTIATION
n = len(szs_product)
# METHODS
if v_size > 0 and v_size <= n:
return szs_product[v_size - 1]
my_table = PrettyTable()
my_table.field_names = ['index', 'name', 'dp', 'hblock', 's', 'base_height', 'hcyl', 'rcyl', 'rsphere']
for i in range(n):
prod = szs_product[i]
my_table.add_row([i + 1, prod.name, prod.dp, prod.hblock, prod.s, prod.base_height, prod.hcyl, prod.rcyl, prod.rsphere])
print()
print("Please select product dimensions configuration from below:")
print(my_table)
# loopy = False
while True:
my_input = input("Product dimensions configuration (name or index): ")
if my_input == "#!ERRORCODE!#": exit
for i in range(n):
if validate_input_product_size(my_input, szs_product):
# loopy = True
# RETURNS
return get_product_size(my_input, szs_product)
def get_product_size(product_option, szs_product):
# FUNCTION
# get valid product size from list of scrabble_dimensions
# ARGUMENTS
# str/int product_option
# list[scrabble_dimensions] szs_product
# ARGUMENT VALIDATION
_m = 'get_product_size'
error_msg = av.error_msg_str(_m, product_option, 'product_option', 'scrabble_dimensions identifier')
if not (av.val_int(product_option, 'product_option', _m, suppress_errors = True, suppress_console_outputs = True) or av.val_str(product_option, 'product_option', _m, suppress_errors = True, suppress_console_outputs = True)):
raise ValueError(error_msg)
av.val_list(szs_product, 'szs_product', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>")
# VARIABLE INSTANTIATION
n = len(szs_product)
# METHODS
if av.full_val_int(product_option, 'product_option', _m, suppress_errors = True):
product_option = av.input_int(product_option, 'product_option', _m)
return szs_product[product_option - 1]
for col_i in range(n):
my_product = szs_product[col_i]
if product_option == my_product.name:
return my_product
# RETURNS
raise ValueError(error_msg)
def validate_input_product_size(product_option, szs_product):
# FUNCTION
# evaluate if product_option relates to a szs_product
# ARGUMENTS
# str/int product_option
# list[scrabble_dimensions] szs_product
# ARGUMENT VALIDATION
_m = 'validate_input_product_size'
if not (av.val_int(product_option, 'product_option', _m, suppress_errors = True, suppress_console_outputs = True) or av.val_str(product_option, 'product_option', _m, suppress_errors = True, suppress_console_outputs = True)): return False
av.val_list(szs_product, 'szs_product', _m, "<class 'translate_braille_2_scad.scrabble_dimensions'>")
# VARIABLE INSTANTIATION
n = len(szs_product)
# METHODS
if av.full_val_int(product_option, 'product_option', _m, suppress_errors = True):
product_option = av.input_int(product_option, 'product_option', _m)
return (0 < product_option and product_option <= n)
for prod_i in range(n):
if product_option == szs_product[prod_i].name:
return True
# RETURNS
return False
def validate_openscad_colour(mycolour, openscad_colours):
# FUNCTION
# validate argument openscad colour as string
# ARGUMENTS
# str mycolour - to be validated
# list[str] openscad_colours - to search through
# ARGUMENT VALIDATION
_m = 'validate_openscad_colour'
av.val_str(mycolour, 'mycolour', _m)
av.val_list(openscad_colours, 'openscad_colours', _m, "<class 'str'>")
# VARIABLE INSTANTIATION
N = len(mycolour)
# METHODS
if (N == 7):
if (mycolour[0] == '#' and mycolour[0:5].isnumeric):
return True
for i in range(len(openscad_colours)):
if (mycolour == openscad_colours[i]):
return True
# RETURNS
return False
# inputs
# path_scad = "C:/Users/edwar/OneDrive/Documents/OpenSCAD"
# path_stl = "C:/Users/edwar/OneDrive/Documents/OpenSCAD/STL"
# filename = "Braille_Scrabble_"
# cum = [0, 1]
# letters = ["B"]
# braille = [[2]]
# braille = [[[1, 1, 0, 0, 0, 0]]]
# lmsg = 1
# N = 1
# n_row_keys = 1
# maxln = 2
def gen_col_themes():
# FUNCTION
# create colour themes for image export of 3D models
# REQUIRES
# class export_colour_theme
# function gen_openscad_colours
# VARIABLE INSTANTIATION
openscad_colours = gen_openscad_colours()
col_themes = []
col_themes.append(export_colour_theme("Blue", "#337AFF", "#337AFF", openscad_colours))
col_themes.append(export_colour_theme("Purple", "#8E44AD", "#8E44AD", openscad_colours))
col_themes.append(export_colour_theme("Red", "#F7322F", "#F7322F", openscad_colours))
col_themes.append(export_colour_theme("Black", "Black", "#17202A", openscad_colours))
col_themes.append(export_colour_theme("White", "White", "White", openscad_colours))
# RETURNS
# list[export_colour_theme] col_themes - colour themes with name, top colour, base colour
return col_themes
def input_colour_themes(colour_permutations = False, colour_option = None):
# FUNCTION
# get valid colour option using parameter, else user console input
# ARGUMENTS
# bool colour_permutations
# int colour_option
# ARGUMENT VALIDATION
_m = 'input_colour_themes'
av.val_bool(colour_permutations, 'colour_permutations', _m)
if not (av.val_int(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True) or av.val_str(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True) or str(type(colour_option)) == "<class 'NoneType'>"):
raise ValueError(av.error_msg_str(_m, 'colour_option', colour_option, "export_colour_theme identifier"))
# VARIABLE INSTANTIATION
colour_themes = gen_col_themes()
if colour_permutations: return colour_themes
n = len(colour_themes)
# METHODS
if not validate_input_colour(colour_option, colour_themes):
colour_table = PrettyTable(field_names=['index', 'name', 'colour top', 'colour base'])
for col_i in range(n):
colour_table.add_row([col_i + 1] + colour_themes[col_i].as_row()) # .insert(0, str(col_i + 1))
print(colour_table)
while not validate_input_colour(colour_option, colour_themes):
colour_option = input("Please input colour selection by name or index above.")
# RETURNS
return [get_colour_theme(colour_option, colour_themes)]
def validate_input_colour(colour_option, colour_themes):
# FUNCTION
# evaluate if colour_option relates to a colour_theme
# ARGUMENTS
# str/int colour_option
# list[export_colour_themes] colour_themes
# ARGUMENT VALIDATION
_m = 'validate_input_colour'
if not (av.val_int(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True) or av.val_str(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True)): return False
av.val_list(colour_themes, 'colour_themes', _m, "<class 'translate_braille_2_scad.export_colour_theme'>")
# VARIABLE INSTANTIATION
n = len(colour_themes)
# METHODS
if av.full_val_int(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True):
colour_option = av.input_int(colour_option, 'colour_option', _m)
return (0 < colour_option and colour_option <= n)
for col_i in range(n):
if colour_option == colour_themes[col_i].name:
return True
# RETURNS
return False
def get_colour_theme(colour_option, colour_themes):
# FUNCTION
# get valid colour_option from colour_themes
# ARGUMENTS
# str/int colour_option
# list[export_colour_themes] colour_themes
# ARGUMENT VALIDATION
_m = 'get_colour_theme'
error_msg = av.error_msg_str(_m, colour_option, 'colour_option', 'export_colour_theme identifier')
if not (av.val_int(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True) or av.val_str(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True)):
raise ValueError(error_msg)
av.val_list(colour_themes, 'colour_themes', _m, "<class 'translate_braille_2_scad.export_colour_theme'>")
# VARIABLE INSTANTIATION
n = len(colour_themes)
# METHODS
if av.full_val_int(colour_option, 'colour_option', _m, suppress_errors = True, suppress_console_outputs = True):
colour_option = av.input_int(colour_option, 'colour_option', _m)
return colour_themes[colour_option - 1]
for col_i in range(n):
my_colour = colour_themes[col_i]
if colour_option == my_colour.name:
return my_colour
# ERROR HANDLING
raise ValueError(error_msg)
def gen_path_braille_scrabble(sz_scheme, col_theme, my_style, path_file = "C:\\Users\\edwar\\OneDrive\\Documents\\Programming\\Python Scripts\\Braille_Scrabble", suffix = "stl", presuffix=""):
# FUNCTION
# generate file path for braille scrabble design
# ARGUMENTS
# scrabble_dimensions sz_scheme
# int letter - index in the alphabet with base 0
# export_colour_theme col_theme
# style my_style
# string path_file - path of folder + filename (message text)
# string suffix - file type
# string presuffix - text before file type
# ARGUMENT VALIDATION
_m = 'gen_path_braille_scrabble'
av.val_type(sz_scheme, "<class 'translate_braille_2_scad.scrabble_dimensions'>", 'sz_scheme', _m)
av.val_type(col_theme, "<class 'translate_braille_2_scad.export_colour_theme'>", 'col_theme', _m)
av.val_type(my_style, "<class 'translate_braille_2_scad.style'>", 'my_style', _m)
av.val_str(path_file, 'path_file', _m)
av.val_str(suffix, 'suffix', _m)
av.val_str(presuffix, 'presuffix', _m)
# RETURNS
return f"{path_file}_{sz_scheme.name}_{col_theme.name}{my_style.gen_filetxt()}.{suffix}"
def gen_openscad_braille(cum, letters, numbers, braille, n_keys, n_row_keys, n_rows, mydims, mystyle, col_theme, filename, path_file="C:/Users/edwar/OneDrive/Documents/Programming/Python Scripts/Braille", quality = 25):
# FUNCTION
# generate openscad model of Braille product
# ARGUMENTS
# list[int] cum
# list[str] letters - array of plaintext for output
# list[int] numbers - ordinality of translated keys in alphabet / number line (where appropriate)
# list[list[int]] braille - translated keys
# int n_keys - number of keys in Braille message
# int n_row_keys - number of Braille keys per row on keyboard
# int n_rows - number of rows of keys on keyboard
# scrabble_dimensions mydims - sizing parameters
# style mystyle
# export_colour_themes col_theme
# str filename - excl. path
# str path_file
# ARGUMENT VALIDATION
_m = 'gen_openscad_braille'
av.val_list(cum, 'cum', _m, "<class 'int'>")
av.val_list(letters, 'letters', _m, "<class 'str'>")
av.val_nested_list(numbers, 0, 1, 'numbers', _m, "<class 'int'>")
av.val_nested_list(braille, 0, 2, 'braille', _m, "<class 'int'>", -1, [-1, -1, 6], -1, [-1, -1, 6])
av.val_int(n_keys, 'n_keys', _m)
av.val_int(n_row_keys, 'n_row_keys', _m)
av.val_int(n_rows, 'n_rows', _m)
# av.val_int(show_braille, 'show_braille', _m)
# av.val_int(show_let, 'show_let', _m)
# av.val_int(show_num, 'show_num', _m)
# av.val_type(show_braille, "<enum 'elem_visibility'>", 'show_braille', _m)
# av.val_type(show_let, "<enum 'elem_visibility'>", 'show_let', _m)
# av.val_type(show_num, "<enum 'elem_visibility'>", 'show_num', _m)
av.val_type(mystyle, "<class 'translate_braille_2_scad.style'>", 'mystyle', _m)
# if not (av.val_type(col_theme, "<class 'export_colour_theme'>", 'col_theme', _m, True) or av.val_type(col_theme, "<class 'translate_braille_2_scad.export_colour_theme'>", 'col_theme', _m, True)):
# raise ValueError(av.error_msg_str(_m, 'col_theme', col_theme, "<class 'export_colour_theme'>"))
av.val_type(col_theme, "<class 'translate_braille_2_scad.export_colour_theme'>", 'col_theme', _m)
av.val_str(filename, 'filename', _m)
av.val_str(path_file, 'path_file', _m)
# VARIABLE INSTANTIATION
# integer boolean conversions for position
i_s_braille = int(mystyle.braille == elem_visibility.VISIBLE)
i_s_let = int(mystyle.letter == elem_visibility.VISIBLE)
i_s_num = int(mystyle.number == elem_visibility.VISIBLE)
print(f'i_s_b = {i_s_braille}\ni_s_let = {i_s_let}\ni_s_num = {i_s_num}\n')
# dimensions
dp = mydims.dp # horizontal and vertical spacing between dots = 2.2 - 2.8mm
h_block = mydims.hblock # block height
s = mydims.s # inter-block spacing
h_base = mydims.base_height # thickness of base block
# derived from: horizontal distance between corresponding braille dots in adjacent cells = 5.1 - 6.8mm
# and also conforms to: vertical distance between corresponding braille dots in adjacent cells = 10 - 15mm
hcyl = mydims.hcyl # braille dot height
rcyl = mydims.rcyl #3/2; # braille dot base-radius
rsphere = mydims.rsphere #3/2*4/5; # braille dot top-radius
xb = dp + 2 * s + rcyl * 2
R_base_letter = [xb, xb] # alphabet block dimensions [x, y]
R_base_braille = [xb, xb + dp] # braille block dimensions [x, y]
R_base_number = np.array([xb, xb - 2 * s]) * i_s_num # number block dimensions [x, y] ' adjust to scalar coefficient rather than linear translation
htxt = hcyl # height of text
stxt = xb - 4 * s
snum = stxt * 0.75
ntxtsfn = 0.65 # scale factor for shrinking number text to fit more letters in single char space
ntxtsfm = 0.75 # scale factor for shrinking message text to fit more letters in single char space
font = '"Arial:style=Bold"'
_fn = quality
# keyboard layout
#maxln = 10;
#nln = min(maxln, N); # renamed n_row_keys
# temp = 1 + (N - 1) % nln
# yn = (N + nln - temp) / nln # - 0 ** (temp)
# print(f"number of rows = {yn}")
R_board = [n_row_keys * R_base_letter[0] + (n_row_keys + 3) * s,
n_rows * (R_base_braille[1] * i_s_braille + R_base_letter[1] * i_s_let + R_base_number[1] * i_s_num + s * (i_s_braille + i_s_let + i_s_num)) + 3 * s, # - 3 * s,
h_base] # +R_base_number[1]
print(f"R_board = {R_board}")
obj_dif = ops.Difference()
obj_uni = ops.Union()
# obj_uni.append(base_fillet_cube(R_board[0], R_board[1], R_board[2], h_block, centre = "false").translate([-2 * s - rcyl, 2 * s + rcyl - R_board[1], -h_block - R_board[2]]).color(col_theme.base))
obj_uni.append(ops.Cube([R_board[0], R_board[1], R_board[2]], h_block, centre = "false").translate([-3 * s - rcyl, 3 * s + rcyl - R_board[1], -h_block - R_board[2]]).color(col_theme.base))
# METHODS
for ab_i in range(len(braille)): # alpha-braille iterator
char = braille[ab_i]
print(f"char = braille[{ab_i}]") # " = {char}")
for char_j in range(len(char)):
char_old = [0, 0, 0, 0, 0, 0] if (ab_i == 0 and char_j == 0) else braille[0][char_j - 1] if (char_j > 0) else braille[ab_i - 1][len(braille[ab_i - 1]) - 1]
char_new = char[char_j]
print(f"char_new = {char_new}")
ab_n = (cum[ab_i] + char_j) % n_row_keys
ab_len = ((cum[ab_i] + char_j) - ab_n) / n_row_keys
ab_p = [ab_n * (R_base_braille[0] + s), -ab_len * (R_base_braille[1] * i_s_braille + R_base_letter[1] * i_s_let + R_base_number[1] * i_s_num + s * (i_s_braille + i_s_let + i_s_num)), 0]
# Bases
if (letters[ab_i] != " "):
if (mystyle.braille == elem_visibility.VISIBLE):
obj_uni.append(ops.Cube([R_base_braille[0], R_base_braille[1], h_block]).color(col_theme.base).translate([-(s + rcyl), s + rcyl - R_base_braille[1], -h_block]).translate(ab_p))
if (mystyle.letter == elem_visibility.VISIBLE):
obj_uni.append(ops.Cube([R_base_letter[0], R_base_letter[1], h_block]).color(col_theme.base).translate([-(s + rcyl), s + rcyl -R_base_letter[1], 0]).translate([0, -(R_base_braille[1] + s) * i_s_braille, -h_block]).translate(ab_p)) # should this be: rcyl - R_base_letter[1] ?????!?!?!?!!!!
# Braille message
# Dots
if (mystyle.braille == elem_visibility.VISIBLE):
for dot_y in range(3):
for dot_x in range(2):
if (char_new[dot_y + 3 * dot_x] == 1):
obj_uni.append(ops.Cylinder(hcyl, None, rcyl, rsphere, _fn = _fn, center = 'true').color(col_theme.top).translate([dot_x * dp, -dot_y * dp, 0]).translate(ab_p))
# Text
if (mystyle.letter == elem_visibility.VISIBLE):
obj_uni.append(ops.Text(f'"{letters[ab_i]}"', stxt * ntxtsfm ** (len(letters[ab_i]) - 1), font, halign = '"center"', valign = '"center"', _fn = _fn).linear_extrude(htxt, center = "false").translate([R_base_letter[0] / 2, R_base_letter[1] / 2, 0]).color(col_theme.top).translate([-(s + rcyl), s + rcyl -R_base_letter[1], 0]).translate([0, - (R_base_braille[1] + s) * i_s_braille, 0]).translate(ab_p))
# Text ordinality
num_new = numbers[ab_i]
if (num_new != [-1] and mystyle.number == elem_visibility.VISIBLE):
print(f"num_new = {num_new}, type = {type(num_new)}")
for num_x in range(len(num_new)):
snum = (R_base_number[1] - s * (len(num_new) + 1)) / (len(num_new) ** ntxtsfn)
# Base
obj_uni.append(ops.Cube([R_base_number[0], R_base_number[1], h_block]).color(col_theme.base).translate([0, -R_base_number[1], 0]).translate([-(s + rcyl), s + rcyl -(R_base_letter[1] + s) * i_s_let, 0]).translate([0, -(R_base_braille[1] + s) * i_s_braille, -h_block]).translate(ab_p))
# Number (text)
obj_uni.append(ops.Text(f'"{num_new[num_x]}"', snum, font, halign = '"center"', valign = '"center"', _fn = _fn).linear_extrude(htxt, center = "true").color(col_theme.top).translate([R_base_number[0] / 2 if (len(num_new) == 1) else R_base_number[0] / 2 + 1.6 * snum * (num_x - (len(num_new) - 1) / 2), R_base_number[1] * 0.25, htxt / 2]).translate([-s, s -R_base_number[1], 0]).translate([0, -(R_base_letter[1] - s) * i_s_let, 0]).translate([s-(s + rcyl), s - (R_base_braille[1] + s) * i_s_braille, -h_block * 0]).translate(ab_p))
obj_dif.append(obj_uni)
# remove excess plastic if no numbers on final row regardless of mystyle.number
remove_num_space = True
for ab_i in range(n_row_keys):
remove_num_space &= numbers[len(numbers) - ab_i - 1] == [-1]
# Trimming tools for no numbers:
if remove_num_space:
obj_dif.append(ops.Cube([R_board[0], R_base_number[1] + s, R_board[2]], center = "true").translate([R_board[0] / 2 - 3 * s - rcyl, 3 * s + rcyl + (R_base_number[1] + s) / 2 - R_board[1], -R_board[2] / 2 - h_block]))
# obj_dif.append(triprism(h_block, R[0], centre = "true").rotate([0, 90, 0]).translate([R[0] / 2 - 1.6, (12+4) * s - R[1], -1/1000 - R[2] - h_block]))
# embossed characters
for ab_i in range(len(braille)):
char = braille[ab_i]
print(f"char = braille[{ab_i}]") # " = {char}")
for char_j in range(len(char)):
# what is the purpose of char_old?
char_old = [0, 0, 0, 0, 0, 0] if (ab_i == 0 and char_j == 0) else braille[0][char_j - 1] if (char_j > 0) else braille[ab_i - 1][len(braille[ab_i - 1]) - 1]
char_new = char[char_j]
ab_n = (cum[ab_i] + char_j) % n_row_keys
ab_len = ((cum[ab_i] + char_j) - ab_n) / n_row_keys
ab_p = [ab_n * (R_base_braille[0] + s), -ab_len * (R_base_braille[1] * i_s_braille + R_base_letter[1] * i_s_let + R_base_number[1] * i_s_num + s * (i_s_braille + i_s_let + i_s_num)), 0]
# Text
if (mystyle.letter == elem_visibility.EMBOSSED):
obj_dif.append(ops.Text(f'"{letters[ab_i]}"', stxt * ntxtsfm ** (len(letters[ab_i]) - 1) * 1.15, font, halign = '"center"', valign = '"center"', _fn = _fn).linear_extrude(htxt, center = "false").mirror([1, 0, 0]).translate([R_base_letter[0] / 2, R_base_letter[1] * 3 / 4, - R_board[2]]).color(col_theme.top).translate([0, -R_base_braille[1], 0]).translate([-(s + rcyl), s + rcyl - (R_base_braille[1] + s) * i_s_braille * 0, -h_block]).translate(ab_p))
# my_prefix = '_0b' if (mystyle.braille == elem_visibility.HIDDEN) else ''
# my_prefix += '_0l' if (mystyle.letter == elem_visibility.HIDDEN) else ''
# my_prefix += '__l' if (mystyle.letter == elem_visibility.EMBOSSED) else ''
# my_prefix += '_0n' if (mystyle.number == elem_visibility.HIDDEN) else ''
# my_prefix = mystyle.gen_filetxt()
path_png = gen_path_braille_scrabble(mydims, col_theme, mystyle, path_file, 'png')
path_scad = gen_path_braille_scrabble(mydims, col_theme, mystyle, path_file, 'scad')
path_stl = gen_path_braille_scrabble(mydims, col_theme, mystyle, path_file, 'stl')
# RETURNS
obj_dif.write(path_scad)
print("writing SCAD")
# obj_dif.write(path_png)
return path_png, path_scad, path_stl
# def get_shownum(braille):
# shownum = 1
# for n_x in range(len(braille)):
# shownum &= not (not braille[n_x])
# return 0 # 1 if shownum else 0

View File

@@ -0,0 +1,801 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 24 14:26:02 2023
@author: Edward Middleton-Smith
Braille 3D Model Product Creation
Braille Dictionary Conversion / Creation
Plaintext message translation into Braille for 3D modelling
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import pandas as pd
from typing import Optional
from enum import Enum
import argument_validation as av
import sys
class difficulty(Enum):
ALPHABETPUNCTUATION = 1
SIMPLEWORDGROUPSIGNS = 2
LOWERCONTRACTIONS = 3
def mini():
# FUNCTION
# Get minimum value in enumerator
# RETURNS
return min([e.value for e in difficulty])
def maxi():
# FUNCTION
# Get maximum value in enumerator
# RETURNS
return max([e.value for e in difficulty])
class braille_trans():
# ATTRIBUTE DECLARATION
key: str # search key in input messages for Braille translation - includes additional characters for literal processing
level: difficulty # stage of learning at which this translation is discovered
braille: list # list[list[int]] # Braille translation of plaintext
plaintext: str # English plaintext key
# METHODS
# def argvalinit(key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# # run before instantiating braille_trans
# # av.val_list(braille, 'list')=
# # _m = 'braille_trans.argvalinit'
# # if not av.val_str(key, 'key', method, min_len = -1, max_len = -1, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument')
# if not (av.val_str(key) and (str(type(level)) == "<enum 'difficulty'>" or av.val_int(level, difficulty.mini(), difficulty.maxi())) and av.val_list(braille, "<class 'list'>") and (av.val_str(plaintext, -1, -1, True) or plaintext == None)):
# print(f'Invalid braille_trans instantiation. key = {key}, level = {level}, braille = {braille}, plaintext = {plaintext}')
# return None
# return braille_trans(key, level, braille, plaintext)
def __new__(cls, key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str key
# difficulty level
# list[list[int]] braille
# optional str plaintext
# VARIABLE DECLARATION
_m = 'braille_trans.__new__'
v_arg_type = 'class attribute'
# ARGUMENT VALIDATION
av.val_str(key, 'key', _m, 1, -1, v_arg_type = v_arg_type)
av.val_type(level, "<enum 'difficulty'>", 'level', _m, v_arg_type = v_arg_type)
av.val_nested_list(braille, 0, 1, 'braille', _m, "<class 'int'>", -1, [-1, 6], -1, [-1, 6], v_arg_type = v_arg_type)
if not (av.val_str(plaintext, 'plaintext', _m, -1, -1, True, True, v_arg_type) or str(type(plaintext)) == "<class 'NoneType'>"):
raise ValueError(av.error_msg_str(_m, 'plaintext', plaintext, "<class 'str'>", v_arg_type = v_arg_type))
# if not av.val_str(key):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'key', key, 'attribute'))
# if not av.val_type(level, "<enum 'difficulty'>"):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'level', level, 'attribute'))
# if not av.val_nested_list(braille, 0, 2, "<class 'int'>", 6, [1, 6], 6, [-1, 6]):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'braille', braille, 'attribute'))
# if not (av.val_str(plaintext) or str(type(plaintext)) == "<class 'NoneType'>"):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'plaintext', plaintext, 'attribute'))
# RETURNS
return super(braille_trans, cls).__new__(cls)
def __init__(self, key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# FUNCTION
# Construct class object
# ARGUMENTS
# str key
# difficulty level
# list[list[int]] braille
# optional str plaintext
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE + VARIABLE INSTANTIATION
self.key = key
self.level = level
self.braille = braille
self.plaintext = self.key if (plaintext is None) else plaintext
def __repr__(self):
return f"key = {self.key}, level = {self.level}, braille = {self.braille}, plaintext = {self.plaintext}"
# def query_lvl(self):
# return ' & '.join(["{}=='{}'".format(key, value)
# for key, value in self.__dict__.items()
# if not value is None])
def as_dict(self):
return {'key': self.key, 'level': self.level, 'braille': self.braille, 'plaintext': self.plaintext}
class product():
# ATTRIBUTE DECLARATION
name: str
line_length: int # number of Braille characters per line on keyboard
msg: str # pre-translated English (with necessary modifications for input to this programme e.g. splitting up undesired translations with hidden delimiter character @?NOTHING)
msg_prefix: str # additional pre-translated str as above to pre-append to product for adding header to creation of product messages from dictionary queries
filename: str # filename - name without spaces
# METHODS
# def argvalinit(name: str, line_length: int, msg: str, msg_prefix: Optional[str] = ''):
# # run before instantiating product
# if not (av.val_str(name) and av.val_int(line_length, 0) and av.val_str(msg) and av.val_str(msg_prefix)):
# print(f'Invalid product instantiation. name = {name}, line_length = {line_length}, msg = {msg}, msg_prefix = {msg_prefix}')
# return None
# return product(name, line_length, msg, msg_prefix)
def __new__(cls, name, line_length, msg, msg_prefix = '', filename = ''):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str name
# int line_length
# str msg
# str msg_prefix
# ARGUMENT VALIDATION
_m = 'product.__new__'
v_arg_type = 'class attribute'
av.val_str(name, 'name', _m, 1, -1, v_arg_type = v_arg_type)
av.val_int(line_length, 'line_length', _m, 1, v_arg_type = v_arg_type)
av.val_str(msg, 'msg', _m, -1, -1, v_arg_type = v_arg_type)
av.val_str(msg_prefix, 'msg_prefix', _m, -1, -1, v_arg_type = v_arg_type)
av.val_str(filename, 'filename', _m, -1, -1, v_arg_type = v_arg_type)
# if not av.val_str(name):
# raise ValueError(av.error_msg_str('product.__new__', 'name', name, 'attribute'))
# if not av.val_int(line_length, 1):
# raise ValueError(av.error_msg_str('product.__new__', 'line_length', line_length, 'attribute'))
# if not av.val_str(msg):
# raise ValueError(av.error_msg_str('product.__new__', 'msg', msg, 'attribute'))
# if not av.val_str(msg_prefix):
# raise ValueError(av.error_msg_str('product.__new__', 'msg_prefix', msg_prefix, 'attribute'))
# RETURNS
return super(product, cls).__new__(cls)
def __init__(self, name, line_length, msg, msg_prefix = '', filename = ''):
# FUNCTION
# Construct class object
# ARGUMENTS
# str name
# int line_length
# str msg
# str msg_prefix
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE + VARIABLE INSTANTIATION
self.name = name
self.line_length = line_length
self.msg = msg
self.msg_prefix = msg_prefix # for procedurally-generated messages from difficulty selection
self.filename = name.replace(' ', '_') if filename == '' else filename
def __repr__(self):
return f"name = {self.name}, line_length = {self.line_length}, msg = {self.msg}, msg_prefix = {self.msg_prefix}, filename = {self.filename}"
def get_braille_translations():
# FUNCTION
# return list of braille translations
# longer keys get priority in translation
# VARIABLE INSTANTIATION
temp_dict = [braille_trans("A", difficulty(1), [[1, 0, 0, 0, 0, 0]]),
braille_trans("B", difficulty(1), [[1, 1, 0, 0, 0, 0]]),
braille_trans("C", difficulty(1), [[1, 0, 0, 1, 0, 0]]),
braille_trans("D", difficulty(1), [[1, 0, 0, 1, 1, 0]]),
braille_trans("E", difficulty(1), [[1, 0, 0, 0, 1, 0]]),
braille_trans("F", difficulty(1), [[1, 1, 0, 1, 0, 0]]),
braille_trans("G", difficulty(1), [[1, 1, 0, 1, 1, 0]]),
braille_trans("H", difficulty(1), [[1, 1, 0, 0, 1, 0]]),
braille_trans("I", difficulty(1), [[0, 1, 0, 1, 0, 0]]),
braille_trans("J", difficulty(1), [[0, 1, 0, 1, 1, 0]]),
braille_trans("K", difficulty(1), [[1, 0, 1, 0, 0, 0]]),
braille_trans("L", difficulty(1), [[1, 1, 1, 0, 0, 0]]),
braille_trans("M", difficulty(1), [[1, 0, 1, 1, 0, 0]]),
braille_trans("N", difficulty(1), [[1, 0, 1, 1, 1, 0]]),
braille_trans("O", difficulty(1), [[1, 0, 1, 0, 1, 0]]),
braille_trans("P", difficulty(1), [[1, 1, 1, 1, 0, 0]]),
braille_trans("Q", difficulty(1), [[1, 1, 1, 1, 1, 0]]),
braille_trans("R", difficulty(1), [[1, 1, 1, 0, 1, 0]]),
braille_trans("S", difficulty(1), [[0, 1, 1, 1, 0, 0]]),
braille_trans("T", difficulty(1), [[0, 1, 1, 1, 1, 0]]),
braille_trans("U", difficulty(1), [[1, 0, 1, 0, 0, 1]]),
braille_trans("V", difficulty(1), [[1, 1, 1, 0, 0, 1]]),
braille_trans("W", difficulty(1), [[0, 1, 0, 1, 1, 1]]),
braille_trans("X", difficulty(1), [[1, 0, 1, 1, 0, 1]]),
braille_trans("Y", difficulty(1), [[1, 0, 1, 1, 1, 1]]),
braille_trans("Z", difficulty(1), [[1, 0, 1, 0, 1, 1]]),
braille_trans("@?NUM", difficulty(1), [[0, 0, 1, 1, 1, 1]], 'NUMBER'),
#" ", difficulty(1), [[0, 0, 0, 0, 0, 0]]),
braille_trans(",", difficulty(1), [[0, 1, 0, 0, 0, 0]]),
braille_trans(";", difficulty(1), [[0, 1, 1, 0, 0, 0]]),
braille_trans(":", difficulty(1), [[0, 1, 0, 0, 1, 0]]),
braille_trans(".", difficulty(1), [[0, 1, 0, 0, 1, 1]]),
braille_trans("!", difficulty(1), [[0, 1, 1, 0, 1, 0]]),
braille_trans("(", difficulty(1), [[0, 1, 1, 0, 1, 1]]),
braille_trans(")", difficulty(1), [[0, 1, 1, 0, 1, 1]]),
braille_trans("?", difficulty(1), [[0, 1, 1, 0, 0, 1]]),
braille_trans('"@?BO', difficulty(1), [[0, 1, 1, 0, 0, 1]], '"'),
braille_trans('"@?BC', difficulty(1), [[0, 0, 1, 0, 1, 1]], '"'),
braille_trans("'", difficulty(1), [[0, 0, 1, 0, 0, 0]]),
braille_trans("@?ABBREV1", difficulty(1), [[0, 0, 0, 1, 0, 0]], "ABBREV"),
braille_trans("@?ABBREV2", difficulty(1), [[0, 0, 0, 1, 1, 0]], "ABBREV"),
braille_trans("@?ABBREV3", difficulty(1), [[0, 0, 0, 1, 1, 1]], "ABBREV"),
braille_trans("@?ABBREV4", difficulty(1), [[0, 0, 0, 0, 1, 0]], "ABBREV"),
braille_trans("...", difficulty(1), [[0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0]]),
braille_trans("-", difficulty(1), [[0, 0, 1, 0, 0, 1]]),
braille_trans("-@?S", difficulty(1), [[0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1]], "-"),
braille_trans("-@?L", difficulty(1), [[0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1]], "-"),
braille_trans("/@?B", difficulty(1), [[0, 0, 0, 1, 0, 0], [0, 1, 1, 0, 1, 1]], "/"),
braille_trans("\@?B", difficulty(1), [[0, 0, 0, 1, 0, 0], [0, 1, 1, 0, 1, 1]], "\\"),
braille_trans("[@?BPH", difficulty(1), [[0, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1]], "["),
braille_trans("]@?BPH", difficulty(1), [[0, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1]], "]"),
braille_trans("<", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans(">", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("/", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 0, 1, 1, 0, 0]]),
braille_trans("{", difficulty(1), [[0, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("}", difficulty(1), [[0, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("[@?BSQ", difficulty(1), [[0, 0, 0, 0, 0, 1], [0, 1, 1, 0, 1, 1]], "["),
braille_trans("]@?BSQ", difficulty(1), [[0, 1, 1, 0, 1, 1], [0, 0, 0, 0, 0, 1]], "]"),
braille_trans("'@?BO", difficulty(1), [[0, 0, 0, 0, 0, 1], [0, 1, 1, 0, 0, 1]], "'"),
braille_trans("'@?BC", difficulty(1), [[0, 1, 1, 0, 0, 1], [0, 0, 0, 0, 0, 1]], "'"),
# oldbrailledict_2 = {
# Simple Upper Wordsigns
braille_trans("BUT", difficulty(2), [[1, 1, 0, 0, 0, 0]]),
braille_trans("CAN", difficulty(2), [[1, 0, 0, 1, 0, 0]]),
braille_trans("DO", difficulty(2), [[1, 0, 0, 1, 1, 0]]),
braille_trans("EVERY", difficulty(2), [[1, 0, 0, 0, 1, 0]]),
braille_trans("FROM", difficulty(2), [[1, 1, 0, 1, 0, 0]]),
braille_trans("GO", difficulty(2), [[1, 1, 0, 1, 1, 0]]),
braille_trans("HAVE", difficulty(2), [[1, 1, 0, 0, 1, 0]]),
braille_trans("JUST", difficulty(2), [[0, 1, 0, 1, 1, 0]]),
braille_trans("KNOWLEDGE", difficulty(2), [[1, 0, 1, 0, 0, 0]]),
braille_trans("LIKE", difficulty(2), [[1, 1, 1, 0, 0, 0]]),
braille_trans("MORE", difficulty(2), [[1, 0, 1, 1, 0, 0]]),
braille_trans("NOT", difficulty(2), [[1, 0, 1, 1, 1, 0]]),
braille_trans("PEOPLE", difficulty(2), [[1, 1, 1, 1, 0, 0]]),
braille_trans("QUITE", difficulty(2), [[1, 1, 1, 1, 1, 0]]),
braille_trans("RATHER", difficulty(2), [[1, 1, 1, 0, 1, 0]]),
braille_trans("SO", difficulty(2), [[0, 1, 1, 1, 0, 0]]),
braille_trans("THAT", difficulty(2), [[0, 1, 1, 1, 1, 0]]),
braille_trans("US", difficulty(2), [[1, 0, 1, 0, 0, 1]]),
braille_trans("VERY", difficulty(2), [[1, 1, 1, 0, 0, 1]]),
braille_trans("WILL", difficulty(2), [[0, 1, 0, 1, 1, 1]]),
braille_trans("IT", difficulty(2), [[1, 0, 1, 1, 0, 1]]),
braille_trans("YOU", difficulty(2), [[1, 0, 1, 1, 1, 1]]),
braille_trans("AS", difficulty(2), [[1, 0, 1, 0, 1, 1]]),
braille_trans("CHILD", difficulty(2), [[1, 0, 0, 0, 0, 1]]),
braille_trans("SHALL", difficulty(2), [[1, 0, 0, 1, 0, 1]]),
braille_trans("THIS", difficulty(2), [[1, 0, 0, 1, 1, 1]]),
braille_trans("WHICH", difficulty(2), [[1, 0, 0, 0, 1, 1]]),
braille_trans("OUT", difficulty(2), [[1, 1, 0, 0, 1, 1]]),
braille_trans("STILL", difficulty(2), [[0, 0, 1, 1, 0, 0]]),
# Simple Upper Groupsigns
braille_trans("AND", difficulty(2), [[1, 1, 1, 1, 0, 1]]),
braille_trans("FOR", difficulty(2), [[1, 1, 1, 1, 1, 1]]),
braille_trans("OF", difficulty(2), [[1, 1, 1, 0, 1, 1]]),
braille_trans("THE", difficulty(2), [[0, 1, 1, 1, 0, 1]]),
braille_trans("WITH", difficulty(2), [[0, 1, 1, 1, 1, 1]]),
braille_trans("CH", difficulty(2), [[1, 0, 0, 0, 0, 1]]),
braille_trans("GH", difficulty(2), [[1, 1, 0, 0, 0, 1]]),
braille_trans("SH", difficulty(2), [[1, 0, 0, 1, 0, 1]]),
braille_trans("TH", difficulty(2), [[1, 0, 0, 1, 1, 1]]),
braille_trans("WH", difficulty(2), [[1, 0, 0, 0, 1, 1]]),
braille_trans("ED", difficulty(2), [[1, 1, 0, 1, 0, 1]]),
braille_trans("ER", difficulty(2), [[1, 1, 0, 1, 1, 1]]),
braille_trans("OU", difficulty(2), [[1, 1, 0, 0, 1, 1]]),
braille_trans("OW", difficulty(2), [[0, 1, 0, 1, 0, 1]]),
braille_trans("ST", difficulty(2), [[0, 0, 1, 1, 0, 0]]),
braille_trans("AR", difficulty(2), [[0, 0, 1, 1, 1, 0]]),
braille_trans("ING", difficulty(2), [[0, 0, 1, 1, 0, 1]]),
braille_trans("BLE", difficulty(2), [[0, 0, 1, 1, 1, 1]]),
# oldbrailledict_3 = {
# Lower Contractions
# Initial Groupsigns
braille_trans("BE", difficulty(3), [[0, 1, 1, 0, 0, 0]]),
braille_trans("COM", difficulty(3), [[0, 0, 1, 0, 0, 1]]),
braille_trans("CON", difficulty(3), [[0, 1, 0, 0, 1, 0]]),
braille_trans("DIS", difficulty(3), [[0, 1, 0, 0, 1, 1]]),
# Initial-Medial-Terminal Groupsigns
braille_trans("EN", difficulty(3), [[0, 1, 0, 0, 0, 1]]),
braille_trans("IN", difficulty(3), [[0, 0, 1, 0, 1, 0]]),
# Medial Groupsigns
braille_trans("EA", difficulty(3), [[0, 1, 0, 0, 0, 0]]),
braille_trans("BB", difficulty(3), [[0, 1, 1, 0, 0, 0]]),
braille_trans("CC", difficulty(3), [[0, 1, 0, 0, 1, 0]]),
braille_trans("DD", difficulty(3), [[0, 1, 0, 0, 1, 1]]),
braille_trans("FF", difficulty(3), [[0, 1, 1, 0, 1, 0]]),
braille_trans("GG", difficulty(3), [[0, 1, 1, 0, 1, 1]]),
# Wordsigns
braille_trans("ENOUGH", difficulty(3), [[0, 1, 0, 0, 0, 1]]),
braille_trans("TO", difficulty(3), [[0, 1, 1, 0, 1, 0]]),
braille_trans("WERE", difficulty(3), [[0, 1, 1, 0 , 1, 1]]),
braille_trans("HIS", difficulty(3), [[0, 1, 1, 0, 0, 1]]),
braille_trans("INTO", difficulty(3), [[0, 0, 1, 0, 1, 0], [0, 1, 1, 0, 1, 0]]), #(sequenced)
braille_trans("BY", difficulty(3), [[0, 0, 1, 0, 1, 1]]), #(sequenced)
braille_trans("WAS", difficulty(3), [[0, 0 , 1, 0 , 1, 1]]),
# Modifiers
braille_trans("@?LET", difficulty(3), [[0, 0, 0, 0, 1, 1]], "LET"),
braille_trans("@?CAPS", difficulty(3), [[0, 0, 0, 0, 0, 1]], "CAPS"),
braille_trans("@?EMPH", difficulty(3), [[0, 0, 0, 1, 0, 1]], "EMPH"),
]
# remove None 's - rejected inputs
valid = False
while not valid:
try:
temp_dict.remove(None)
except:
valid = True
braille_dict = pd.DataFrame([x.as_dict() for x in temp_dict]) # , columns=['key', 'level', 'msg', 'msg_prefix'])
# RETURNS
# print('Braille Dictionary Creation')
# print(f"type(temp_dict) = {type(temp_dict)}")
# print("temp_dict = ")
# for i in range(len(temp_dict)):
# print(f"{temp_dict[i]}")
# print('')
# print(f"type(braille_dict) = {type(braille_dict)}")
# print(f"braille_dict = {braille_dict}")
return braille_dict # temp_dict # braille_dict
def get_delimiters():
# FUNCTION
# delimiters and special character codes for plaintext message before braille translation
# VARIABLE INSTANTIATION
txtdict = {"@?NUM" : "NUMBER",
"@?NOTHING" : "",
#" " : "",
'"@?BO' : '"',
'"@?BC' : '"',
"-@?S" : "-",
"-@?L" : "-",
"/@?B" : "/",
"[@?BPH" : "[",
"]@?BPH" : "]",
"[@?BSQ" : "[",
"]@?BSQ" : "]",
"'@?BO" : "'",
"'@?BC" : "'",
"@?LET" : "LET",
"@?CAPS" : "CAPS",
"@?EMPH" : "EMPH",
"@?ABBREV1" : "ABBREV",
"@?ABBREV2" : "ABBREV",
"@?ABBREV3" : "ABBREV",
"@?ABBREV4" : "ABBREV",
}
# RETURNS
return txtdict
def gen_difficulty_msgstr(braille_dict, level: difficulty = difficulty(1)):
# FUNCTION
# generate keyboard message for specified difficulty
# ARGUMENTS
# list[braille_trans] braille_dict
# difficulty level
# ARGUMENT VALIDATION
_m = 'gen_difficulty_msgstr'
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', _m)
av.val_type(level, "<enum 'difficulty'>", 'level', _m)
# VARIABLE INSTANTIATION
str_out = ''
# n = len(braille_dict)
# METHODS
# print(f"len(braille_dict) = {n}")
# print(f"braille_dict.columns =")
# for i in braille_dict.columns:
# print(braille_dict.columns[i])
# temp_dict = braille_dict['key']
dict_iterator = braille_dict[braille_dict['level'] == level]
# print(f"dict_iterator.index = {dict_iterator.index}")
for bd_i in range(len(dict_iterator.index)):
bd_n = dict_iterator['key'][dict_iterator.index[bd_i]]
# print(f"bd_i = {bd_i}")
# print(f"bd_n = {bd_n}")
str_out += "@?NOTHING" + bd_n
# for i in range(n):
# bd_i = braille_dict.loc[i][0]
# # print(f"bd_i = {bd_i}")
# # print(f"type(bd_i) = {str(type(bd_i))}")
# if (bd_i.level == difficulty):
# str_out += "@?NOTHING" + bd_i.key
# RETURNS
return str_out
# def get_braille_by_key(braille_dict: pd.DataFrame, key: str):
# # FUNCTION
# # Find key in braille dictionary
# return None
# # ARGUMENTS
# # ARGUMENT VALIDATION
# # VARIABLE INSTANTIATION
# # METHODS
# # RETURNS
def input_product(braille_dict, products, my_option: Optional[int] = -1, my_select: Optional[str] = ''):
# FUNCTION
# Get product input from user - repeat until valid input received
# ARGUMENTS
# list[braille_trans] braile_dict
# list[product] products
# optional int my_option - if option provided in code
# ARGUMENT VALIDATION
_m = 'input_product'
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', _m)
av.val_list(products, 'products', _m, "<class 'translate_msg_2_braille.product'>", 1)
av.val_int(my_option, 'my_option', _m)
# VARIABLE INSTANTIATION
N = len(products)
select_i = my_option
valid = (my_option > 0 and my_option <= N)
# temp_dict = braille_dict['key']
# METHODS
if valid:
if my_option == N:
temp = braille_dict[braille_dict['key'] == my_select]
if len(temp.index) == 1:
products[N - 1].msg_prefix = my_select
else:
valid = False
while not valid:
print()
print('Welcome to your 3D Braille Model Generator')
print("At any time, answer the following error code to exit (excl. speech marks): '#!ERRORCODE!#'")
print()
print('Braille Products:')
for i in range(N):
print(f"{i + 1}. {products[i].name}")
print()
select_i = av.input_int(input(f"Please enter your selection (1 - {N}) from the products above\n"), 'select_i', _m, 1, N)
if select_i == '#!ERRORCODE!#':
sys.exit
valid = not (str(type(select_i)) == "<class 'NoneType'>")
if valid and select_i == N:
valid = False
while not valid:
select_A = input("Please enter a character selection for your Scrabble tile\n")
if select_A == '#!ERRORCODE!#':
sys.exit
temp = braille_dict[braille_dict['key'] == select_A].index
if not len(temp) == 1:
print(f"temp = {temp}")
valid = False
else:
valid = True
products[N - 1].msg_prefix = select_A
# RETURNS
return products[select_i - 1]
def append_ifnotNone(v_list, v_item):
# FUNCTION
# append v_item to v_list if v_item is not None
# ARGUMENTS
# list v_list
# v_item
# ARGUMENT VALIDATION
if (not av.val_list(v_list, 'v_list', 'append_ifnotNone', suppress_errors = True)) or v_item == None:
# RETURNS
return v_list
v_list.append(v_item)
return v_list#.append(v_item)
def gen_product_inputs(braille_dict):
# FUNCTION
# Generate product inputs
# ARGUMENTS
# [pandas.DataFrame] braille_dict - braille dictionary
# VARIABLE INSTANTIATION
products = []
# ARGUMENT VALIDATION
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', 'gen_product_inputs')
# METHODS
products.append(product("Extended Alphabet", 10, "abcdefg@?NOTHINGhijKLMNOPQRS@?NOTHINGTUVXYZANDFOROFTHEWITHCHGHSHTHWHEDEROUOWWEABBCCDDENFF?GGINBY"))
products.append(product("Upper Groupsigns", 10, "uppe@?nothingr GRO@?NOTHINGUPSIGNsand:a@?nothingn@?nothingd for:fo@?nothingr of:o@?nothingf the:t@?nothingh@?nothinge with:wi@?nothingt@?nothingh "+"@?NEWLINECH:C@?NOTHINGH " + "GH:G@?NOTHINGH " + "SH:S@?NOTHINGH " + "TH:T@?NOTHINGH " + "WH:W@?NOTHINGH " + "ED:E@?NOTHINGD " + "ER:E@?NOTHINGR " + "OU:O@?NOTHINGU " + "OW:O@?NOTHINGW "+"st:s@?nothingt ar:a@?nothingr ble:bl@?nothinge ing:i@?nothingng"))
products.append(product("Upper Wordsigns", 24, gen_difficulty_msgstr(braille_dict, difficulty(3))))
products.append(product("Alphabet", 10, "ABCDEFG@?NOTHINGHIJKLMNOPQRSTUVWXYZ"))
# products.append(product("Travel", 5, "ABCDEFG@?NOTHINGHIJ"))
products.append(product("Demo", 9, "BRAILLE"))
products.append(product("Scrabble Alphabet of Tiles", 1, '', filename = 'Scrabble_Tile_Set'))
products.append(product("Scrabble Character Tile", 1, '', filename = 'Scrabble_Tile'))
# RETURNS
return products
def gen_braille_inputs_4_openscad(msgin, line_length, brailledict): # , hyphenate = False
# FUNCTION
# Convert message to Braille for openSCAD generation
# ARGUMENTS
# str msgin - partially translated message containing only brailledict keys and blankspace
# int line_length - number of Braille characters per row on keyboard
# pandas.DataFrame brailledict - Braille translations with diffculty
# # bool hyphenate - hyphenate words that cross lines or start on new line
# ARGUMENT VALIDATION
_m = 'gen_braille_inputs_4_openscad'
av.val_str(msgin, 'msgin', _m, 1)
av.val_int(line_length, 'line_length', _m)
av.val_type(brailledict, "<class 'pandas.core.frame.DataFrame'>", 'brailledict', _m)
# VARIABLE INSTANTIATION
# dict txtdict - delimiters for Braille translation
msgin = msgin.upper()
braille = []
letters = []
n_rows = 1
start_of_word = 0 # position within cum
numbers = []
cum = [0, ] # 0-based cumulative starting position of Braille translation of message segments
#lmsg = [0] * len(msgin) # length of braille message
last_is_num = False
new_word = True
iter_lim = len(msgin)
print(f"iteration limit = {iter_lim}") #len(msgin))
msg_i_0 = 0
maxstrlen = max_key_len(brailledict)
# METHODS
print(f"msgin = {msgin}")
while (msg_i_0 < iter_lim):
found = False
print(f"msg_i_0 = {msg_i_0}")
for phrase_len in range(min(len(msgin) - msg_i_0, maxstrlen), 0, -1):
if found:
continue
phrase = msgin[msg_i_0 : msg_i_0 + phrase_len] # message segment to search for in Braille translation keys
print(f'phrase = {phrase}')
# generate braille if a code has been found
if (phrase_len == 0):
if (ord(phrase) >= 48 and ord(phrase) <= 57): # numbers
b_num_pre = brailledict[brailledict['key'] == "@?NUM"]['braille'].values[0]
b_num = brailledict[brailledict['key'] == ("J" if (ord(phrase) == 48) else chr(ord(phrase)+16))]['braille'].values[0]
if last_is_num == True:
braille[len(braille) - 1].append(b_num[0])
new_cum = 1
# temp = temp2
else:
braille.append([b_num_pre[0], b_num[0]])
new_cum = 2
# temp = [temp1[0], temp2[0]]
print('braille(numeric phrase) = ', braille[len(braille) - 1])
last_is_num = True
else:
# new_cum = len(brailledict[brailledict['key'] == phrase].index)
found = (len(brailledict[brailledict['key'] == phrase].index) == 1)
if found:
last_is_num = False
# temp = brailledict.get(phrase)
else:
# new_cum = len(brailledict[brailledict['key'] == phrase].index)
found = (len(brailledict[brailledict['key'] == phrase].index) == 1)
if found:
last_is_num = False
# temp = brailledict.get(phrase)
#print("tempsearch = ", temp)
# organise placement of braille phrase onto end of whole message
if found or last_is_num: # (temp != None): #
# found = True
# last_is_num = False
new_num = [-1]
if (len(phrase) == 1):
if (ord(phrase) >= 65 and ord(phrase) <= 90): # letters
new_num = [ord(phrase) - 64]
elif (ord(phrase) >= 48 and ord(phrase) <= 57): # numbers
new_num = [ord(phrase) - 48]
# last_is_num = True
if found:
braille.append(brailledict[brailledict['key'] == phrase]['braille'].values[0])
new_cum = len(braille[len(braille) - 1])
numbers.append(new_num)
new_cum = cum[len(cum) - 1] + new_cum
cum.append(new_cum)
n_rows_0 = n_lines_at_pos(cum[start_of_word], line_length)
n_rows_next = n_lines_at_pos(new_cum, line_length)
if ((not new_word) and n_rows_0 < n_rows_next and not (cum[start_of_word] % line_length == 0)):
delta_cum_new_line = n_rows_next * line_length + 1 - cum[start_of_word]
for msg_j in range(len(cum) - start_of_word - 1):
cum[start_of_word + msg_j] += delta_cum_new_line
#if (cum[len(cum)-1] % line_length > 0):
# cum[len(cum)-1] = cum[len(cum)-1] + line_length - (1+(cum[len(cum)-1]-1) % line_length)
# print("clean_rows",cum[len(cum)-1])
# print("phrase_len=",phrase_len)
msg_i_0 += phrase_len
letters.append(brailledict[brailledict['key'] == phrase]['plaintext'].values[0])
elif phrase == "@?NOTHING":
msg_i_0 += 9
print('found nothing')
found = True
elif phrase == "@?NEWLINE":
msg_i_0 += 9
print('forced newline')
cum[len(cum) - 1] += (line_length - (cum[len(cum) - 1] % line_length)) % line_length
found = True
new_word = True
elif phrase == " ": # and (cum[len(cum)-1] % line_length > 0)): # no space at start of line # or letters[len(cum)-1] == " " or msgin[ni+1] == " ")
msg_i_0 += 1
cum[len(cum) - 1] = cum[len(cum) - 1] + 1
print('space')
new_word = True
# unfound character??
if phrase_len == 0 and not (found or (ord(phrase) >= 48 and ord(phrase) <= 57)):
print(f"Unfound phrase: {phrase}")
msg_i_0 += 1
new_word = True
# word start position
if new_word:
start_of_word = len(cum) - 1 # position within cum
# OUTPUTS
# console output
n_keys = max(cum)
n_rows = n_rows_0
cum = cum[0 : len(cum) - 1]
# letters = letters[1:len(letters)] # why does element 0 exist?
# print(f"message length b = {n_keys}")
# print(f"braille = {braille}")
# print(f"cum = {cum}")
# print(f"numbers = {numbers}")
# print(f"letters = {letters}")
## file output
f = open('Braille.txt','a')
f.truncate()
f.write(f'cum = {str(cum)};\n')
f.write('msgstr = [')
for i in range(len(letters)):
f.write('"')
f.write(str(letters[i]))
if i < len(letters) - 1:
f.write('", ')
f.write('"];\n')
f.write('numbers = [')
for i in range(len(numbers)):
#f.write('"')
f.write(str(numbers[i]))
if i < len(numbers) - 1:
f.write(', ')
f.write('];\n')
f.write(f"inA = {str(braille)};\n")
f.write(f"lmsg = {str(len(braille))};\n")
f.write(f"N = {str(n_keys)};\n")
f.write(f"nln = {str(min(line_length, n_keys))};\n")
f.write(f"maxln = {str(n_rows)};\n")
f.close()
# RETURNS
return cum, letters, numbers, braille, n_keys, n_rows
def n_lines_at_pos(position, line_length):
# FUNCTION
# calculate number of rows of keyboard required for message of length (in Braille keys) position
# ARGUMENTS
# int position - quantity of Braille keys in message up to (+ incl.) position
# int line_length - number of Braille keys per line / row
# ARGUMENT VALIDATION
_m = 'n_lines_at_pos'
av.val_int(position, 'position', _m, 0)
av.val_int(line_length, 'line_length', _m, 1)
# RETURNS
return 1 + (position // line_length)
def max_key_len(mydict: pd.DataFrame, min_dict_len: Optional[int] = 1):
# FUNCTION
# find maximum key length in braille dictionary
# ARGUMENTS
# pandas.DataFrame mydict
# ARGUMENT VALIDATION
_m = 'max_key_len'
av.val_int(min_dict_len, 'min_dict_len', _m)
av.val_type(mydict, "<class 'pandas.core.frame.DataFrame'>", 'mydict', _m)
# VARIABLE INSTANTIATION
n = len(mydict.index)
max_len = 0
# METHODS
for i in range(n):
max_len = max(max_len, len(mydict.iloc[i]['key']))
if max_len < min_dict_len:
return -1
# RETURNS
return max_len
# ToDo: Finish this!
# def remove_words_in_word(word, maxstrlen=9):
# ln = len(word)
# minmax = min(ln, maxstrlen)
# fix = False
# skip = False
# for length in np.arange(minmax, 1, -1):
# for start in range(ln-length):
# tempstr = word[start:start+length]
# if (tempstr == "@?NOTHING"):
# skip = True
# if skip:
# continue
# tempfind = brailledict.get(tempstr)
# if not (tempbool == None):
# tempword = word[:start]
# for li in range(length):
# ## add "@?NOTHING"
# def get_translated_input(my_option: Optional[int] = -1): # REDUNDANT
# # FUNCTION
# # Get product selection input from user + convert to Braille
# # VARIABLE INSTANTIATION
# braille_translations = get_braille_translations()
# products = gen_product_inputs(braille_translations)
# delimiters = get_delimiters()
# # METHODS
# my_product = input_product(braille_translations, products, my_option)
# # cum, letters, numbers, braille, ltmsg, n_rows = gen_braille_inputs_4_openscad(my_product.msg, my_product.line_length, braille_translations, max_key_len(braille_translations), delimiters)
# # RETURNS
# return my_product, braille_translations, max_key_len(braille_translations), delimiters
# get_translated_input() ' requires translate_msg_2_braille is replaced by __main__ in type validation strings
# def process_old_dict(old_dict, difficulty):
# # FUNCTION
# # create new list of braille_trans dataclass items
# # ARGUMENTS
# # old_dict - old dictionary of keys, values
# # difficulty - level field of dataclass
# # ARGUMENT VALIDATION
# print(f"type(old_dict) = {type(old_dict)}")
# print(f"type(difficulty) = {type(difficulty)}")
# # VARIABLE INSTANTIATION
# new_dict = []
# # METHODS
# for i in range(len(old_dict)):
# temp_key, temp_value = old_dict.popitem()
# new_dict.append(braille_trans(temp_key, difficulty, temp_value))
# # RETURNS
# return new_dict
# class braille_dictionary():
# def __init__(self, keys, hardnesses, braille_translations):
# return self.push(keys, hardnesses, braille_translations)
# def push(self, keys, hardnesses, braille_translations):
# N_in = len(keys)
# if not (N_in == len(hardnesses) == len(braille_translations)):
# return False
# for i in range(N_in - 1):
# for j in range(i + 1):
# if (keys[i + 1] == keys[j]):
# return False
# for i in range(N_in):
# self.keys.append(keys[i])
# self.hards.append(hardnesses[i])
# self.brailles.append(braille_translations[i])
# return True
# def exists_key(self, key):
# try:
# i = self.keys.index(key)
# except ValueError:
# return True
# else:
# return False
# def get_key_index(self, key):
# if self.exists_key(key):
# return self.keys.index(key)
# else:
# return -1

View File

@@ -0,0 +1,801 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 24 14:26:02 2023
@author: Edward Middleton-Smith
Braille 3D Model Product Creation
Braille Dictionary Conversion / Creation
Plaintext message translation into Braille for 3D modelling
"""
# CLASSES
# ATTRIBUTE DECLARATION
# METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# ATTRIBUTE + VARIABLE INSTANTIATION
# METHODS
# RETURNS
# NORMAL METHODS
# FUNCTION
# ARGUMENTS
# ARGUMENT VALIDATION
# VARIABLE INSTANTIATION
# METHODS
# RETURNS
import pandas as pd
from typing import Optional
from enum import Enum
import argument_validation as av
import sys
class difficulty(Enum):
ALPHABETPUNCTUATION = 1
SIMPLEWORDGROUPSIGNS = 2
LOWERCONTRACTIONS = 3
def mini():
# FUNCTION
# Get minimum value in enumerator
# RETURNS
return min([e.value for e in difficulty])
def maxi():
# FUNCTION
# Get maximum value in enumerator
# RETURNS
return max([e.value for e in difficulty])
class braille_trans():
# ATTRIBUTE DECLARATION
key: str # search key in input messages for Braille translation - includes additional characters for literal processing
level: difficulty # stage of learning at which this translation is discovered
braille: list # list[list[int]] # Braille translation of plaintext
plaintext: str # English plaintext key
# METHODS
# def argvalinit(key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# # run before instantiating braille_trans
# # av.val_list(braille, 'list')=
# # _m = 'braille_trans.argvalinit'
# # if not av.val_str(key, 'key', method, min_len = -1, max_len = -1, suppress_errors = False, suppress_console_outputs = False, v_arg_type = 'argument')
# if not (av.val_str(key) and (str(type(level)) == "<enum 'difficulty'>" or av.val_int(level, difficulty.mini(), difficulty.maxi())) and av.val_list(braille, "<class 'list'>") and (av.val_str(plaintext, -1, -1, True) or plaintext == None)):
# print(f'Invalid braille_trans instantiation. key = {key}, level = {level}, braille = {braille}, plaintext = {plaintext}')
# return None
# return braille_trans(key, level, braille, plaintext)
def __new__(cls, key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str key
# difficulty level
# list[list[int]] braille
# optional str plaintext
# VARIABLE DECLARATION
_m = 'braille_trans.__new__'
v_arg_type = 'class attribute'
# ARGUMENT VALIDATION
av.val_str(key, 'key', _m, 1, -1, v_arg_type = v_arg_type)
av.val_type(level, "<enum 'difficulty'>", 'level', _m, v_arg_type = v_arg_type)
av.val_nested_list(braille, 0, 1, 'braille', _m, "<class 'int'>", -1, [-1, 6], -1, [-1, 6], v_arg_type = v_arg_type)
if not (av.val_str(plaintext, 'plaintext', _m, -1, -1, True, True, v_arg_type) or str(type(plaintext)) == "<class 'NoneType'>"):
raise ValueError(av.error_msg_str(_m, 'plaintext', plaintext, "<class 'str'>", v_arg_type = v_arg_type))
# if not av.val_str(key):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'key', key, 'attribute'))
# if not av.val_type(level, "<enum 'difficulty'>"):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'level', level, 'attribute'))
# if not av.val_nested_list(braille, 0, 2, "<class 'int'>", 6, [1, 6], 6, [-1, 6]):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'braille', braille, 'attribute'))
# if not (av.val_str(plaintext) or str(type(plaintext)) == "<class 'NoneType'>"):
# raise ValueError(av.error_msg_str('braille_trans.__new__', 'plaintext', plaintext, 'attribute'))
# RETURNS
return super(braille_trans, cls).__new__(cls)
def __init__(self, key: str, level: difficulty, braille: list, plaintext: Optional[str] = None):
# FUNCTION
# Construct class object
# ARGUMENTS
# str key
# difficulty level
# list[list[int]] braille
# optional str plaintext
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE + VARIABLE INSTANTIATION
self.key = key
self.level = level
self.braille = braille
self.plaintext = self.key if (plaintext is None) else plaintext
def __repr__(self):
return f"key = {self.key}, level = {self.level}, braille = {self.braille}, plaintext = {self.plaintext}"
# def query_lvl(self):
# return ' & '.join(["{}=='{}'".format(key, value)
# for key, value in self.__dict__.items()
# if not value is None])
def as_dict(self):
return {'key': self.key, 'level': self.level, 'braille': self.braille, 'plaintext': self.plaintext}
class product():
# ATTRIBUTE DECLARATION
name: str
line_length: int # number of Braille characters per line on keyboard
msg: str # pre-translated English (with necessary modifications for input to this programme e.g. splitting up undesired translations with hidden delimiter character @?NOTHING)
msg_prefix: str # additional pre-translated str as above to pre-append to product for adding header to creation of product messages from dictionary queries
filename: str # filename - name without spaces
# METHODS
# def argvalinit(name: str, line_length: int, msg: str, msg_prefix: Optional[str] = ''):
# # run before instantiating product
# if not (av.val_str(name) and av.val_int(line_length, 0) and av.val_str(msg) and av.val_str(msg_prefix)):
# print(f'Invalid product instantiation. name = {name}, line_length = {line_length}, msg = {msg}, msg_prefix = {msg_prefix}')
# return None
# return product(name, line_length, msg, msg_prefix)
def __new__(cls, name, line_length, msg, msg_prefix = ''):
# FUNCTION
# Initialise class object
# ARGUMENTS
# str name
# int line_length
# str msg
# str msg_prefix
# ARGUMENT VALIDATION
_m = 'product.__new__'
v_arg_type = 'class attribute'
av.val_str(name, 'name', _m, 1, -1, v_arg_type = v_arg_type)
av.val_int(line_length, 'line_length', _m, 1, v_arg_type = v_arg_type)
av.val_str(msg, 'msg', _m, -1, -1, v_arg_type = v_arg_type)
av.val_str(msg_prefix, 'msg_prefix', _m, -1, -1, v_arg_type = v_arg_type)
# if not av.val_str(name):
# raise ValueError(av.error_msg_str('product.__new__', 'name', name, 'attribute'))
# if not av.val_int(line_length, 1):
# raise ValueError(av.error_msg_str('product.__new__', 'line_length', line_length, 'attribute'))
# if not av.val_str(msg):
# raise ValueError(av.error_msg_str('product.__new__', 'msg', msg, 'attribute'))
# if not av.val_str(msg_prefix):
# raise ValueError(av.error_msg_str('product.__new__', 'msg_prefix', msg_prefix, 'attribute'))
# RETURNS
return super(product, cls).__new__(cls)
def __init__(self, name: str, line_length: int, msg: str, msg_prefix: Optional[str] = ''):
# FUNCTION
# Construct class object
# ARGUMENTS
# str name
# int line_length
# str msg
# str msg_prefix
# ARGUMENT VALIDATION
# see __new__()
# ATTRIBUTE + VARIABLE INSTANTIATION
self.name = name
self.line_length = line_length
self.msg = msg
self.msg_prefix = msg_prefix # for procedurally-generated messages from difficulty selection
self.filename = name.replace(' ', '_')
def __repr__(self):
return f"name = {self.name}, line_length = {self.line_length}, msg = {self.msg}, msg_prefix = {self.msg_prefix}, filename = {self.filename}"
def get_braille_translations():
# FUNCTION
# return list of braille translations
# longer keys get priority in translation
# VARIABLE INSTANTIATION
temp_dict = [braille_trans("A", difficulty(1), [[1, 0, 0, 0, 0, 0]]),
braille_trans("B", difficulty(1), [[1, 1, 0, 0, 0, 0]]),
braille_trans("C", difficulty(1), [[1, 0, 0, 1, 0, 0]]),
braille_trans("D", difficulty(1), [[1, 0, 0, 1, 1, 0]]),
braille_trans("E", difficulty(1), [[1, 0, 0, 0, 1, 0]]),
braille_trans("F", difficulty(1), [[1, 1, 0, 1, 0, 0]]),
braille_trans("G", difficulty(1), [[1, 1, 0, 1, 1, 0]]),
braille_trans("H", difficulty(1), [[1, 1, 0, 0, 1, 0]]),
braille_trans("I", difficulty(1), [[0, 1, 0, 1, 0, 0]]),
braille_trans("J", difficulty(1), [[0, 1, 0, 1, 1, 0]]),
braille_trans("K", difficulty(1), [[1, 0, 1, 0, 0, 0]]),
braille_trans("L", difficulty(1), [[1, 1, 1, 0, 0, 0]]),
braille_trans("M", difficulty(1), [[1, 0, 1, 1, 0, 0]]),
braille_trans("N", difficulty(1), [[1, 0, 1, 1, 1, 0]]),
braille_trans("O", difficulty(1), [[1, 0, 1, 0, 1, 0]]),
braille_trans("P", difficulty(1), [[1, 1, 1, 1, 0, 0]]),
braille_trans("Q", difficulty(1), [[1, 1, 1, 1, 1, 0]]),
braille_trans("R", difficulty(1), [[1, 1, 1, 0, 1, 0]]),
braille_trans("S", difficulty(1), [[0, 1, 1, 1, 0, 0]]),
braille_trans("T", difficulty(1), [[0, 1, 1, 1, 1, 0]]),
braille_trans("U", difficulty(1), [[1, 0, 1, 0, 0, 1]]),
braille_trans("V", difficulty(1), [[1, 1, 1, 0, 0, 1]]),
braille_trans("W", difficulty(1), [[0, 1, 0, 1, 1, 1]]),
braille_trans("X", difficulty(1), [[1, 0, 1, 1, 0, 1]]),
braille_trans("Y", difficulty(1), [[1, 0, 1, 1, 1, 1]]),
braille_trans("Z", difficulty(1), [[1, 0, 1, 0, 1, 1]]),
braille_trans("@?NUM", difficulty(1), [[0, 0, 1, 1, 1, 1]], 'NUMBER'),
#" ", difficulty(1), [[0, 0, 0, 0, 0, 0]]),
braille_trans(",", difficulty(1), [[0, 1, 0, 0, 0, 0]]),
braille_trans(";", difficulty(1), [[0, 1, 1, 0, 0, 0]]),
braille_trans(":", difficulty(1), [[0, 1, 0, 0, 1, 0]]),
braille_trans(".", difficulty(1), [[0, 1, 0, 0, 1, 1]]),
braille_trans("!", difficulty(1), [[0, 1, 1, 0, 1, 0]]),
braille_trans("(", difficulty(1), [[0, 1, 1, 0, 1, 1]]),
braille_trans(")", difficulty(1), [[0, 1, 1, 0, 1, 1]]),
braille_trans("?", difficulty(1), [[0, 1, 1, 0, 0, 1]]),
braille_trans('"@?BO', difficulty(1), [[0, 1, 1, 0, 0, 1]], '"'),
braille_trans('"@?BC', difficulty(1), [[0, 0, 1, 0, 1, 1]], '"'),
braille_trans("'", difficulty(1), [[0, 0, 1, 0, 0, 0]]),
braille_trans("@?ABBREV1", difficulty(1), [[0, 0, 0, 1, 0, 0]], "ABBREV"),
braille_trans("@?ABBREV2", difficulty(1), [[0, 0, 0, 1, 1, 0]], "ABBREV"),
braille_trans("@?ABBREV3", difficulty(1), [[0, 0, 0, 1, 1, 1]], "ABBREV"),
braille_trans("@?ABBREV4", difficulty(1), [[0, 0, 0, 0, 1, 0]], "ABBREV"),
braille_trans("...", difficulty(1), [[0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0]]),
braille_trans("-", difficulty(1), [[0, 0, 1, 0, 0, 1]]),
braille_trans("-@?S", difficulty(1), [[0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1]], "-"),
braille_trans("-@?L", difficulty(1), [[0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1]], "-"),
braille_trans("/@?B", difficulty(1), [[0, 0, 0, 1, 0, 0], [0, 1, 1, 0, 1, 1]], "/"),
braille_trans("\@?B", difficulty(1), [[0, 0, 0, 1, 0, 0], [0, 1, 1, 0, 1, 1]], "\\"),
braille_trans("[@?BPH", difficulty(1), [[0, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1]], "["),
braille_trans("]@?BPH", difficulty(1), [[0, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1]], "]"),
braille_trans("<", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans(">", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("/", difficulty(1), [[0, 0, 0, 1, 1, 1], [0, 0, 1, 1, 0, 0]]),
braille_trans("{", difficulty(1), [[0, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("}", difficulty(1), [[0, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 1]]),
braille_trans("[@?BSQ", difficulty(1), [[0, 0, 0, 0, 0, 1], [0, 1, 1, 0, 1, 1]], "["),
braille_trans("]@?BSQ", difficulty(1), [[0, 1, 1, 0, 1, 1], [0, 0, 0, 0, 0, 1]], "]"),
braille_trans("'@?BO", difficulty(1), [[0, 0, 0, 0, 0, 1], [0, 1, 1, 0, 0, 1]], "'"),
braille_trans("'@?BC", difficulty(1), [[0, 1, 1, 0, 0, 1], [0, 0, 0, 0, 0, 1]], "'"),
# oldbrailledict_2 = {
# Simple Upper Wordsigns
braille_trans("BUT", difficulty(2), [[1, 1, 0, 0, 0, 0]]),
braille_trans("CAN", difficulty(2), [[1, 0, 0, 1, 0, 0]]),
braille_trans("DO", difficulty(2), [[1, 0, 0, 1, 1, 0]]),
braille_trans("EVERY", difficulty(2), [[1, 0, 0, 0, 1, 0]]),
braille_trans("FROM", difficulty(2), [[1, 1, 0, 1, 0, 0]]),
braille_trans("GO", difficulty(2), [[1, 1, 0, 1, 1, 0]]),
braille_trans("HAVE", difficulty(2), [[1, 1, 0, 0, 1, 0]]),
braille_trans("JUST", difficulty(2), [[0, 1, 0, 1, 1, 0]]),
braille_trans("KNOWLEDGE", difficulty(2), [[1, 0, 1, 0, 0, 0]]),
braille_trans("LIKE", difficulty(2), [[1, 1, 1, 0, 0, 0]]),
braille_trans("MORE", difficulty(2), [[1, 0, 1, 1, 0, 0]]),
braille_trans("NOT", difficulty(2), [[1, 0, 1, 1, 1, 0]]),
braille_trans("PEOPLE", difficulty(2), [[1, 1, 1, 1, 0, 0]]),
braille_trans("QUITE", difficulty(2), [[1, 1, 1, 1, 1, 0]]),
braille_trans("RATHER", difficulty(2), [[1, 1, 1, 0, 1, 0]]),
braille_trans("SO", difficulty(2), [[0, 1, 1, 1, 0, 0]]),
braille_trans("THAT", difficulty(2), [[0, 1, 1, 1, 1, 0]]),
braille_trans("US", difficulty(2), [[1, 0, 1, 0, 0, 1]]),
braille_trans("VERY", difficulty(2), [[1, 1, 1, 0, 0, 1]]),
braille_trans("WILL", difficulty(2), [[0, 1, 0, 1, 1, 1]]),
braille_trans("IT", difficulty(2), [[1, 0, 1, 1, 0, 1]]),
braille_trans("YOU", difficulty(2), [[1, 0, 1, 1, 1, 1]]),
braille_trans("AS", difficulty(2), [[1, 0, 1, 0, 1, 1]]),
braille_trans("CHILD", difficulty(2), [[1, 0, 0, 0, 0, 1]]),
braille_trans("SHALL", difficulty(2), [[1, 0, 0, 1, 0, 1]]),
braille_trans("THIS", difficulty(2), [[1, 0, 0, 1, 1, 1]]),
braille_trans("WHICH", difficulty(2), [[1, 0, 0, 0, 1, 1]]),
braille_trans("OUT", difficulty(2), [[1, 1, 0, 0, 1, 1]]),
braille_trans("STILL", difficulty(2), [[0, 0, 1, 1, 0, 0]]),
# Simple Upper Groupsigns
braille_trans("AND", difficulty(2), [[1, 1, 1, 1, 0, 1]]),
braille_trans("FOR", difficulty(2), [[1, 1, 1, 1, 1, 1]]),
braille_trans("OF", difficulty(2), [[1, 1, 1, 0, 1, 1]]),
braille_trans("THE", difficulty(2), [[0, 1, 1, 1, 0, 1]]),
braille_trans("WITH", difficulty(2), [[0, 1, 1, 1, 1, 1]]),
braille_trans("CH", difficulty(2), [[1, 0, 0, 0, 0, 1]]),
braille_trans("GH", difficulty(2), [[1, 1, 0, 0, 0, 1]]),
braille_trans("SH", difficulty(2), [[1, 0, 0, 1, 0, 1]]),
braille_trans("TH", difficulty(2), [[1, 0, 0, 1, 1, 1]]),
braille_trans("WH", difficulty(2), [[1, 0, 0, 0, 1, 1]]),
braille_trans("ED", difficulty(2), [[1, 1, 0, 1, 0, 1]]),
braille_trans("ER", difficulty(2), [[1, 1, 0, 1, 1, 1]]),
braille_trans("OU", difficulty(2), [[1, 1, 0, 0, 1, 1]]),
braille_trans("OW", difficulty(2), [[0, 1, 0, 1, 0, 1]]),
braille_trans("ST", difficulty(2), [[0, 0, 1, 1, 0, 0]]),
braille_trans("AR", difficulty(2), [[0, 0, 1, 1, 1, 0]]),
braille_trans("ING", difficulty(2), [[0, 0, 1, 1, 0, 1]]),
braille_trans("BLE", difficulty(2), [[0, 0, 1, 1, 1, 1]]),
# oldbrailledict_3 = {
# Lower Contractions
# Initial Groupsigns
braille_trans("BE", difficulty(3), [[0, 1, 1, 0, 0, 0]]),
braille_trans("COM", difficulty(3), [[0, 0, 1, 0, 0, 1]]),
braille_trans("CON", difficulty(3), [[0, 1, 0, 0, 1, 0]]),
braille_trans("DIS", difficulty(3), [[0, 1, 0, 0, 1, 1]]),
# Initial-Medial-Terminal Groupsigns
braille_trans("EN", difficulty(3), [[0, 1, 0, 0, 0, 1]]),
braille_trans("IN", difficulty(3), [[0, 0, 1, 0, 1, 0]]),
# Medial Groupsigns
braille_trans("EA", difficulty(3), [[0, 1, 0, 0, 0, 0]]),
braille_trans("BB", difficulty(3), [[0, 1, 1, 0, 0, 0]]),
braille_trans("CC", difficulty(3), [[0, 1, 0, 0, 1, 0]]),
braille_trans("DD", difficulty(3), [[0, 1, 0, 0, 1, 1]]),
braille_trans("FF", difficulty(3), [[0, 1, 1, 0, 1, 0]]),
braille_trans("GG", difficulty(3), [[0, 1, 1, 0, 1, 1]]),
# Wordsigns
braille_trans("ENOUGH", difficulty(3), [[0, 1, 0, 0, 0, 1]]),
braille_trans("TO", difficulty(3), [[0, 1, 1, 0, 1, 0]]),
braille_trans("WERE", difficulty(3), [[0, 1, 1, 0 , 1, 1]]),
braille_trans("HIS", difficulty(3), [[0, 1, 1, 0, 0, 1]]),
braille_trans("INTO", difficulty(3), [[0, 0, 1, 0, 1, 0], [0, 1, 1, 0, 1, 0]]), #(sequenced)
braille_trans("BY", difficulty(3), [[0, 0, 1, 0, 1, 1]]), #(sequenced)
braille_trans("WAS", difficulty(3), [[0, 0 , 1, 0 , 1, 1]]),
# Modifiers
braille_trans("@?LET", difficulty(3), [[0, 0, 0, 0, 1, 1]], "LET"),
braille_trans("@?CAPS", difficulty(3), [[0, 0, 0, 0, 0, 1]], "CAPS"),
braille_trans("@?EMPH", difficulty(3), [[0, 0, 0, 1, 0, 1]], "EMPH"),
]
# remove None 's - rejected inputs
valid = False
while not valid:
try:
temp_dict.remove(None)
except:
valid = True
braille_dict = pd.DataFrame([x.as_dict() for x in temp_dict]) # , columns=['key', 'level', 'msg', 'msg_prefix'])
# RETURNS
# print('Braille Dictionary Creation')
# print(f"type(temp_dict) = {type(temp_dict)}")
# print("temp_dict = ")
# for i in range(len(temp_dict)):
# print(f"{temp_dict[i]}")
# print('')
# print(f"type(braille_dict) = {type(braille_dict)}")
# print(f"braille_dict = {braille_dict}")
return braille_dict # temp_dict # braille_dict
def get_delimiters():
# FUNCTION
# delimiters and special character codes for plaintext message before braille translation
# VARIABLE INSTANTIATION
txtdict = {"@?NUM" : "NUMBER",
"@?NOTHING" : "",
#" " : "",
'"@?BO' : '"',
'"@?BC' : '"',
"-@?S" : "-",
"-@?L" : "-",
"/@?B" : "/",
"[@?BPH" : "[",
"]@?BPH" : "]",
"[@?BSQ" : "[",
"]@?BSQ" : "]",
"'@?BO" : "'",
"'@?BC" : "'",
"@?LET" : "LET",
"@?CAPS" : "CAPS",
"@?EMPH" : "EMPH",
"@?ABBREV1" : "ABBREV",
"@?ABBREV2" : "ABBREV",
"@?ABBREV3" : "ABBREV",
"@?ABBREV4" : "ABBREV",
}
# RETURNS
return txtdict
def gen_difficulty_msgstr(braille_dict, level: difficulty = difficulty(1)):
# FUNCTION
# generate keyboard message for specified difficulty
# ARGUMENTS
# list[braille_trans] braille_dict
# difficulty level
# ARGUMENT VALIDATION
_m = 'gen_difficulty_msgstr'
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', _m)
av.val_type(level, "<enum 'difficulty'>", 'level', _m)
# VARIABLE INSTANTIATION
str_out = ''
# n = len(braille_dict)
# METHODS
# print(f"len(braille_dict) = {n}")
# print(f"braille_dict.columns =")
# for i in braille_dict.columns:
# print(braille_dict.columns[i])
# temp_dict = braille_dict['key']
dict_iterator = braille_dict[braille_dict['level'] == level]
print(f"dict_iterator.index = {dict_iterator.index}")
for bd_i in range(len(dict_iterator.index)):
bd_n = dict_iterator['key'][dict_iterator.index[bd_i]]
# print(f"bd_i = {bd_i}")
# print(f"bd_n = {bd_n}")
str_out += "@?NOTHING" + bd_n
# for i in range(n):
# bd_i = braille_dict.loc[i][0]
# # print(f"bd_i = {bd_i}")
# # print(f"type(bd_i) = {str(type(bd_i))}")
# if (bd_i.level == difficulty):
# str_out += "@?NOTHING" + bd_i.key
# RETURNS
return str_out
# def get_braille_by_key(braille_dict: pd.DataFrame, key: str):
# # FUNCTION
# # Find key in braille dictionary
# return None
# # ARGUMENTS
# # ARGUMENT VALIDATION
# # VARIABLE INSTANTIATION
# # METHODS
# # RETURNS
def input_product(braille_dict, products, my_option: Optional[int] = -1, my_select: Optional[str] = ''):
# FUNCTION
# Get product input from user - repeat until valid input received
# ARGUMENTS
# list[braille_trans] braile_dict
# list[product] products
# optional int my_option - if option provided in code
# ARGUMENT VALIDATION
_m = 'input_product'
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', _m)
av.val_list(products, 'products', _m, "<class 'translate_msg_2_braille.product'>", 1)
av.val_int(my_option, 'my_option', _m)
# VARIABLE INSTANTIATION
N = len(products)
select_i = my_option
valid = (my_option > 0 and my_option <= N)
# temp_dict = braille_dict['key']
# METHODS
if valid:
if my_option == N:
temp = braille_dict[braille_dict['key'] == my_select]
if len(temp.index) == 1:
products[N - 1].msg_prefix = my_select
else:
valid = False
while not valid:
print()
print('Welcome to your 3D Braille Model Generator')
print("At any time, answer the following error code to exit (excl. speech marks): '#!ERRORCODE!#'")
print()
print('Braille Products:')
for i in range(N):
print(f"{i + 1}. {products[i].name}")
print()
select_i = av.input_int(input(f"Please enter your selection (1 - {N}) from the products above\n"), 1, N)
if select_i == '#!ERRORCODE!#':
sys.exit
valid = not (str(type(select_i)) == "<class 'NoneType'>")
if valid and select_i == N:
valid = False
while not valid:
select_A = input("Please enter a character selection for your Scrabble tile\n")
if select_A == '#!ERRORCODE!#':
sys.exit
temp = braille_dict[braille_dict['key'] == select_A].index
if not len(temp) == 1:
print(f"temp = {temp}")
valid = False
else:
valid = True
products[N - 1].msg_prefix = select_A
# RETURNS
return products[select_i - 1]
def append_ifnotNone(v_list, v_item):
# FUNCTION
# append v_item to v_list if v_item is not None
# ARGUMENTS
# list v_list
# v_item
# ARGUMENT VALIDATION
if (not av.val_list(v_list, 'v_list', 'append_ifnotNone', suppress_errors = True)) or v_item == None:
# RETURNS
return v_list
v_list.append(v_item)
return v_list#.append(v_item)
def gen_product_inputs(braille_dict):
# FUNCTION
# Generate product inputs
# ARGUMENTS
# [pandas.DataFrame] braille_dict - braille dictionary
# VARIABLE INSTANTIATION
products = []
# ARGUMENT VALIDATION
av.val_type(braille_dict, "<class 'pandas.core.frame.DataFrame'>", 'braille_dict', 'gen_product_inputs')
# METHODS
products.append(product("Extended Alphabet", 10, "abcdefg@?NOTHINGhijKLMNOPQRS@?NOTHINGTUVXYZANDFOROFTHEWITHCHGHSHTHWHEDEROUOWWEABBCCDDENFF?GGINBY"))
products.append(product("Upper Groupsigns", 10, "uppe@?nothingr GRO@?NOTHINGUPSIGNsand:a@?nothingn@?nothingd for:fo@?nothingr of:o@?nothingf the:t@?nothingh@?nothinge with:wi@?nothingt@?nothingh "+"@?NEWLINECH:C@?NOTHINGH " + "GH:G@?NOTHINGH " + "SH:S@?NOTHINGH " + "TH:T@?NOTHINGH " + "WH:W@?NOTHINGH " + "ED:E@?NOTHINGD " + "ER:E@?NOTHINGR " + "OU:O@?NOTHINGU " + "OW:O@?NOTHINGW "+"st:s@?nothingt ar:a@?nothingr ble:bl@?nothinge ing:i@?nothingng"))
products.append(product("Upper Wordsigns", 24, gen_difficulty_msgstr(braille_dict, difficulty(3))))
products.append(product("Alphabet", 10, "ABCDEFG@?NOTHINGHIJKLMNOPQRSTUVWXYZ"))
products.append(product("Travel", 5, "ABCDEFG@?NOTHINGHIJ"))
products.append(product("Scrabble Alphabet of Tiles", 1, ''))
products.append(product("Scrabble Character Tile", 1, ''))
# RETURNS
return products
def gen_braille_inputs_4_openscad(msgin, line_length, brailledict): # , hyphenate = False
# FUNCTION
# Convert message to Braille for openSCAD generation
# ARGUMENTS
# str msgin - partially translated message containing only brailledict keys and blankspace
# int line_length - number of Braille characters per row on keyboard
# pandas.DataFrame brailledict - Braille translations with diffculty
# # bool hyphenate - hyphenate words that cross lines or start on new line
# ARGUMENT VALIDATION
_m = 'gen_braille_inputs_4_openscad'
av.val_str(msgin, 'msgin', _m, 1)
av.val_int(line_length, 'line_length', _m)
av.val_type(brailledict, "<class 'pandas.core.frame.DataFrame'>", 'brailledict', _m)
# VARIABLE INSTANTIATION
# dict txtdict - delimiters for Braille translation
msgin = msgin.upper()
braille = []
letters = ["", ]
n_rows = 1
start_of_word = 0 # position within cum
numbers = []
cum = [0] # 0-based cumulative starting position of Braille translation of message segments
#lmsg = [0] * len(msgin) # length of braille message
last_is_num = False
new_word = True
iter_lim = len(msgin)
print(f"iteration limit = {iter_lim}") #len(msgin))
msg_i_0 = -1
maxstrlen = max_key_len(brailledict)
# METHODS
print(f"msgin = {msgin}")
while (msg_i_0 < iter_lim):
msg_i_0 = msg_i_0 + 1
found = False
print(f"msg_i_0 = {msg_i_0}")
for phrase_len in range(min(len(msgin) - msg_i_0, maxstrlen), 0, -1):
if found:
continue
phrase = msgin[msg_i_0 : msg_i_0 + phrase_len] # message segment to search for in Braille translation keys
print(f'phrase = {phrase}')
# generate braille if a code has been found
if (phrase_len == 0):
if (ord(phrase) >= 48 and ord(phrase) <= 57): # numbers
b_num_pre = brailledict[brailledict['key'] == "@?NUM"]['braille'].values[0]
b_num = brailledict[brailledict['key'] == ("J" if (ord(phrase) == 48) else chr(ord(phrase)+16))]['braille'].values[0]
if last_is_num == True:
braille[len(braille) - 1].append(b_num[0])
new_cum = 1
# temp = temp2
else:
braille.append([b_num_pre[0], b_num[0]])
new_cum = 2
# temp = [temp1[0], temp2[0]]
print('braille(numeric phrase) = ', braille[len(braille) - 1])
last_is_num = True
else:
# new_cum = len(brailledict[brailledict['key'] == phrase].index)
found = (len(brailledict[brailledict['key'] == phrase].index) == 1)
if found:
last_is_num = False
# temp = brailledict.get(phrase)
else:
# new_cum = len(brailledict[brailledict['key'] == phrase].index)
found = (len(brailledict[brailledict['key'] == phrase].index) == 1)
if found:
last_is_num = False
# temp = brailledict.get(phrase)
#print("tempsearch = ", temp)
# organise placement of braille phrase onto end of whole message
if found or last_is_num: # (temp != None): #
# found = True
# last_is_num = False
new_num = [-1]
if (len(phrase) == 1):
if (ord(phrase) >= 65 and ord(phrase) <= 90): # letters
new_num = [ord(phrase) - 64]
elif (ord(phrase) >= 48 and ord(phrase) <= 57): # numbers
new_num = [ord(phrase) - 48]
# last_is_num = True
if found:
braille.append(brailledict[brailledict['key'] == phrase]['braille'].values[0])
new_cum = len(braille[len(braille) - 1])
numbers.append(new_num)
new_cum = cum[len(cum) - 1] + new_cum
cum.append(new_cum)
n_rows_0 = n_lines_at_pos(start_of_word, line_length)
n_rows_next = n_lines_at_pos(new_cum, line_length)
if (n_rows_0 < n_rows_next and not n_rows_0 % line_length == 0):
delta_cum_new_line = n_rows_next * line_length + 1 - cum[start_of_word]
for msg_j in range(len(cum) - start_of_word - 1):
cum[start_of_word + msg_j] += delta_cum_new_line
#if (cum[len(cum)-1] % line_length > 0):
# cum[len(cum)-1] = cum[len(cum)-1] + line_length - (1+(cum[len(cum)-1]-1) % line_length)
# print("clean_rows",cum[len(cum)-1])
# print("phrase_len=",phrase_len)
msg_i_0 += phrase_len - 1
letters.append(brailledict[brailledict['key'] == phrase]['plaintext'].values[0])
# temptxt = txtdict.get(phrase)
# if temptxt == None:
# letters.append(phrase)
# else:
# letters.append(temptxt)
elif phrase == "@?NOTHING":
msg_i_0 += 8 # 9
print('found nothing')
found = True
elif phrase == "@?NEWLINE":
msg_i_0 += 8 # 9
print('forced newline')
cum[len(cum) - 1] += line_length - 1 - ((cum[len(cum) - 1] - 1) % line_length)
found = True
start_of_word = True
elif phrase == " ": # and (cum[len(cum)-1] % line_length > 0)): # no space at start of line # or letters[len(cum)-1] == " " or msgin[ni+1] == " ")
# msg_i_0 += 1
cum[len(cum)-1] = cum[len(cum)-1] + 1
print('space')
start_of_word = True
# word start position
if new_word:
start_of_word = len(cum) - 1 # position within cum
# unfound character??
if phrase_len == 0 and not (found or (ord(phrase) >= 48 and ord(phrase) <= 57)):
print(f"Unfound phrase: {phrase}")
# OUTPUTS
# console output
n_keys = max(cum)
letters = letters[1:len(letters)] # why does element 0 exist?
# print(f"message length b = {n_keys}")
# print(f"braille = {braille}")
# print(f"cum = {cum}")
# print(f"numbers = {numbers}")
# print(f"letters = {letters}")
## file output
f = open('Braille.txt','a')
f.truncate()
f.write(f'cum = {str(cum)};\n')
f.write('msgstr = [')
for i in range(len(letters)):
f.write('"')
f.write(str(letters[i]))
if i < len(letters) - 1:
f.write('", ')
f.write('"];\n')
f.write('numbers = [')
for i in range(len(numbers)):
#f.write('"')
f.write(str(numbers[i]))
if i < len(numbers) - 1:
f.write(', ')
f.write('];\n')
f.write(f"inA = {str(braille)};\n")
f.write(f"lmsg = {str(len(braille))};\n")
f.write(f"N = {str(n_keys)};\n")
f.write(f"nln = {str(min(line_length, n_keys))};\n")
f.write(f"maxln = {str(n_rows)};\n")
f.close()
# RETURNS
return cum, letters, numbers, braille, n_keys, n_rows
def n_lines_at_pos(position, line_length):
# FUNCTION
# calculate number of rows of keyboard required for message of length (in Braille keys) position
# ARGUMENTS
# int position - quantity of Braille keys in message up to (+ incl.) position
# int line_length - number of Braille keys per line / row
# ARGUMENT VALIDATION
_m = 'n_lines_at_pos'
av.val_int(position, 'position', _m, 0)
av.val_int(line_length, 'line_length', _m, 1)
# RETURNS
return 1 + (position // line_length)
def max_key_len(mydict: pd.DataFrame, min_dict_len: Optional[int] = 1):
# FUNCTION
# find maximum key length in braille dictionary
# ARGUMENTS
# pandas.DataFrame mydict
# ARGUMENT VALIDATION
_m = 'max_key_len'
av.val_int(min_dict_len, 'min_dict_len', _m)
av.val_type(mydict, "<class 'pandas.core.frame.DataFrame'>", 'mydict', _m)
# VARIABLE INSTANTIATION
n = len(mydict.index)
max_len = 0
# METHODS
for i in range(n):
max_len = max(max_len, len(mydict.iloc[i]['key']))
if max_len < min_dict_len:
return -1
# RETURNS
return max_len
# ToDo: Finish this!
# def remove_words_in_word(word, maxstrlen=9):
# ln = len(word)
# minmax = min(ln, maxstrlen)
# fix = False
# skip = False
# for length in np.arange(minmax, 1, -1):
# for start in range(ln-length):
# tempstr = word[start:start+length]
# if (tempstr == "@?NOTHING"):
# skip = True
# if skip:
# continue
# tempfind = brailledict.get(tempstr)
# if not (tempbool == None):
# tempword = word[:start]
# for li in range(length):
# ## add "@?NOTHING"
# def get_translated_input(my_option: Optional[int] = -1): # REDUNDANT
# # FUNCTION
# # Get product selection input from user + convert to Braille
# # VARIABLE INSTANTIATION
# braille_translations = get_braille_translations()
# products = gen_product_inputs(braille_translations)
# delimiters = get_delimiters()
# # METHODS
# my_product = input_product(braille_translations, products, my_option)
# # cum, letters, numbers, braille, ltmsg, n_rows = gen_braille_inputs_4_openscad(my_product.msg, my_product.line_length, braille_translations, max_key_len(braille_translations), delimiters)
# # RETURNS
# return my_product, braille_translations, max_key_len(braille_translations), delimiters
# get_translated_input() ' requires translate_msg_2_braille is replaced by __main__ in type validation strings
# def process_old_dict(old_dict, difficulty):
# # FUNCTION
# # create new list of braille_trans dataclass items
# # ARGUMENTS
# # old_dict - old dictionary of keys, values
# # difficulty - level field of dataclass
# # ARGUMENT VALIDATION
# print(f"type(old_dict) = {type(old_dict)}")
# print(f"type(difficulty) = {type(difficulty)}")
# # VARIABLE INSTANTIATION
# new_dict = []
# # METHODS
# for i in range(len(old_dict)):
# temp_key, temp_value = old_dict.popitem()
# new_dict.append(braille_trans(temp_key, difficulty, temp_value))
# # RETURNS
# return new_dict
# class braille_dictionary():
# def __init__(self, keys, hardnesses, braille_translations):
# return self.push(keys, hardnesses, braille_translations)
# def push(self, keys, hardnesses, braille_translations):
# N_in = len(keys)
# if not (N_in == len(hardnesses) == len(braille_translations)):
# return False
# for i in range(N_in - 1):
# for j in range(i + 1):
# if (keys[i + 1] == keys[j]):
# return False
# for i in range(N_in):
# self.keys.append(keys[i])
# self.hards.append(hardnesses[i])
# self.brailles.append(braille_translations[i])
# return True
# def exists_key(self, key):
# try:
# i = self.keys.index(key)
# except ValueError:
# return True
# else:
# return False
# def get_key_index(self, key):
# if self.exists_key(key):
# return self.keys.index(key)
# else:
# return -1

11
requirements.txt Normal file
View File

@@ -0,0 +1,11 @@
# Requirements
pandas
numpy
prettytable
openpyscad
# built-in
# enum
# os
# sys
# typing

25
setup.py Normal file
View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Package and distribution management
# Learn more: {github_repo}
from setuptools import setup, find_packages
with open('README.rst') as f:
readme = f.read()
with open('LICENSE') as f:
license = f.read()
setup(
name='project/package name',
version='0.1.0',
description='Project/package description',
long_description=readme,
author='Edward Middleton-Smith',
author_email='edward.middletonsmith@gmail.com',
url='github_repo',
license=license,
packages=find_packages(exclude('tests', 'docs'))
)

17
tests/context.py Normal file
View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
"""
Created on Sun May 14 13:48:42 2023
@author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Project: Braille Model Generator
Feature: test context
"""
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import model_gen

15
tests/test_advanced.py Normal file
View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
"""
Created on Sun May 14 13:48:42 2023
@author: Edward Middleton-Smith
Company: Precision And Research Technology Systems Limited
Project: Braille Model Generator
Feature: advanced / comprehensive unit test procedure
"""
from .context import model_gen
model_gen.main.generate()

15
tests/test_basic.py Normal file
View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
"""
Created on Sun May 14 13:48:42 2023
@author: Edward Middleton-Smith
Company: Precision And Research Technology Systems Limited
Project: Braille Model Generator
Feature: basic unit test procedure
"""
from .context import model_gen
model_gen.main.generate(7, 'A')