550 lines
30 KiB
Python
550 lines
30 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
@author: Edward Middleton-Smith
|
|
"""
|
|
|
|
# import argument_validation as av
|
|
from colour_theme_braille_character import Colour_Theme_Character_Braille, BaseStyle
|
|
from openscad_objects import ModelOpenSCAD # get_openscad_colours
|
|
# from translate_msg_2_braille import Character_Braille
|
|
from character_braille import Character_Braille
|
|
from translation_braille import Translation_Braille, Enum_Braille_Proficiency_Level
|
|
from utils_system import render_openscad, make_openscad, exec_oscmd
|
|
|
|
import openpyscad as ops # Union, Difference
|
|
import numpy as np
|
|
from typing import Optional, List
|
|
from prettytable import PrettyTable
|
|
from enum import Enum
|
|
from pydantic import BaseModel, Field, ValidationError, validate_arguments, validator
|
|
# from color import Color
|
|
from builtins import staticmethod
|
|
import os
|
|
import string
|
|
from abc import ABC, abstractmethod
|
|
import inspect
|
|
|
|
|
|
"""
|
|
class EnumBaseStyleMeta(type(Enum), type(BaseStyle)):
|
|
pass
|
|
"""
|
|
class Enum_Visibility_Character_Braille(Enum): # BaseStyle, metaclass=EnumBaseStyleMeta):
|
|
EMBOSSED = -1
|
|
HIDDEN = 0
|
|
VISIBLE = 1
|
|
def minimum():
|
|
return min([e.value for e in Enum_Visibility_Character_Braille])
|
|
def maximum():
|
|
return max([e.value for e in Enum_Visibility_Character_Braille])
|
|
def get_text_filename(self):
|
|
return '_0' if (self == Enum_Visibility_Character_Braille.HIDDEN) else '__' if (self == Enum_Visibility_Character_Braille.EMBOSSED) else '_1'
|
|
|
|
class Style_Character_Braille(BaseModel, BaseStyle):
|
|
show_braille: Enum_Visibility_Character_Braille # = Enum_Visibility_Character_Braille.VISIBLE
|
|
show_letter: Enum_Visibility_Character_Braille # = Enum_Visibility_Character_Braille.VISIBLE
|
|
show_number: Enum_Visibility_Character_Braille # = Enum_Visibility_Character_Braille.VISIBLE
|
|
|
|
"""
|
|
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 get_text_filename(self):
|
|
return f"{self.show_braille.get_text_filename()}{self.show_letter.get_text_filename()}{self.show_number.get_text_filename()}"
|
|
|
|
@staticmethod
|
|
def get_default():
|
|
return Style_Character_Braille(show_braille=Enum_Visibility_Character_Braille.VISIBLE, show_letter=Enum_Visibility_Character_Braille.VISIBLE, show_number=Enum_Visibility_Character_Braille.VISIBLE)
|
|
|
|
@staticmethod
|
|
def get_defaults():
|
|
return [Style_Character_Braille.get_default()]
|
|
|
|
def as_row(self):
|
|
return [self.show_braille.name, self.show_letter.name, self.show_number.name]
|
|
"""
|
|
def input_from_console():
|
|
sizes = Size_Character_Braille.get_defaults()
|
|
count_sizes = len(sizes)
|
|
table_output = PrettyTable()
|
|
table_output.field_names = ['index', 'name', 'dot spacing', 'block height', 'character spacing', 'base height', 'dot height', 'dot bottom radius', 'dot top radius']
|
|
for index_size in range(count_sizes):
|
|
size_index = sizes[index_size]
|
|
table_output.add_row([index_size + 1] + size_index.as_row())
|
|
print()
|
|
print("Please select product dimensions configuration from below:")
|
|
print(table_output)
|
|
while True:
|
|
size_input = str(input("Product dimensions configuration (name or index): "))
|
|
print(size_input + " selected")
|
|
if size_input == "#!ERRORCODE!#": exit
|
|
for index_size in range(count_sizes):
|
|
if size_input == sizes[index_size].name or size_input == str(index_size + 1):
|
|
return sizes[index_size]
|
|
|
|
def input_many_from_console():
|
|
sizes_selected = []
|
|
print('Inputting many Size_Character_Braille objects')
|
|
print()
|
|
while True:
|
|
try:
|
|
count_sizes = int(input('Quantity of size objects to enter:'))
|
|
except: continue
|
|
for index_size in range(count_sizes):
|
|
print(f'Inputting size object {index_size + 1}')
|
|
size_new = Size_Character_Braille.input_from_console()
|
|
sizes_selected.append(size_new)
|
|
break
|
|
return sizes_selected
|
|
"""
|
|
|
|
def get_list_headings():
|
|
return ['show braille', 'show letter', 'show number']
|
|
|
|
class Size_Character_Braille(BaseModel, BaseStyle):
|
|
# ATTRIBUTE DECLARATION
|
|
name: str
|
|
spacing_dot: float = Field(ge = 0) # dp distance between dots
|
|
height_block: float = Field(ge = 0) # hblock height of
|
|
spacing_character: float = Field(ge = 0) # spacing between keys on keyboard
|
|
height_base: float = Field(ge = 0) # height of
|
|
height_dot: float = Field(ge = 0) # height of Braille dots
|
|
radius_bottom_dot: float = Field(ge = 0) # base radius of Braille dots
|
|
radius_top_dot : float = Field(ge = 0) # top radius of Braille dots
|
|
|
|
width_character_braille: float = 0
|
|
R_block_letter: List[float] = [0, 0, 0]
|
|
R_block_braille: List[float] = [0, 0, 0]
|
|
R_block_number: List[float] = [0, 0, 0]
|
|
size_font_alphabetic: float = 0
|
|
size_font_numeric: float = 0
|
|
sf_size_font_word_length: float = 0
|
|
sf_size_font_number_length: float = 0
|
|
|
|
def __init__(self, name, spacing_dot, height_block, spacing_character, height_base, height_dot, radius_bottom_dot, radius_top_dot):
|
|
BaseModel.__init__(self, name=name, spacing_dot=spacing_dot, height_block=height_block, spacing_character=spacing_character, height_base=height_base, height_dot=height_dot, radius_bottom_dot=radius_bottom_dot, radius_top_dot=radius_top_dot)
|
|
self.width_character_braille = self.spacing_dot + 2 * self.spacing_character + self.radius_bottom_dot * 2
|
|
self.R_block_letter = [self.width_character_braille, self.width_character_braille, self.height_block] # alphabet block dimensions [x, y]
|
|
self.R_block_braille = [self.width_character_braille, self.width_character_braille + self.spacing_dot, self.height_block] # braille block dimensions [x, y]
|
|
self.R_block_number = [self.width_character_braille, self.width_character_braille - 2 * self.spacing_character, self.height_block] #np.array(* i_s_num # number block dimensions [x, y] ' adjust to scalar coefficient rather than linear translation
|
|
|
|
self.size_font_alphabetic = self.R_block_letter[0] - 4 * self.spacing_character
|
|
self.size_font_numeric = self.size_font_alphabetic * 0.75
|
|
self.sf_size_font_word_length = 0.65 # scale factor for shrinking number text to fit more letters in single char space
|
|
self.sf_size_font_number_length = 0.75 # scale factor for shrinking message text to fit more letters in single char space
|
|
|
|
"""
|
|
# 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}, spacing_dot = {self.spacing_dot}, height_block = {self.height_block}, spacing_character = {self.spacing_character}, height_base = {self.height_base}, height_dot = {self.height_dot}, radius_bottom_dot = {self.radius_bottom_dot}, radius_top_dot = {self.radius_top_dot}"
|
|
|
|
def as_dict(self):
|
|
# FUNCTION
|
|
# Convert object attribute, value pairs to dictionary representation
|
|
# RETURNS
|
|
return {'name': self.name, 'spacing_dot': self.spacing_dot, 'height_block': self.height_block, 'spacing_character': self.spacing_character, 'height_base': self.height_base, 'height_dot': self.height_dot, 'radius_bottom_dot': self.radius_bottom_dot, 'radius_top_dot': self.radius_top_dot}
|
|
|
|
def as_row(self):
|
|
return [self.name, self.spacing_dot, self.height_block, self.spacing_character, self.height_base, self.height_dot, self.radius_bottom_dot, self.radius_top_dot]
|
|
|
|
def get_defaults():
|
|
k = 2.3622
|
|
s = 1
|
|
sizes = []
|
|
sizes.append(Size_Character_Braille('sz_1', 2.5, 2*s, s, 4*s, 1.2, 2/3, 1/2))
|
|
sizes.append(Size_Character_Braille('sz_2', 4, 1.28, s, 4*s, 1.2, 3/2, 1))
|
|
sizes.append(Size_Character_Braille('sz_3', 8, 2.5, s, 6*s, 1.2, 3/2, 1))
|
|
sizes.append(Size_Character_Braille('sz_4', 10, 3, 1, 6*s, 1.2, 3/2, 1))
|
|
sizes.append(Size_Character_Braille('sz_5', 10, 1, 1, 6*s, 1.2, 3/2, 1))
|
|
sizes.append(Size_Character_Braille('keyboard', 2.5, 0.8, 0.5, 4, 1.2, 2/3, 0.5))
|
|
sizes.append(Size_Character_Braille('poster', 2.5, 0.8, 0.5, 2, 1.2, 2/3, 0.5))
|
|
sizes.append(Size_Character_Braille('poster_big', 2.5*k, 0.8, 0.5*k, 2, 1.2, 2/3*k, 0.5*k))
|
|
# print('szs_scrabble')
|
|
return sizes
|
|
|
|
def get_default():
|
|
sizes_default = Size_Character_Braille.get_defaults()
|
|
return sizes_default['Character_Braille'].apply(lambda x: x if x.name == 'Keyboard' else None).dropna()[0]
|
|
|
|
"""
|
|
def input_from_console():
|
|
sizes = Size_Character_Braille.get_defaults()
|
|
count_sizes = len(sizes)
|
|
table_output = PrettyTable()
|
|
table_output.field_names = ['index', 'name', 'dot spacing', 'block height', 'character spacing', 'base height', 'dot height', 'dot bottom radius', 'dot top radius']
|
|
for index_size in range(count_sizes):
|
|
size_index = sizes[index_size]
|
|
table_output.add_row([index_size + 1] + size_index.as_row())
|
|
print()
|
|
print("Please select product dimensions configuration from below:")
|
|
print(table_output)
|
|
while True:
|
|
size_input = str(input("Product dimensions configuration (name or index): "))
|
|
print(size_input + " selected")
|
|
if size_input == "#!ERRORCODE!#": exit
|
|
for index_size in range(count_sizes):
|
|
if size_input == sizes[index_size].name or size_input == str(index_size + 1):
|
|
return sizes[index_size]
|
|
|
|
def input_many_from_console():
|
|
sizes_selected = []
|
|
print('Inputting many Size_Character_Braille objects')
|
|
print()
|
|
while True:
|
|
try:
|
|
count_sizes = int(input('Quantity of size objects to enter:'))
|
|
except: continue
|
|
for index_size in range(count_sizes):
|
|
print(f'Inputting size object {index_size + 1}')
|
|
size_new = Size_Character_Braille.input_from_console()
|
|
sizes_selected.append(size_new)
|
|
break
|
|
return sizes_selected
|
|
"""
|
|
def get_list_headings():
|
|
return ['name', 'dot spacing', 'block height', 'character spacing', 'base height', 'dot height', 'dot bottom radius', 'dot top radius']
|
|
"""
|
|
class Utils_Size_Character_Braille:
|
|
@staticmethod
|
|
@validate_arguments
|
|
def is_valid_size_input(size_input: str, sizes_valid: List[Size_Character_Braille]):
|
|
count_sizes_valid = len(sizes_valid)
|
|
for i_size_valid in range(count_sizes_valid):
|
|
if size_input == sizes_valid[i_size_valid].name:
|
|
return True
|
|
return False
|
|
"""
|
|
|
|
|
|
class Enum_Justification_Text(Enum):
|
|
LEFT = 0
|
|
CENTRE = 1
|
|
RIGHT = 2
|
|
def minimum():
|
|
return min([e.value for e in Enum_Visibility_Character_Braille])
|
|
def maximum():
|
|
return max([e.value for e in Enum_Visibility_Character_Braille])
|
|
def input_from_console(cls):
|
|
print("Please select justification for text:")
|
|
print("0. Left")
|
|
print("1. Centre")
|
|
print("2. Right")
|
|
while True:
|
|
justification_input = input("Justification (0, 1, 2): ")
|
|
print(str(justification_input) + " selected")
|
|
if justification_input == "#!ERRORCODE!#": exit
|
|
try:
|
|
justification_input = int(justification_input)
|
|
except: continue
|
|
# if justification_input is not int: continue
|
|
if justification_input < Enum_Justification_Text.minimum() or justification_input > Enum_Justification_Text.maximum(): continue
|
|
return Enum_Justification_Text(justification_input)
|
|
def get_default():
|
|
return Enum_Justification_Text(0)
|
|
|
|
def input_many_from_console():
|
|
return BaseStyle.input_many_from_console(Enum_Justification_Text)
|
|
|
|
class Keyboard_3D(ModelOpenSCAD): #, BaseModel):
|
|
size_characters: Size_Character_Braille
|
|
style_characters: Style_Character_Braille
|
|
colour_theme: Colour_Theme_Character_Braille
|
|
justification_text: Enum_Justification_Text
|
|
max_characters_per_row: int
|
|
translation: Translation_Braille # List[List[Character_Braille]]
|
|
# fn: int = Field(ge=0, default=25)
|
|
|
|
# filename: str = ''
|
|
|
|
def __init__(self, **kwargs): # , size_characters, style_characters, colour_theme, justification_text, path_dir, max_characters_per_row, translation, fn=25, filename=''):
|
|
# print(f'size_characters, style_characters, colour_theme, justification_text, path_dir, max_characters_per_row, translation, fn, filename: {size_characters, style_characters, colour_theme, justification_text, path_dir, max_characters_per_row, translation, fn, filename}')
|
|
# BaseModel.__init__(self, size_characters=size_characters, style_characters=style_characters, colour_theme=colour_theme, justification_text=justification_text, path_dir=path_dir, max_characters_per_row=max_characters_per_row, translation=translation, fn=fn, filename=filename)
|
|
# BaseModel.__init__(self, size_characters=size_characters, style_characters=style_characters, justification_text=justification_text, max_characters_per_row=max_characters_per_row, translation=translation, filename='')
|
|
# self.filename = self.get_filename()
|
|
ModelOpenSCAD.__init__(self, **{**kwargs, 'filename': '', 'model': None}) # , path_dir=path_dir, filename=filename, colour_theme=colour_theme, fn=fn)
|
|
# BaseModel.__init__(self, size_characters=size_characters, style_characters=style_characters, justification_text=justification_text, max_characters_per_row=max_characters_per_row, translation=translation)
|
|
# BaseModel.__init__(self, **kwargs) # , size_characters=size_characters, style_characters=style_characters, colour_theme=colour_theme, justification_text=justification_text, path_dir=path_dir, max_characters_per_row=max_characters_per_row, translation=translation, fn=fn, filename=filename)
|
|
self.filename = self.get_filename()
|
|
|
|
|
|
def get_filename(self): #, sz_scheme, col_theme, my_style, path_file = "C:\\Users\\edwar\\OneDrive\\Documents\\Programming\\Python Scripts\\Braille_Scrabble", suffix = "stl", presuffix=""):
|
|
"""
|
|
av.val_str(path_file, 'path_file', _m)
|
|
av.val_str(suffix, 'suffix', _m)
|
|
av.val_str(presuffix, 'presuffix', _m)
|
|
"""
|
|
return f"{self.size_characters.name}_{self.colour_theme.name}{self.style_characters.get_text_filename()}"
|
|
|
|
def get_path_file(self, suffix):
|
|
return f"{self.path_dir}/{self.filename}.{suffix}"
|
|
|
|
@staticmethod
|
|
@validate_arguments
|
|
def make_from_styles_and_plaintext_and_proficiency_level(size_characters: Size_Character_Braille, style_characters: Style_Character_Braille, colour_theme: Colour_Theme_Character_Braille, justification_text: Enum_Justification_Text, path_dir: str, max_characters_per_row: int, plaintext: str, proficiency_level: Enum_Braille_Proficiency_Level):
|
|
braille_translation = Translation_Braille(plaintext, proficiency_level)
|
|
return Keyboard_3D(size_characters = size_characters, style_characters = style_characters, colour_theme = colour_theme, justification_text = justification_text, path_dir = path_dir, max_characters_per_row = max_characters_per_row, translation = braille_translation)
|
|
|
|
def make_model_openpyscad(self):
|
|
# integer boolean conversions for position
|
|
show_braille = (self.style_characters.show_braille == Enum_Visibility_Character_Braille.VISIBLE) # or self.style_characters.show_braille == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
show_letter = (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE) # or self.style_characters.show_letter == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
show_number = (self.style_characters.show_number == Enum_Visibility_Character_Braille.VISIBLE) # or self.style_characters.show_number == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
|
|
# dimensions
|
|
"""
|
|
width_character_braille = self.size_characters.spacing_dot + 2 * self.size_characters.spacing_character + self.size_characters.radius_bottom_dot * 2
|
|
R_base_letter = [width_character_braille, width_character_braille, self.size_characters.height_block] # alphabet block dimensions [x, y]
|
|
R_base_braille = [width_character_braille, width_character_braille + self.size_characters.spacing_dot, self.size_characters.height_block] # braille block dimensions [x, y]
|
|
R_base_number = [width_character_braille, width_character_braille - 2 * self.size_characters.spacing_character, self.size_characters.height_block] #np.array(* i_s_num # number block dimensions [x, y] ' adjust to scalar coefficient rather than linear translation
|
|
"""
|
|
|
|
# _fn = self.fn
|
|
model_positive = ops.Union()
|
|
model_negative = ops.Union()
|
|
count_rows = 0
|
|
count_characters_in_row = 0
|
|
size_character = np.array([
|
|
self.size_characters.spacing_character + self.size_characters.width_character_braille,
|
|
self.size_characters.R_base_braille[1] * show_braille + self.size_characters.R_base_letter[1] * show_letter + self.size_characters.R_base_number[1] * show_number + self.size_characters.spacing_character * (show_braille + show_letter + show_number),
|
|
0
|
|
])
|
|
origin_character = np.array([-self.size_characters.spacing_character, -self.size_characters.spacing_character, 0])
|
|
for braille_translation in self.translation:
|
|
length_translation = len(braille_translation.braille_text)
|
|
if count_characters_in_row + length_translation > self.max_characters_per_row or (braille_translation.plaintext == 'NEWLINE' and braille_translation.list_dots_braille == [0, 0, 0, 0, 0, 0] and count_characters_in_row > 0):
|
|
count_rows += 1
|
|
count_characters_in_row = 0
|
|
for character in braille_translation.braille_text:
|
|
model_character_positive, model_character_negative = self.make_model_openscad_from_character(character) # character.make_model_openpyscad()
|
|
position_character = origin_character + np.array([
|
|
(self.size_characters.spacing_character + size_character[0]) * count_characters_in_row,
|
|
(self.size_characters.spacing_character + size_character[1]) * count_rows,
|
|
0
|
|
])
|
|
model_character_positive.translate(position_character)
|
|
model_positive.append(model_character_positive)
|
|
model_character_negative.translate(position_character)
|
|
model_negative.append(model_character_negative)
|
|
count_characters_in_row += 1
|
|
self.model = ops.Difference()
|
|
self.model.append(model_character_positive)
|
|
self.model.append(model_character_negative)
|
|
return self.model
|
|
|
|
@validate_arguments
|
|
def make_model_openscad_from_character(self, character: Character_Braille): # origin_character: List[float] , show_braille: bool, show_letter: bool, show_number: bool
|
|
show_braille = (self.style_characters.show_braille == Enum_Visibility_Character_Braille.VISIBLE) # or self.style_characters.show_braille == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
show_letter = (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE or self.style_characters.show_letter == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
show_number = (self.style_characters.show_number == Enum_Visibility_Character_Braille.VISIBLE) # or self.style_characters.show_number == Enum_Visibility_Character_Braille.EMBOSSED)
|
|
|
|
model_positive = ops.Union()
|
|
model_negative = ops.Union()
|
|
origin_block = np.array([0, 0, 0])
|
|
if show_braille:
|
|
block = self.make_model_openscad_block_braille_from_character(character)
|
|
block.translate(origin_block)
|
|
model_positive.append(block)
|
|
origin_block += np.array([
|
|
0,
|
|
-self.size_characters.spacing_character - self.size_characters.R_block_braille[1],
|
|
0
|
|
])
|
|
if show_letter:
|
|
block = self.make_model_openscad_block_letter_from_character(character)
|
|
block.translate(origin_block)
|
|
if self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE:
|
|
model_positive.append(block)
|
|
else:
|
|
model_negative.append(block)
|
|
origin_block += np.array([
|
|
0,
|
|
-self.size_characters.spacing_character - self.size_characters.R_block_letter[1],
|
|
0
|
|
])
|
|
if show_number:
|
|
block = self.make_model_openscad_block_number_from_character(character)
|
|
block.translate(origin_block)
|
|
model_positive.append(block)
|
|
return model_positive, model_negative
|
|
"""
|
|
@validator('origin_character')
|
|
def validate_origin_character(cls, value):
|
|
if len(value) != 3:
|
|
raise ValueError("origin_character must have 3 elements")
|
|
for element in value:
|
|
if not isinstance(element, (int, float)):
|
|
raise ValueError("origin_character must be a list of integers or floats")
|
|
return value
|
|
|
|
@validator('R_block_braille')
|
|
def validate_R_block_braille(cls, value):
|
|
if len(value) != 3:
|
|
raise ValueError("R_block_braille must have 3 elements")
|
|
return value
|
|
|
|
@validator('R_block_letter')
|
|
def validate_R_block_letter(cls, value):
|
|
if len(value) != 3:
|
|
raise ValueError("R_block_letter must have 3 elements")
|
|
return value
|
|
|
|
@validator('R_block_number')
|
|
def validate_R_block_number(cls, value):
|
|
if len(value) != 3:
|
|
raise ValueError("R_block_number must have 3 elements")
|
|
return value
|
|
"""
|
|
@validate_arguments
|
|
def make_model_openscad_block_braille_from_character(self, character: Character_Braille):
|
|
model_block_braille = ops.Union()
|
|
if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.HIDDEN): return model_block_braille
|
|
if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE):
|
|
block = ops.Cube(self.size_characters.R_block_braille, center = False)
|
|
block.translate([0, -self.size_characters.R_block_braille[1], -self.size_characters.R_block_braille[2]])
|
|
block.color(self.colour_theme.colour_base)
|
|
model_block_braille.append(block)
|
|
if (self.style_characters.show_braille == Enum_Visibility_Character_Braille.VISIBLE):
|
|
for index_dot_braille_y in range(3):
|
|
for index_dot_braille_x in range(2):
|
|
if (character.matrix_braille_dots[index_dot_braille_y][index_dot_braille_x]):
|
|
dot_braille = ops.Cylinder(
|
|
h = self.size_characters.height_cylinder,
|
|
r1 = self.size_characters.radius_bottom_cylinder,
|
|
r2 = self.size_characters.radius_top_cylinder,
|
|
center = True,
|
|
_fn = self.fn
|
|
)
|
|
dot_braille.translate([
|
|
index_dot_braille_x * self.size_characters.spacing_dot,
|
|
-index_dot_braille_y * self.size_characters.spacing_dot,
|
|
0
|
|
])
|
|
dot_braille.color(self.colour_theme.colour_top)
|
|
model_block_braille.append(dot_braille)
|
|
return model_block_braille
|
|
|
|
@validate_arguments
|
|
def make_model_openscad_block_letter_from_character(self, character: Character_Braille):
|
|
font = '"Arial:style=Bold"'
|
|
model_block_letter = ops.Union()
|
|
if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.HIDDEN): return model_block_letter
|
|
if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE):
|
|
block = ops.Cube(self.size_characters.R_block_letter, center = False)
|
|
block.translate([0, -self.size_characters.R_block_letter[1], -self.size_characters.R_block_letter[2]])
|
|
block.color(self.colour_theme.colour_base)
|
|
model_block_letter.append(block)
|
|
size_text = self.size_characters.size_font_alphabetic * self.size_characters.scale_text ** (len(character.plaintext) - 1)
|
|
model_letter = ops.Text(f'"{character.plaintext}"', size_text, font, halign = '"center"', valign = '"center"', _fn = self.fn)
|
|
model_letter.linear_extrude(self.size_characters.height_dot, center = False)
|
|
model_letter.color(self.colour_theme.colour_top)
|
|
model_letter.translate([
|
|
self.size_characters.R_block_letter[0] / 2,
|
|
self.size_characters.R_block_letter[1] / 2 if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE) else self.size_characters.R_block_braille[1] / 2,
|
|
0 if (self.style_characters.show_letter == Enum_Visibility_Character_Braille.VISIBLE) else self.size_characters.height_dot - self.size_characters.height_block - self.size_characters.height_base
|
|
])
|
|
model_block_letter.append(model_letter)
|
|
return model_block_letter
|
|
|
|
@validate_arguments
|
|
def make_model_openscad_block_number_from_character(self, character: Character_Braille):
|
|
model_block_number = ops.Union()
|
|
if (self.style_characters.show_number == Enum_Visibility_Character_Braille.HIDDEN or self.style_characters.show_number == Enum_Visibility_Character_Braille.EMBOSSED or len(character.plaintext) != 1): return model_block_number
|
|
font = '"Arial:style=Bold"'
|
|
number = string.ascii_lowercase.index(character.plaintext.lower()) + 1
|
|
length_number = len(str(number))
|
|
if (number < 1 or number > 26): return model_block_number
|
|
block = ops.Cube(self.size_characters.R_block_number, center = True)
|
|
block.translate([])
|
|
block.color(self.colour_theme.colour_base)
|
|
model_block_number.append(block)
|
|
size_text = (self.size_characters.R_block_number[1] - self.size_characters.spacing_character * (len(number) + 1)) / (len(number) ** self.size_characters.sf_size_font_number_length)
|
|
model_number = ops.Text(f'"{number}"', size_text, font, halign = '"center"', valign = '"center"', _fn = self.fn)
|
|
model_number.linear_extrude(self.size_characters.height_dot, center = True)
|
|
model_number.color(self.colour_theme.colour_top)
|
|
model_number.translate([
|
|
self.size_characters.R_block_number[0] / 2 if (length_number == 1) else self.size_characters.R_block_number[0] / 2 + 1.6 * size_text * (number - (length_number - 1) / 2),
|
|
self.size_characters.R_block_number[1] * 0.25,
|
|
self.size_characters.height_dot / 2
|
|
])
|
|
model_block_number.append(model_number)
|
|
return model_block_number
|
|
|
|
def make_file_openscad(self):
|
|
if self.model is None:
|
|
self.make_model_openpyscad()
|
|
self.model.write(self.get_path_file('scad'))
|
|
|
|
def make_file_stl(self):
|
|
if not os.path.exists(self.get_path_file('scad')):
|
|
self.make_file_openscad()
|
|
render_openscad(self.get_path_file('scad'), self.get_path_file('stl'))
|
|
|
|
def make_file_png(self):
|
|
if not os.path.exists(self.get_path_file('scad')):
|
|
self.make_file_openscad()
|
|
render_openscad(self.get_path_file('scad'), self.get_path_file('png'))
|
|
|