# Sesc Lab Códigos Abertos (quartas-feiras) ## `hackmd.io/@sesc-av-paulista/lab-codigos-abertos` ![codigo_aberto_2024-02-07-16-25-20-664x332](https://hackmd.io/_uploads/HytWCUkR6.png) ## 2025 - Fabricação digital ### 2025-03-26 - Explorando o [FreeCAD](https://freecad.org) - importa e exporta STL? - interface Python (console e "macro editor") - Gerando G-Code com a bancada Path (agora chama CAM) https://www.youtube.com/watch?app=desktop&v=RrhahfJNn9s&ab_channel=OpenSourceCNC - - Experimentos [do ano passado](https://hackmd.io/PqKxBSMYRJq_VJjP1Y1fWQ?both#2024-08-14---FreeCAD-e-seus-desafios) ![sketch_2021_04_28_FreeCAD](https://hackmd.io/_uploads/Hkgyon-Tye.png) - Video https://www.youtube.com/watch?v=yp6yBTcdcII&ab_channel=ArifK.Rafiq - ![image](https://hackmd.io/_uploads/r1vBAnb6Jg.png) - GPT_stepper para o Marcelo - https://www.youtube.com/watch?v=7spK_BkMJys&ab_channel=HowToMechatronics - https://docs.arduino.cc/libraries/gpt_stepper/?_gl=1*iahx59*_up*MQ..*_ga*MjA0NDc3NjY5Ni4xNzQzMDE1MzEw*_ga_NEXN8H46L5*MTc0MzAxNTMwNy4xLjAuMTc0MzAxNTMwNy4wLjAuMTA5OTQ2OTM1Ng.. ### 2025-03-19 Desafio do dia, automar fazer muitos "chaveiros" com texto diferente em cada - Tentamos um pouco de automação com Python no Blender - Criar objeto: https://blender.stackexchange.com/questions/163487/how-to-add-text-in-blender-using-python - bpy.context.object.data.extrude = 0.17 - bpy.ops.font.open(filepath="C:\\Windows\\Fonts\\ALGER.TTF", relative_path=True) - Contém dica de ajustar unidades/dimensões https://www.talleye.com/pt-BR/posts/configuracao-do-blender-para-impressao-3d-para-iniciantes - Vamos tentar um pouco com py5, trimesh, shapely ```python """ From https://github.com/villares/villares/blob/main/shapely_helpers.py """ from shapely import Polygon, MultiPolygon import py5 import trimesh def draw_shapely(shps, sketch: py5.Sketch=None): """ Draw most shapely objects with py5. This will use the "current" py5 sketch as default. """ s = sketch or py5.get_current_sketch() s.shape(py5.convert_shape(shps)) draw_shapely_objs = draw_shapely # para retro-compatibilidade def polys_from_text(words, font: py5.Py5Font, leading=None, alternate_spacing=False): """ Produce a list of shapely Polygons (with holes!) from a string. New-line chars will try to move text to a new line. The alternate_spacing option will pick the glyph spacing from py5.text_width() for each glyph, it can be too spaced, but good for monospaced font alignment. """ leading = leading or font.get_size() py5.text_font(font) space_width = py5.text_width(' ') results = [] x_offset = y_offset = 0 for c in words: if c == '\n': y_offset += leading x_offset = 0 # assuming left aligned text... continue glyph_pt_lists = [[]] c_shp = font.get_shape(c, 1) vs3 = [c_shp.get_vertex(i) for i in range(c_shp.get_vertex_count())] vs = set() for vx, vy, _ in vs3: x = vx + x_offset y = vy + y_offset glyph_pt_lists[-1].append((x, y)) if (x, y) not in vs: vs.add((x, y)) else: glyph_pt_lists.append([]) # will leave a trailling empty list if alternate_spacing: w = py5.text_width(c) else: w = c_shp.get_width() if vs3 else space_width x_offset += w # filter out elements with less than 3 points # and stop before the trailling empty list glyph_polys = [Polygon(p) for p in glyph_pt_lists[:-1] if len(p) > 2] if glyph_polys: # there are still empty glyphs at this point glyph_shapes = process_glyphs(glyph_polys) results.extend(glyph_shapes) return results def process_glyphs(polys): """ Try to subtract the shapely Polygons representing a glyph in order to produce appropriate looking glyphs! """ polys = sorted(polys, key=lambda p: p.area, reverse=True) results = [polys[0]] for p in polys[1:]: # works on edge cases like â and ® for i, earlier in enumerate(results): if earlier.contains(p): results[i] = results[i].difference(p) break else: # the for-loop's else only executes after unbroken loops results.append(p) return results if __name__ == '__main__': def setup(): global malha, margem py5.size(800, 800, py5.P3D) py5.color_mode(py5.HSB) #py5.stroke_weight(10) #mp = MultiPoint([(200, 200), (100, 100), (200, 300)]) #draw_shapely(mp) t = 'Sesc Av.Paulista\n' \ 'Quarto: 099' d_font = py5.create_font('BlackOpsOne-Regular.ttf', 60) shapes = MultiPolygon(polys_from_text( t, d_font, alternate_spacing=True)) min_x, min_y, max_x, max_y = shapes.bounds margem = 20 chapa = Polygon(((min_x - margem, min_y - margem), (max_x + margem, min_y - margem), (max_x + margem, max_y + margem), (min_x - margem, max_y + margem))) placa_furada = chapa - shapes malha = trimesh.creation.extrude_polygon( placa_furada, 10) def draw(): py5.background(0, 0, 100) py5.translate(margem * 2, 400) py5.rotate_x(py5.radians(py5.mouse_y)) py5.stroke(200, 200) draw_shapely(malha) py5.run_sketch(block=False) ``` - Dicas de leitura para aprender Python - https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/ - https://automatetheboringstuff.com/ - https://penseallen.github.io/PensePython2e/ ### 2025-03-12 - Inkscape -> SVG -> Blender -> extrusão -> STL -> fatiamento -> GCODE ## 2024 ### 2024-09-25 #### Mais ideias de estudo - Mapas - https://github.com/marceloprates/prettymaps - Fazer um exemplo de *add-on* (plug-in) no Blender - Fotogrametria com Python - Edição de malhas 3D https://www.meshlab.net/ - GIFs animados - py5 - https://abav.lugaralgum.com/como-instalar-py5/ ```python= from py5_tools import animated_gif FPS = 30 def setup(): size(500, 500) frame_rate(FPS) animated_gif('out.gif', frame_numbers=range(1, 256, 2), # inicio, parada, passo duration=2 * 1/FPS) def draw(): background(0) f = frame_count % 256 fill(255 - f) circle(200, 200, f * 5) #print(f) window_title(f'{get_frame_rate():.1f}') ``` ### Linear intERPolation (LERP) ```python from py5_tools import animated_gif FPS = 30 cor_a = color(0, 0, 200) cor_b = color(255, 255, 0) def setup(): size(500, 500) frame_rate(FPS) no_stroke() animated_gif('out.gif', frame_numbers=range(1, 256, 2), # inicio, parada, passo duration=2 * 1/FPS) def draw(): background(cor_a) f = frame_count % 256 t = f / 255 # f:0 -> t:0 f:255 -> t:1 a = TWO_PI * t # em radianos t:0 -> a:0 t:1 -> a: 360 graus cor_c = lerp_color(cor_b, cor_a, t) fill(cor_c) circle(200, 200, f * 5) x = 250 + 200 * cos(a) fill(255) circle(x, 350, 50) y = 250 + 200 * sin(a) fill(255) circle(350, y, 50) fill(0) r = 200 cx, cy = width / 2, height / 2 x = cx + r * cos(a) y = cy + r * sin(a) circle(x, y, 50) x = cx + r * cos(-a) y = cy + r * sin(-a) circle(x, y, 50) #print(f) window_title(f'{get_frame_rate():.1f}') ``` ##### Exemplo final ```python= from py5_tools import animated_gif FPS = 30 cor_a = color(0, 0, 200) cor_b = color(255, 255, 0) def setup(): size(500, 500) frame_rate(FPS) no_stroke() animated_gif('out.gif', frame_numbers=range(1, 256, 2), # inicio, parada, passo duration=2 * 1/FPS) def draw(): background(cor_a) f = frame_count % 256 t = f / 255 # f:0 -> t:0 f:255 -> t:1 a = TWO_PI * t # em radianos t:0 -> a:0 t:1 -> a: 360 graus cor_c = lerp_color(cor_b, cor_a, t) fill(cor_c) circle(200, 200, f * 5) for i, y in enumerate(range(50, height, 50)): ty = (t + i / 9) % 1 if ty < 0.5: x = lerp(50, width - 50, back_ease_in_out(ty * 2)) fill(255) circle(x, y, 50) else: x = lerp(width - 50, 50, back_ease_in_out((ty * 2)-1)) fill(255) circle(x, y, 50) #print(f) window_title(f'{get_frame_rate():.1f}') def cubic_ease_in_out(p): if p < 0.5: return 4 * p ** 3 else: f = ((2 * p) - 2) return 0.5 * f ** 3 + 1 def back_ease_in_out(p): c1 = 1.70158 c2 = c1 * 1.8 #1.525 p2 = p * 2 if p < 0.5: return (p2 ** 2 * ((c2 + 1) * p2 - c2)) / 2 else: return ((p2 - 2) ** 2 * ((c2 + 1) * (p2 - 2) + c2) + 2) / 2 ``` ![out](https://hackmd.io/_uploads/HyslrJzRR.gif) ### 2024-09-18 - Visualização estilo "map tree" - ![](https://raw.githubusercontent.com/villares/sketch-a-day/main/2024/sketch_2024_09_21/sketch_2024_09_21.gif) - https://github.com/villares/sketch-a-day/blob/main/2024/sketch_2024_09_21/sketch_2024_09_21.py ### 2024-09-11 - Fuzzy Matching e Levenshtein Distance - Na biblioteca padrão (Standard Library) - ```python from difflib import SequenceMatcher def similar(a, b): return SequenceMatcher(None, a, b).ratio() ``` - ```python difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6) ``` - Estudo similaridades (não deu muito certo) ```python from pathlib import Path from difflib import get_close_matches, SequenceMatcher from pprint import pprint pasta = Path('C:/Users/ETA/Downloads') arquivo = Path('C:/Users/ETA/Downloads/sashikodiversos.svg') nomes = [] for path in pasta.iterdir(): nomes.append(path.stem.replace(' ', '').lower()) print(get_close_matches('sashiko', nomes, n=10, cutoff=0.3)) # ['sashikodiversos', 'reguasashikofinal', 'eiko', 'reguasashikofinal(1)', # 'um2c_reguasashikofinal', 'desktop', '10sashikotemplates-3852387', # '10sashikotemplates-3852387', 'ss-d-farol', 'anita'] # SequenceMatcher(None, 'tide', 'diet').ratio() palavra_teste = 'sashiko' arquivos = {} for path in pasta.iterdir(): arquivos[path.stem.lower()] = path nomes = arquivos.keys() for nome in nomes: metrica = SequenceMatcher(None, palavra_teste, nome).ratio() if metrica > 0.40: print(nome[:15], metrica) ``` - Subpastas do Downloads ```python= from pathlib import Path from difflib import get_close_matches, SequenceMatcher from pprint import pprint pasta = Path('C:/Users/ETA/Downloads') extensions = set() # conjunto set for path in pasta.iterdir(): if path.is_file(): extensions.add(path.suffix[1:]) # sufixo sem o '.' extensions = sorted(extensions) print(extensions) for ext in extensions: nova_pasta = pasta / ext nova_pasta.mkdir(parents=True, exist_ok=True) print(nova_pasta, nova_pasta.exists()) for path in pasta.iterdir(): if path.is_file(): ext = path.suffix[1:] # path: C:\... Downloads\blahbla.jpg # pasta / blahbla.jpeg # pasta / jpeg / blahbla.jpg destino = pasta / ext / path.name path.rename(destino) ``` - Tuplas e listas - https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/lacos_py.html#um-pouco-sobre-tuplas-e-listas - Dicionários https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/dicionarios.html - Conjuntos https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/conjuntos.html ### 2024-09-04 - Atividade anterior (Grupo de estudos em Python - Sesc) de Processamento de Linguagem Natural https://hackmd.io/@sesc-av-paulista/estudos-em-python-18-junho - TF-IDF - abreviação do inglês term frequency–inverse document frequency, métrica de importância de palavras (termos) em um "corpus". - https://hackmd.io/@villares/mares-de-texto#TF-IDF ```python= from collections import Counter from pathlib import Path import nltk import numpy as np nltk.download('punkt') nltk.download('stopwords') from nltk.corpus import stopwords palavras_a_remover = stopwords.words('portuguese') pontuacao = ['|', '–', '$', '’', '“', '”','•','•', '', ',','.','!','?',';','-','"',"'",'[',']','(',')','@', '\x97', '--', '...', ':', 'si', 'sr', 'd', '\x93', 'tão', 'sra', 'lo', 'la', 'lhe', 'aqui', 'Então', 'porque'] dir_atual = Path.cwd() pasta_txts = dir_atual / 'artigos' if not pasta_txts.exists(): print('Não achei a pasta com os artigos') exit() contadores_por_doc = {} # dict chave documento : valor dict.Counter for txt_path in sorted(pasta_txts.iterdir())[:50]: with open(txt_path, encoding='utf-8') as txt: #texto = txt.read() # texto bruto linhas = txt.readlines() bruto = ''.join(linhas) #print(bruto) words = nltk.word_tokenize(bruto) good_words = [item for item in words if (item.lower() not in pontuacao and item.lower() not in palavras_a_remover) # if not (item in pontuacao or # item in palavras_a_remover) ] contador = Counter(good_words) contadores_por_doc[txt_path.stem] = contador #print(txt_path.stem, contador.most_common(5)) num_docs = len(contadores_por_doc) #contador_doc = contadores_por_doc['teatro'] for doc, contador_doc in contadores_por_doc.items(): print(f'**** {doc} ****') tf_idf_palavras = {} # dict for palavra, tf in contador_doc.items(): existe_em_n_docs = 0 for id_doc, contador in contadores_por_doc.items(): if palavra in contador: existe_em_n_docs += 1 # e = e + 1 # R/C e++ idf = np.log10(num_docs / (existe_em_n_docs + 1)) # parece melhor! tf_idf_palavras[palavra] = tf * idf resultado = sorted((i, k) for k, i in tf_idf_palavras.items() if i > 1) for tf_idf, termo in resultado[-5:]: print(termo, f'{tf_idf:.2f}') ``` - https://automatetheboringstuff.com/ ### 2024-08-28 - Estudar [terceira parte do tutorial de Python no Blender](https://tabreturn.github.io/code/blender/python/2020/11/01/a_quick_intro_to_blender_creative_coding-part_3_of_3.html) do *tabreturn* (Tristan Bunn) ![](https://tabreturn.github.io/img/aqitbcc03/wavy-cone-animation.gif) #### primeiro passo Abrir o Blender - Abrir o console do sistema **Window > Toggle System Console** (Não tem no MacOS, então seguimos parte das intruções [deste vídeo](https://www.youtube.com/watch?v=RbQCzk-ef3g&ab_channel=MichaelBridges)) - Interface de paineis - Workspace? **Scripting** - ![image](https://hackmd.io/_uploads/SyYj4y6iC.png) - **+ New** - ![image](https://hackmd.io/_uploads/Hk6QHJ6sC.png) - Menu **Text** > **Save as...** - ![image](https://hackmd.io/_uploads/SJ0cryaoA.png) - Preferencias extra: - ![image](https://hackmd.io/_uploads/rkJLu16sC.png) - Documentação https://docs.blender.org/api/2.83/info_quickstart.html - Object "location" - **Quais as unidades do Blender?** são explícitas? - Laço `for` com fábrica de números `range()` - ```python # range(stop) # range(start, stop) for numero in range(1, 11, 2): # range(start, stop, step) print(numero) ``` Código do tutorial ```python= import bpy from math import sin, tau # clear meshes in the scene for obj in bpy.data.objects: if obj.type == 'MESH': bpy.data.objects.remove(obj) # animation variables total_frames = 150 theta = 0.0 # define a one hundred frame timeline bpy.context.scene.frame_end = total_frames bpy.context.scene.frame_start = 0 for x in range(5): # original era 30! # generate a grid of cones for y in range(5): # original era 30! cone = bpy.ops.mesh.primitive_cone_add() cone = bpy.context.object cone.name = 'Cone-{}-{}'.format(x, y) cone.location[0] = x * 2 cone.location[1] = y * 2 # add keyframes to each cone for frame in range(0, total_frames): bpy.context.scene.frame_set(frame) cone.location.z = sin(theta + x) * 2 - 1 cone.keyframe_insert(data_path='location') scale = sin(theta + y) cone.scale = (scale, scale, scale) cone.keyframe_insert(data_path='scale') theta += tau / total_frames ``` Mais sobre seno e cosseno: https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/seno_cosseno_atan2.html ### 2024-08-21 - Ideias para desenho com programação - p5js (JavaScript) -> https://p5js.org (da fundação Processing) - Processing (Java) -> https://processing.org - py5 (Python) -> material aberto https://abav.lugaralgum.com/material-aulas #### Pesquisando automação e plugins em vários programas Temos os **plug-ins**, **add-ons** ou **extensions** (extensões) que são artefatos mais acabados, embalados para distribuição, e temos em geral editores de **scripts** ou **macros**. - **Blender** - Conceitos básicos e utilização por scripts em python (em inglês - usar plugin tradutor para quem tem dificuldade) - Programação visual: - https://nortikin.github.io/sverchok/ - https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/index.html - Requisitos , comandos básicos de blender,configurar o blender para rodar scripts em python, importar módulos e alguns conceitos básicos de python: inteiro, booleano, string, lista, tupla, dicionário e conjuntos, criar funções - Tutorial de programação criativa no Blender https://tabreturn.github.io/code/blender/python/2020/06/06/a_quick_intro_to_blender_creative_coding-part_1_of_3.html - Blender add-ons (tutorial plugins) em inglês - https://docs.blender.org/manual/en/latest/advanced/scripting/addon_tutorial.html - Krita - Para criação de plugins no Krita usa-se a programação python. No programa existe o "Editor de Script" - Sobre os plug-ins em Python https://docs.krita.org/pt_PT/user_manual/python_scripting/install_custom_python_plugin.html - Mais coisas em https://docs.krita.org/pt_PT/user_manual/python_scripting/krita_python_plugin_howto.html - **Inkscape** - biblioteca de extensões: https://inkscape.org/pt-br/gallery/=extension/ - documentação: https://inkscape.gitlab.io/extensions/documentation/tutorial/index.html - "effect extensions" -> pega o svg do inkscape, modifica de algum jeito, e retorna a versão modificada para o inkscape para ser renderizada no canvas. - tutorial de extensão simples, para mudar o "fill" de qualquer objeto para vermelho: https://inkscape.gitlab.io/extensions/documentation/tutorial/my-first-effect-extension.html - **Gimp** "Macros" - Tem automação com Perl e com Python 2.7 :(( - Tem um lance que eles chamam de "pseudo código" (pseudo code) que parecem entradas no console Python - Tem um console Python - Ponto inicial na documentação: https://www.gimp.org/tutorials/Automate_Editing_in_GIMP/#motivation - **Kdenlive** - Kdenlive is based on the KDE frameworks and Qt. Most of the code is written in C++, with some parts in Qml. - Para criar plugins no Kdenlive, você precisa de conhecimentos em C++ e Qt. - CMT Plugins. This category consists of effects and filters from the LADSPA library pertaining to CMT (Computer Music Toolkit). They usually require specific hardware. https://docs.kdenlive.org/en/effects_and_filters/audio_effects/cmt_plugins/index.html - LADSPA Plugins. This category consists of effects and filters from the LADSPA library. https://docs.kdenlive.org/en/effects_and_filters/audio_effects/ladspa_plugins/index.html - TAP Plugins. This category consists of effects and filters from the LADSPA library pertaining to TAP (Tom's Audio Plugins). https://docs.kdenlive.org/en/effects_and_filters/audio_effects/tap_plugins/index.html ### 2024-08-14 - FreeCAD e seus desafios - Apresentação - Esta atividade é relacionada ao Grupo de estudos em Python (hackmd.io/@sesc-av-paulista/estudos-em-python) - FreeCAD - Comunidade - Report issues - forum - Tradução - Bug `inserir abas` -> `inserir TABs` - documentação - Um desafio! - Desenhar uma estrela - Desenhar uma placa com furo em forma de estrela - Macro Python grade com furos do Ale - Menu Macro -> botão Criar -> arquivo.py -> editar - Na janela do editor, executa com botão do triângulo (verde na minha interface, pode ser outra cor) CTRL+F6 ```python import Part from FreeCAD import Vector largura, altura, espessura = 50, 80, 10 plate = Part.makeBox(largura, altura, espessura) espaco, raio = 10, 4 furador = Part.makeCylinder(raio, espessura * 2, Vector(0, 0, -espessura / 2)) for x in range(0, largura, espaco): for y in range(0, altura, espaco): furo = furador.translated(Vector(x + espaco / 2, y + espaco / 2, 0)) plate = plate.cut(furo) Part.show(plate) ``` ![image](https://hackmd.io/_uploads/rJKrq_5qR.png) #### Teste Melisso ```py pl = FreeCAD.Placement() points = [ FreeCAD.Vector(-24.233092308044434, 10.237299919128418, 0.0), FreeCAD.Vector(15.492904663085938, 3.3072924613952637, 0.0), FreeCAD.Vector(-6.303082466125488, -19.829988479614258, 0.0), FreeCAD.Vector(-7.979696273803711, -4.181586265563965, 0.0), FreeCAD.Vector(-36.7056999206543, -9.323204040527344, 0.0) ] line = Draft.make_wire(points, placement=pl, closed=True, face=True, support=None) Draft.autogroup(line) ``` Estrelinha ```python= import Draft from math import pi, cos, sin from FreeCAD import Vector pl = FreeCAD.Placement() N = 20 points = [] ang = 2 * pi / N r1, r2 = 8, 4 for i in range(N): x = r1 * cos(ang * i) y = r1 * sin(ang * i) points.append(Vector(x, y, 0.0)) x = r2 * cos(ang * i + ang / 2) y = r2 * sin(ang * i + ang / 2) points.append(Vector(x, y, 0.0)) line = Draft.make_wire(points, placement=pl, closed=True, face=True, support=None) Draft.autogroup(line) App.ActiveDocument.recompute() ``` ### 2024-04-24 - Tutorial Blender com programação criativa - Vamos tentar seguir este [tutorial do Tristan Bunn (tabreturn)](https://tabreturn.github.io/code/blender/python/2020/06/06/a_quick_intro_to_blender_creative_coding-part_1_of_3.html) #### Parte 1 - **Instrução do tutorial**: ~~No Windows usamos o terminal "Prompt de Comando" (interface de linha de comando CLI) com o camimnho (path) do blender.exe (`"C:\Program Files\Blender Foundation\Blender 4.0\blender-launcher.exe"`) que copiamos de dentro das propriedades do atalho do Blender.~~ - **NOVIDADE** Não precisa mais lançar pelo terminal, abra o Blender normalmente e procure o menu *Window*>*Toggle System Console* - Dentro do Blender - clicamos no layout/aba *Scripting* - text > New... - escrevi o código exemplo `print('oi oi oi')` (mas podia ter sido `print("Hello, World"`) - Apertou o botão triangular play/run (executar) - saiu o resultado na janela do terminal #### Parte 2 - Escrever no console Pytho - Mover com G o cubo na interface gráfica e ver o código que aperece (contém comando de translate) - testamos colar um código de translate no console e ele andou com o cubo (de maneira relativa) - dica: setinha pra cima para repetir últimos códigos do console - `C` variável que conta do "contexto" (o que está selecionado no documento). `C.object` objeto selecionado - Investigar a posição olhando o `C.object.location` - Alterar a posição de maneira absoluta (não relativa) com `C.object.location = (0, 0, 0)` - Python Tool Tips - ![scripting-tools-python-tool-tips-preferences](https://hackmd.io/_uploads/rJsuHCIbC.png) #### Parte 3 - No editor de texto é preciso importar a biblioteca que faz a interdafe com o Blender (`import bpy`), o que não é necessário no console interatico (árrea com o prompt `>>>`) - Objetos do documento podem ser acessados com `bpy.data.objects` - podemos converter todos objetos numa lista do Python com `list(bpy.data.objects)` - exemplo do resultado: `[bpy.data.objects['Camera'], bpy.data.objects['Cube.001'], bpy.data.objects['Light'], bpy.data.objects['Light.001']]` - Podemos acessar objetos com uma interface de chave entre colchetes (como um dicionário) com o nome do objeto `bpy.data.objects['Cube.001']` - Alterar atributos do objeto: ```python bpy.data.objects['Cube.001'].location = (2, 0, 0) # ou só um componente da posição bpy.data.objects['Cube'].location.x = 3 ``` #### continua na semana que vem... (*to be continued...*) ### 2024-04-17 - Blender ![image](https://hackmd.io/_uploads/SywkgtTxC.png) - https://blender.org - Modelador 3D (e mais...) - Python no Blender: https://github.com/tabreturn/blender-creative-coding - Básico [vídeo de 20m](https://youtu.be/Rqhtw7dg6Wk?si=FT44xhPOGmWVm8rS): - "editores" (os módulos/janelas) - zoom, orbit e pan - Seleção - **SHIFT** - **A**ll (seleciona tudo) - AA ou ALT+A deseleciona tudo - **G**rab (mover), **R**otate, **S**cale - X Y Z - SHIF + X Y Z (trava um eixo e libera os outros 2) - No editor de propriedades icone do quadradinho laranja tem coordenadas o objeto - ![image](https://hackmd.io/_uploads/BJddWq6l0.png) - Modos: objeto e edição (**TAB**) - No modo de edição - seleçaõ de vértices, arestas e faces - ![image](https://hackmd.io/_uploads/Bk2xfcTgR.png) - 1 2 3 - **Z** Armado, Sólido, Render e Raio-X (ALT+Z) - ![image](https://hackmd.io/_uploads/SkyVVK6lR.png) - Conceitos: Edição "destrutiva" vs. "com histórico" (modificadores) - **CTRL + J** "Join" junta objetos (um pouco como um grupo) - **P** no modo de edição permite separar do join um as partes selecionadas - Seda mostrou: - Como ele fez as [máscaras low poly](https://www.danielseda.com/?pgid=jnisaeoa-3511510d-e02c-4056-b164-13207d098723) - Add-ons: - Para facilitar exportação para impressão 3D - Export Papel Model - Unidades ... para impressão 3D - Em *Scene* > *Units* - Escala da Grade - Default - save startup file - Modifier - Boolean - selecionar objeto principal - Add modifier - conta-gotas para selecionar o secundário - testamos differença e união - pode esconder o objeto secundário - ou pode usar o apply (que torna a operação destrutiva) - Thingiverse: repositório de modelos - https://thingiverse.com --- ### 2024-04-10 - Krita ![image](https://hackmd.io/_uploads/SyfT1talR.png) - https://krita.org - Ilustração digital, baseada em pixels (raster/bitmap) - Anita Cavaleiro mostrou pra nós os primeiros passos! - Usando uma mesa digitalizadora Wacon ### 2024-04-03 - Desenho vetorial - Desenho digital vetorial - SVG (Scalable Vector Graphics) - Editor livre: https://inkscape.org - Fontes typográficas digitais - Postcript, TTF, OTF - Um exemplo de SVG ```svg= <svg height="220" width="500" xmlns="http://www.w3.org/2000/svg"> <polygon points="100,10 150,190 50,36" style="fill:lime;stroke:purple;stroke-width:3" /> Sorry, your browser does not support inline SVG. </svg> ``` <svg height="220" width="500" xmlns="http://www.w3.org/2000/svg"> <polygon points="100,10 150,190 50,36" style="fill:lime;stroke:purple;stroke-width:3" /> Sorry, your browser does not support inline SVG. </svg> ![poly](https://hackmd.io/_uploads/B1ASKGjkR.svg) - Exemplos máscaras e 3D com trimesh https://gist.github.com/villares/036fba275576e85b7411170073a7153d - Código de ler forma do texto com um fonte específica https://gist.github.com/villares/036fba275576e85b7411170073a7153d#file-shapely_helpers-py ```python= import py5 from shapely.geometry import Polygon, MultiPolygon, GeometryCollection, LineString, Point # Experiment to extract poly shapes from a text rendered in a specific font # Demo sketch for poly_from_text() and draw_shapely_objs() def setup(): global d_font, i_font py5.size(800, 800) py5.color_mode(py5.HSB) py5.stroke(255) d_font = py5.create_font('Consolas', 300) i_font = py5.create_font('Gill Sans MT', 300) def draw(): py5.background(100) py5.translate(50, 100) t = 'Sesc Av. Paulista\nLaboratório Aberto' f = i_font if py5.is_key_pressed else d_font shapes = polys_from_text( t, f, alternate_spacing=py5.is_mouse_pressed) pshape = py5.convert_shape(GeometryCollection(shapes)) py5.shape(pshape, 0, 0) def polys_from_text(words, font, alternate_spacing=False): """ Produce a list of shapely Polygons (with holes!) from a string. New-line chars will try to move text to a new line. The alternate_spacing option will pick the glyph spacing from py5.text_width() for each glyph, it can be too spaced, but good for monospaced font alignment. """ py5.text_font(font) space_width = py5.text_width(' ') results = [] x_offset = y_offset = 0 for c in words: if c == '\n': y_offset += font.get_size() x_offset = 0 # assuming left aligned text... continue glyph_pt_lists = [[]] # começa com uma "lista atual" vazia c_shp = font.get_shape(c, py5.mouse_x / 10) # if c == 'a': # print(py5.mouse_x / 10, c_shp.get_vertex_count()) vs3 = [c_shp.get_vertex(i) for i in range(c_shp.get_vertex_count())] if c == 'a': print(c_shp.get_vertex(0)) vs = set() for vx, vy, _ in vs3: x = vx + x_offset y = vy + y_offset lista_atual = glyph_pt_lists[-1] # sempre a última lista lista_atual.append((x, y)) if (x, y) not in vs: vs.add((x, y)) else: glyph_pt_lists.append([]) # will leave a trailling empty list # [[(...,...)...], [(...,...)...], []] if not vs3 or alternate_spacing: w = py5.text_width(c) else: w = c_shp.get_width() x_offset += w # filter out elements with less than 3 points # and stop before the trailling empty list glyph_polys = [Polygon(p) for p in glyph_pt_lists[:-1] if len(p) > 2] if glyph_polys: # there are still empty glyphs at this point glyph_shapes = process_glyphs(glyph_polys) results.extend(glyph_shapes) return results def process_glyphs(polys): """ Try to subtract the shapely Polygons representing a glyph in order to produce appropriate looking glyphs! """ polys = sorted(polys, key=lambda p: p.area, reverse=True) results = [polys[0]] for p in polys[1:]: # works on edge cases like â and ® for i, earlier in enumerate(results): if earlier.contains(p): results[i] = results[i].difference(p) break else: # the for-loop's else only executes after unbroken loops results.append(p) return results if __name__ == '__main__': py5.run_sketch() ``` ### 2024-03-27 - Pesquisar, instalar e explorar: - foxdot (Supercollider) - Seguindo o seguinte guia: https://foxdotcode.readthedocs.io/en/latest/guides/installation.html - Instalar `git` - https://github.com/git-for-windows/git/releases/download/v2.44.0.windows.1/Git-2.44.0-64-bit.exe - Instalar `SuperCollider` - https://github.com/supercollider/supercollider/releases/download/Version-3.13.0/SuperCollider-3.13.0_Release-x64-VS-3188503.exe - Instalar o Python 3.12 - python - Janela de sugestão de instalar o Python - Abrimos o SuperCollider - no editor `Quarks.install("FoxDot")` e **CNTRL+RETURN** - ![image](https://hackmd.io/_uploads/HJQkSyG1C.png) - Também fiz CNTRL+RETURN em cada uma destas duas linhas: ``` Quarks.install("https://github.com/Qirky/FoxDotQuark.git") Quarks.install("https://github.com/supercollider-quarks/BatLib.git") ``` - ![image](https://hackmd.io/_uploads/HJlnrJMkC.png) - Apagamos a pasta `C:\Users\ETA\AppData\Local\SuperCollider\downloaded-quarks\FoxDotQuark` Tentamos usando o venv no Python do Window mas não rolou (desconfio que por ser Python 3.12, muito novo) ~~- Usamos `python -m venv C:\dir_do_env` - para ativar: - Não usar o powershell do windows - Usando o Terminal normal (Prompt de Comando) `C:\dir_do_env\Scripts\activate.bat`~~ - Abrimos o **Thonny** formos em opções > interpretador > criamos um env - Abrir o shell do sistema - Fizemos o `pip install FoxDot` - `python -m FoxDot` - A conxeção FoxDot -> SuperCollider parece funcionar - Rodamos exemplos do Tutorial foxdot.org mas não sai som. - No SC tem ` FAILURE IN SERVER /s_new SynthDef not found *** ERROR: SynthDef pluck not found FAILURE IN SERVER /s_new SynthDef not found ` ### 2024-03-20 - Usou o Inkscape.org para produzir um desenho vetorial de 50x50mm de um estêncil - exportou em PNG (raster), preto e branco - Abriu o PNG no CURA - ajustou 0.5mm de altura máxima e 0mm na base - escalou de novo pra 50x50mm - Mara ajustou CURA para PLA branco diâmetro 2.75mm - sem "brim" (saia que segura primeira camada) - 20% infill (preenchimeto) - altura 0.15mm (normal) - o resto parece padrão... - ![rect1](https://hackmd.io/_uploads/ryWsE3_Aa.png) ![triste](https://hackmd.io/_uploads/B1WsVnd06.png) ![vv](https://hackmd.io/_uploads/ByWjVhORp.png) ### 2024-03-13 - Conversamos sobre software livre - Fabricação digital - Código que gera o STL com as estrelinhas - https://github.com/villares/sketch-a-day/tree/main/2024/sketch_2024_03_03 - Escalamos no cura para 100x100x3mm - Para rodar o código [Thonny + py5](https://abav.lugaralgum.com/como-instalar-py5/) - https://abav.lugaralgum.com/material-aulas/Processing-Python-py5/ STL: https://github.com/villares/sesc-lab-codigos-abertos/tree/main/2024-03-20