Проверка и подготовка модели к экспорту по пайплайну #202
4 changed files with 331 additions and 0 deletions
|
@ -108,3 +108,83 @@ def run_BoM_list():
|
||||||
sortedParts = uniquePartsSort(labelParts)
|
sortedParts = uniquePartsSort(labelParts)
|
||||||
countedParts = countForUniques(sortedParts)
|
countedParts = countForUniques(sortedParts)
|
||||||
fillInBoMList(sheet, countedParts)
|
fillInBoMList(sheet, countedParts)
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
|
|
||||||
|
def printETACounter(partLabel):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
from FreeCAD import Base
|
||||||
|
|
||||||
|
def export_to_stl(doc, filename):
|
||||||
|
mesh = doc.getObjectsByType("Mesh")[0]
|
||||||
|
mesh.exportStl(filename)
|
||||||
|
|
||||||
|
def upload_to_octoprint(file_path, api_key, octoprint_url):
|
||||||
|
headers = {
|
||||||
|
"X-Api-Key": api_key
|
||||||
|
}
|
||||||
|
files = {
|
||||||
|
"file": open(file_path, "rb")
|
||||||
|
}
|
||||||
|
response = requests.post(octoprint_url + "/api/files/local", headers=headers, files=files)
|
||||||
|
if response.status_code == 201:
|
||||||
|
print("Файл успешно загружен в OctoPrint.")
|
||||||
|
return response.json()["name"]
|
||||||
|
else:
|
||||||
|
print("Ошибка при загрузке файла в OctoPrint:", response.text)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_print_duration(file_name, api_key, octoprint_url):
|
||||||
|
headers = {
|
||||||
|
"X-Api-Key": api_key
|
||||||
|
}
|
||||||
|
response = requests.get(octoprint_url + "/api/files/local/" + file_name, headers=headers)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()["gcodeAnalysis"]["estimatedPrintTime"]
|
||||||
|
else:
|
||||||
|
print("Ошибка при получении информации о файле из OctoPrint:", response.text)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Путь к документу FreeCAD
|
||||||
|
doc_path = "/path/to/your/file.FCStd"
|
||||||
|
|
||||||
|
# Путь для сохранения STL-файла
|
||||||
|
stl_path = "/path/to/your/output.stl"
|
||||||
|
|
||||||
|
# Настройки OctoPrint
|
||||||
|
octoprint_api_key = "your_octoprint_api_key"
|
||||||
|
octoprint_url = "http://localhost:5000"
|
||||||
|
|
||||||
|
# Открываем документ FreeCAD
|
||||||
|
doc = FreeCAD.open(doc_path)
|
||||||
|
|
||||||
|
# Экспортируем модель в STL-файл
|
||||||
|
export_to_stl(doc, stl_path)
|
||||||
|
print("STL-файл успешно создан.")
|
||||||
|
|
||||||
|
# Загружаем STL-файл в OctoPrint
|
||||||
|
uploaded_file_name = upload_to_octoprint(stl_path, octoprint_api_key, octoprint_url)
|
||||||
|
if uploaded_file_name is not None:
|
||||||
|
# Получаем информацию о длительности печати
|
||||||
|
print_duration = get_print_duration(uploaded_file_name, octoprint_api_key, octoprint_url)
|
||||||
|
if print_duration is not None:
|
||||||
|
print("Оценочная длительность печати: {} секунд.".format(print_duration))
|
||||||
|
else:
|
||||||
|
print("Не удалось получить информацию о длительности печати.")
|
||||||
|
else:
|
||||||
|
print("Загрузка файла в OctoPrint не удалась.")
|
||||||
|
|
||||||
|
# Закрываем документ FreeCAD
|
||||||
|
FreeCAD.closeDocument(doc)
|
||||||
|
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 839ce36c70e0a48d82c32c5b6fe17c5634c8ee07
|
||||||
|
|
84
cg/freecad/Frames/materialOperator.py
Normal file
84
cg/freecad/Frames/materialOperator.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import FreeCAD as App
|
||||||
|
import FreeCADGui as Gui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#создаем вкладку с материалами
|
||||||
|
|
||||||
|
#концептуально нам нужен лишь обьект, в котором перечислены тела, связанные с материалами
|
||||||
|
|
||||||
|
#создаем объект
|
||||||
|
#указываем референсный материал
|
||||||
|
#указываем референсное тело
|
||||||
|
#добавляем все остальные тела, которые имеют такой же цвет
|
||||||
|
|
||||||
|
|
||||||
|
#план-минимум
|
||||||
|
'''
|
||||||
|
План:
|
||||||
|
|
||||||
|
Сделать приемлемым работу FEM:
|
||||||
|
1. Проверка на уникальность и повторяемость материалов
|
||||||
|
2. Проверка на детали, которые не имеют материала
|
||||||
|
3. Проверка материалов на соответствие требованиям
|
||||||
|
4. Назначение деталям цвета, соответствующего материалам
|
||||||
|
5. Черный материал - тем, кто без материала
|
||||||
|
6. BoM считает плотности деталей и пишет массы. Здесь должна быть функция, считающая массу детали и записывающая ее в свойства детали
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
doc = App.ActiveDocument
|
||||||
|
obj = doc.Objects
|
||||||
|
|
||||||
|
|
||||||
|
def partsCheckup(doc):
|
||||||
|
for obj in
|
||||||
|
|
||||||
|
material = doc.addObject('App::Document')
|
||||||
|
|
||||||
|
doc.addObject("App::DocumentObjectGroup", "Materials") #создаем папку с материалами
|
||||||
|
|
||||||
|
group.addObject(material)
|
||||||
|
|
||||||
|
#открываем и выбираем MaterialEditor
|
||||||
|
|
||||||
|
import MaterialEditor
|
||||||
|
MaterialEditor.openEditor()
|
||||||
|
|
||||||
|
doc.addObject('App::')
|
||||||
|
'''
|
||||||
|
Нам нужно указать материал в обьекте
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Создаем папку "Материалы"
|
||||||
|
material_group = doc.addObject("App::DocumentObjectGroup", "Materials")
|
||||||
|
|
||||||
|
'''
|
||||||
|
нужно импортировать материалы
|
||||||
|
самое простое - взять целиком блок fem и работать с этим инструментом
|
||||||
|
в fem они вставляются тупо строкой
|
||||||
|
мы можем считать, что материал задан a.k.a json или что-то такое
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Создаем файл материалов fcmat
|
||||||
|
material_file = "путь_к_файлу.fcmat" # Укажите путь к файлу материалов
|
||||||
|
|
||||||
|
# Создаем объект "Материал"
|
||||||
|
material_obj = doc.addObject("App::MaterialObject", "Материал")
|
||||||
|
material_obj.Material = material_file
|
||||||
|
|
||||||
|
# Получаем список тел в сборке, состоящих из данного материала
|
||||||
|
part_names = ["Тело1", "Тело2", "Тело3"] # Укажите имена тел
|
||||||
|
for part_name in part_names:
|
||||||
|
part_obj = doc.getObject(part_name)
|
||||||
|
if part_obj:
|
||||||
|
material_obj.addObject(part_obj)
|
||||||
|
|
||||||
|
# Добавляем объект "Материал" в папку "Материалы"
|
||||||
|
material_group.addObject(material_obj)
|
||||||
|
|
||||||
|
# Обновляем вид дерева построения FreeCAD
|
||||||
|
FreeCADGui.updateGui()
|
6
cg/freecad/Frames/material_requirements.JSON
Normal file
6
cg/freecad/Frames/material_requirements.JSON
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
["Density",
|
||||||
|
"DiffuseColor",
|
||||||
|
"EmissiveColor"
|
||||||
|
]
|
161
cg/freecad/Frames/modelExport.py
Normal file
161
cg/freecad/Frames/modelExport.py
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
'''
|
||||||
|
Эта штука создается с целью проводить все необходимые проверки и манипуляции при движении моделей
|
||||||
|
по пайплайну
|
||||||
|
|
||||||
|
Планируемые фичи:
|
||||||
|
1. Материалы:
|
||||||
|
1.1 Проверка на уникальность
|
||||||
|
1.2 Проверка на повторяемость
|
||||||
|
1.3 Проверки на соответствие материала требованиям
|
||||||
|
1.4 Изменение цветов деталей по факту назначения материалов
|
||||||
|
1.5 Расчет массы по плотностям деталей и прописывание ее в свойствах детали
|
||||||
|
1.6 Указание наименования материала в свойствах детали
|
||||||
|
|
||||||
|
2. Вспомогательные обьекты и тела:
|
||||||
|
2.1. Вспомогательные обьекты имеют отметки о своем статусе
|
||||||
|
2.2. Несолиды имеют пометку несолидовости
|
||||||
|
2.3 Детали без материалов должны быть с материалами
|
||||||
|
|
||||||
|
3. [на будущее] Проверка существования разметки
|
||||||
|
|
||||||
|
4. Дополнение информации в бом-лист (это нужно засунуть в бом, а не сюда)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
import FreeCAD as App
|
||||||
|
import FreeCADGui as Gui
|
||||||
|
from helper.is_solid import is_object_solid
|
||||||
|
import json
|
||||||
|
|
||||||
|
doc = App.ActiveDocument
|
||||||
|
|
||||||
|
#0 Проверка существования директорий
|
||||||
|
#должны быть директории на материалы, на технологические операции, на вспомогательные обьекты
|
||||||
|
#если у нас есть директория "анализ" от Fem, то мы переименуем ее в свою директорию и сделаем ей пометку.
|
||||||
|
#если мы находим материалы в дереве, которые не относятся к этой директории, мы должны засунуть их в нашу директорию
|
||||||
|
#если материалов нет, мы должны указать, что их нет
|
||||||
|
|
||||||
|
|
||||||
|
def materialExistenceCheck(doc):
|
||||||
|
|
||||||
|
# if "Materials" not in doc.Objects:
|
||||||
|
if doc.getObjectsByLabel('Materials') == 0:
|
||||||
|
material_group = doc.addObject("App::DocumentObjectGroup", "Materials")
|
||||||
|
App.Console.PrintMessage("Директория материалов не обнаружена и была создана вновь\n")
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
material_group = doc.getObject("Materials")
|
||||||
|
|
||||||
|
fem_materials = [obj for obj in doc.Objects if (hasattr(obj, 'Proxy') and hasattr(obj.Proxy, 'Type') and obj.Proxy.Type == 'Fem::MaterialCommon')]
|
||||||
|
|
||||||
|
if len(fem_materials) > 0:
|
||||||
|
for material in fem_materials:
|
||||||
|
material_group.addObject(material)
|
||||||
|
print('Материалы успешно скомпонованы')
|
||||||
|
else:
|
||||||
|
|
||||||
|
App.Console.PrintMessage("FEM-материалы не заданы. Укажите FEM-материалы и произведите проверку\n")
|
||||||
|
Gui.updateGui()
|
||||||
|
|
||||||
|
return material_group, fem_materials #шоб не пропадало зазря
|
||||||
|
|
||||||
|
|
||||||
|
[material_group, fem_materials ] = materialExistenceCheck(doc) # укомпоновали материалы
|
||||||
|
|
||||||
|
|
||||||
|
#проверим, что материалы правильно описаны:
|
||||||
|
# Открываем файл JSON с требованиями и загружаем его содержимое
|
||||||
|
with open('material_requirements.json', 'r') as f:
|
||||||
|
material_requirements = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def material_isCorrect(fem_materials, material_requirements):
|
||||||
|
femmat_trobles = {}
|
||||||
|
for femmat in fem_materials:
|
||||||
|
for req in material_requirements:
|
||||||
|
if not ( req in femmat.Material and femmat.Material[req]):
|
||||||
|
if femmat in femmat_trobles:
|
||||||
|
femmat_trobles[femmat].append(req)
|
||||||
|
else:
|
||||||
|
femmat_trobles[femmat] = [req]
|
||||||
|
|
||||||
|
print(femmat_trobles)
|
||||||
|
|
||||||
|
|
||||||
|
material_isCorrect(fem_materials, material_requirements)
|
||||||
|
|
||||||
|
|
||||||
|
#1
|
||||||
|
#1.1 Проверка на уникальность
|
||||||
|
|
||||||
|
#присвоим каждому телу имя материала и значение плотности
|
||||||
|
|
||||||
|
def matProperties2bodies(doc, fem_materials):
|
||||||
|
#проходимся по всем материалам и присваиваем деталюхам параметры
|
||||||
|
#нужно кстати еще цвет им переназначить
|
||||||
|
for femmat in fem_materials:
|
||||||
|
|
||||||
|
body = doc.getObject(femmat.References[0][0].Name).Label #вот эта вот абоба добывает нам тело из перечисления
|
||||||
|
#в это тело нам надо добавить два свойства
|
||||||
|
|
||||||
|
#нужно проверить, есть ли материальные свойства у тела и, если нет, добавить их
|
||||||
|
#в следующей серии будем проверять все тела, есть ли у них материал
|
||||||
|
if 'MaterialName' in body.PropertiesList:
|
||||||
|
if body.getPropertyByName('MaterialName') != femmat.Material['CardName']: #если не совпадает
|
||||||
|
print('ВНИМАНИЕ! Тело ' + body.Label + ' имеет переназначение материалов. Проверьте и укажите один (1) правильный материал!')
|
||||||
|
body.setProperty('MaterialName', femmat.Material['CardName']) #пусть перепишется на новый
|
||||||
|
body.setProperty('Density', femmat.Material['Density']) #плотность
|
||||||
|
else:
|
||||||
|
body.addObjectProperty('MaterialName', femmat.Material['CardName']) #добавляем название материала
|
||||||
|
body.addObjectProperty('Density', femmat.Material['Density']) #добавляем плотность
|
||||||
|
|
||||||
|
|
||||||
|
#считаем массу деталюх
|
||||||
|
density, unit = parse_values(femmat.Material['Density'])
|
||||||
|
volume = body.Shape.Volume
|
||||||
|
body_mass = volume * density
|
||||||
|
body.addObjectProperty('Mass', body_mass) #масса деталюхи
|
||||||
|
|
||||||
|
def bodyWithoutMaterialsCheck(doc):
|
||||||
|
objs = doc.Objects
|
||||||
|
for obj in objs:
|
||||||
|
#проверка на солидовость
|
||||||
|
if (is_object_solid(obj) and ('MaterialName' not in obj.PropertiesList)):
|
||||||
|
print('Деталь ' + obj.Label + 'не имеет назначения материала')
|
||||||
|
|
||||||
|
matProperties2bodies(doc, fem_materials)
|
||||||
|
bodyWithoutMaterialsCheck(doc)
|
||||||
|
|
||||||
|
#после выполнения предыдущей функции у нас появились деталюхи с обозначениями материалов
|
||||||
|
#все деталюхи без этой позиции нужно как-то выделить, а
|
||||||
|
|
||||||
|
#гпт предлагает парсить значение единиц измерения
|
||||||
|
#я с ним соглашусь
|
||||||
|
|
||||||
|
def parse_values(value_str):
|
||||||
|
value = ""
|
||||||
|
unit = ""
|
||||||
|
|
||||||
|
# Проверяем каждый символ в строке плотности
|
||||||
|
for char in value_str:
|
||||||
|
if char.isdigit() or char == ".":
|
||||||
|
# Символ является цифрой или точкой - добавляем его к числу
|
||||||
|
value += char
|
||||||
|
else:
|
||||||
|
# Символ не является цифрой или точкой - считаем его частью единицы измерения
|
||||||
|
unit += char
|
||||||
|
|
||||||
|
# Преобразуем значение плотности в число
|
||||||
|
density = float(value)
|
||||||
|
|
||||||
|
return value, unit
|
||||||
|
|
||||||
|
|
||||||
|
#todo:
|
||||||
|
# сделать проверку на солидовые тела
|
||||||
|
#укомпоновать все вспомогательные обьекты в отдельную штуку
|
||||||
|
#wip
|
Loading…
Add table
Add a link
Reference in a new issue