add all last func

This commit is contained in:
ksenia_mikhailova 2025-06-24 13:41:38 +03:00
parent 27ea6e903e
commit 9230dbced0
3 changed files with 452 additions and 16 deletions

View File

@ -35,7 +35,14 @@ class PythonJSBridge(QObject):
data = self.kompas.get_open_documents()
if command == KompasCommand.GET_AVAILABLE_ACTIONS:
data = self.kompas.get_available_actions()
if command == KompasCommand.IGES:
data = self.kompas.save_to_iges()
if command == KompasCommand.EXPORT_RASTER:
data = self.kompas.export_to_raster()
if command == KompasCommand.PROJECT_SUPPORT:
data = self.kompas.create_drawing_for_parts()
if command == KompasCommand.STATS:
data = self.kompas.collect_statistics()
return json.dumps(data, ensure_ascii=False)
def send_event_to_js(self, event_type: str, data: dict):

View File

@ -4,6 +4,11 @@ class KompasCommand(str, Enum):
OPEN_KOMPAS = "open_kompas"
GET_AVAILABLE_ACTIONS = "get_available_actions"
IGES = "iges"
STATS = "stats"
EXPORT_RASTER = "export_raster"
PROJECT_SUPPORT = "project_support"
@classmethod
def has_value(cls, value):
return any(value == item.value for item in cls)

View File

@ -2,6 +2,9 @@ import os
import traceback
import pythoncom
from win32com.client import Dispatch, gencache
from PIL import Image, ImageDraw, ImageFont
from enums import KompasCommand
ids = {
"api_5": "{0422828C-F174-495E-AC5D-D31014DBBE87}",
@ -80,28 +83,441 @@ class KompasDocumentParser:
return documents
# --- Заглушки для действий ---
def create_drawing_for_parts(self):
"""
Создание чертежей для всех уникальных деталей из открытых деталей и сборок.
Также создаёт спецификацию для сборок.
"""
print("Начинаем создание чертежей для деталей...")
saving_path = "../cdw/"
def get_all_sheets(self):
"""Заглушка: Извлечение данных о листовых деталях"""
pass
# Получаем доступные типы из разрешённых действий
av_actions = self.get_available_actions()
allowed_types = av_actions[KompasCommand.PROJECT_SUPPORT]["allowed_types"]
docs_collection = self.application.Documents
for i in range(docs_collection.Count):
try:
doc = docs_collection.Item(i)
if doc is None:
continue
doc_path = doc.Path
# Сохранение чертежа
output_dir = os.path.join(doc_path, saving_path.strip("/"))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Создана папка: {output_dir}")
doc_type = doc.DocumentType
if doc_type not in allowed_types:
continue
doc.Active = True
doc_name = "-".join(doc.Name.split(".")[:-1])
print(f"Обрабатываем документ: {doc_name}")
# Сохранение чертежа
output_dir = os.path.join(doc_path, saving_path.strip("/"))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Создана папка: {output_dir}")
doc_3d = self.api7_module.IKompasDocument3D(doc)
doc_components = []
def all_elements(part):
"""Рекурсивный обход всех компонентов сборки"""
parts = self.api7_module.IParts7(part.Parts)
for j in range(parts.Count):
element = parts.Part(j)
if element.Parts.Count == 0:
if not element.Standard and not any(
el.Name == element.Name for el in doc_components
):
doc_components.append(element)
else:
all_elements(element)
if doc_type == self.constants.ksDocumentAssembly:
all_elements(doc_3d.TopPart)
else:
doc_components.append(doc_3d.TopPart)
for component in doc_components:
component_ipart = self.api7_module.IPart7(component)
if component_ipart.Standard:
continue
print(f"Создаём чертёж для: {component.Name}")
# Создаём новый чертёж
c_doc = self.application.Documents.Add(self.constants.ksDocumentDrawing)
c_layout = c_doc.LayoutSheets
c_sheet = c_layout.Item(0)
c_sheet.Format.Format = self.constants.ksFormatA3
c_sheet.Format.VerticalOrientation = False
c_sheet.Update()
# Расчёт габаритов
c_size = [1, 1, 1]
if component_ipart.Owner.ResultBodies:
gabarit = [0, 0, 0, 0, 0, 0]
component_ipart.Owner.ResultBodies.GetGabarit(*gabarit)
g1 = gabarit[1:4]
g2 = gabarit[4:]
c_size = [abs(g1[i] - g2[i]) for i in range(len(g1))]
g = max(c_size)
# Масштабирование
c_scale = c_sheet.Format.FormatHeight / sum(c_size)
# Получаем интерфейс 2D документа
c_doc_2d = self.api7_module.IKompasDocument2D(c_doc)
c_views = c_doc_2d.ViewsAndLayersManager.Views
# Добавляем стандартные виды
c_views.AddStandartViews(
component_ipart.FileName,
component_ipart.Name,
[1, 3, 5, 7],
c_size[1] * c_scale,
c_sheet.Format.FormatHeight - 25,
c_scale,
20,
20,
)
filename = "_".join(
filter(
None,
[component_ipart.Marking, component_ipart.Name[:20]],
)
).replace(" ", "-")
full_path = os.path.join(output_dir, f"{filename}.cdw")
c_doc.SaveAs(full_path)
print(f"[OK] Сохранён чертёж: {full_path}")
# Сохранение спецификации для сборок
if doc_type == self.constants.ksDocumentAssembly:
spec = self.application.Documents.Add(
self.constants.ksDocumentSpecification
)
spec_doc = self.api7_module.ISpecificationDocument(spec)
spec_doc.AttachedDocuments.Add(doc.PathName, True)
filename = "Список_деталей"
full_path = os.path.join(output_dir, f"{filename}.spw")
spec.SaveAs(full_path)
print(f"[OK] Сохранена спецификация: {full_path}")
except Exception as e:
print(f"[ERROR] Ошибка при обработке документа #{i + 1}: {e}")
traceback.print_exc()
def save_to_iges(self):
"""Заглушка: Экспорт в IGES"""
pass
"""Сохраняет открытые 3D-документы (детали/сборки) в формате IGES"""
print("Начинаем сохранение документов в формате IGES...")
av_actions = self.get_available_actions()
docs_collection = self.application.Documents
for i in range(docs_collection.Count):
try:
doc = docs_collection.Item(i)
if doc is None:
continue
doc_type = doc.DocumentType
if doc_type not in av_actions[KompasCommand.IGES]["allowed_types"]:
continue
doc.Active = True
doc_path = doc.Path
doc_name = "-".join(doc.Name.split(".")[:-1])
print(f"Попытка сохранить: {doc_name}")
# Получаем 3D-документ через API v5
doc_api5 = self.api5.ActiveDocument3D()
if not doc_api5:
raise RuntimeError(
"Не удалось получить активный 3D-документ через API v5"
)
# Подготавливаем параметры сохранения в IGES
save_params = doc_api5.AdditionFormatParam()
save_params.Init()
save_params.format = self.constants.ksConverterToIGES
ext = "igs"
output_dir = os.path.join(doc_path, ext)
filename = f"{doc_name}.{ext}"
full_path = os.path.join(output_dir, filename)
# Создаём директорию, если её нет
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Сохраняем файл
result = doc_api5.SaveAsToAdditionFormat(full_path, save_params)
if result:
print(f"[OK] Сохранено: {full_path}")
else:
print(f"[ERROR] Не удалось сохранить: {full_path}")
except Exception as e:
print(f"[ERROR] Ошибка при обработке документа #{i + 1}: {e}")
traceback.print_exc()
def collect_statistics(self):
"""Заглушка: Сбор статистики по элементам, гибам и сваркам"""
pass
"""Сбор статистики по элементам, гибам и сваркам в активном документе"""
print("Начинаем сбор статистики по элементам...")
# Получаем доступные типы из разрешённых действий
av_actions = self.get_available_actions()
allowed_types = av_actions[KompasCommand.STATS]["allowed_types"]
docs_collection = self.application.Documents
for i in range(docs_collection.Count):
try:
doc = docs_collection.Item(i)
if doc is None:
continue
doc_type = doc.DocumentType
if doc_type not in allowed_types:
continue
doc.Active = True
doc_name = "-".join(doc.Name.split(".")[:-1])
print(f"Обрабатываем документ: {doc_name}")
doc_3d = self.api7_module.IKompasDocument3D(doc)
top_part = doc_3d.TopPart
elements = []
bends = []
welding = []
def look_features(element):
feature = self.api7_module.IFeature7(element)
sub_features = feature.SubFeatures(1, True, False) or []
for item in sub_features:
if type(item) in (
self.api7_module.ISheetMetalBend,
self.api7_module.ISheetMetalLineBend,
self.api7_module.ISheetMetalBody,
):
sub_sheets = item.Owner.SubFeatures(1, True, False)
if sub_sheets:
for b in sub_sheets:
bend = self.api7_module.ISheetMetalBend(b)
bends.append(bend)
def look_drawing(part):
drawing_context = self.api7_module.IDrawingContainer(part)
macro = self.api7_module.IMacroObject3D(drawing_context)
sub_features = macro.Owner.SubFeatures(1, True, False) or []
for item in sub_features:
if isinstance(item, self.api7_module.IUserDesignationCompObj):
welding.append(item)
def find_el(part):
try:
drawing_context = self.api7_module.IDrawingContainer(part)
macro = self.api7_module.IMacroObject3D(drawing_context)
sub_features = macro.Owner.SubFeatures(1, True, False) or []
for item in sub_features:
if isinstance(item, self.api7_module.IUserDesignationCompObj):
welding.append(item)
except Exception as e:
print('Ошибка в DrawingContext:', e)
try:
doc_parts = self.api7_module.IParts7(part.Parts)
for j in range(doc_parts.Count):
element = doc_parts.Part(j)
if element.Parts.Count == 0:
elements.append(element)
look_features(element)
find_el(element)
except Exception as e:
print('Ошибка в Parts:', e)
if doc_type == self.constants.ksDocumentAssembly:
find_el(top_part)
else:
elements.append(top_part)
look_drawing(top_part)
look_features(top_part)
print(f"Найдено:\n Элементов {len(elements)}\n Гибов {len(bends)}\n")
sorted_stats = {
"Name": {},
"Material": {},
"Area": {},
}
for e in elements:
for key in sorted_stats.keys():
if key == 'Name':
value = f"{getattr(e, key)}, масса {round(getattr(e, 'Mass'), 3)}"
sorted_stats[key][value] = sorted_stats[key].get(value, 0) + 1
elif key == 'Area':
mass_inertial_params = self.api7_module.IMassInertiaParam7(e)
area = mass_inertial_params.Area * 0.0001 # м²
material = getattr(e, 'Material', 'Неизвестно')
key_area = f"Площадь {material}, м²:"
sorted_stats[key][key_area] = round(sorted_stats[key].get(key_area, 0) + area, 6)
else:
value = getattr(e, key)
sorted_stats[key][value] = sorted_stats[key].get(value, 0) + 1
sorted_stats['Area']['Total'] = sum(sorted_stats['Area'].values())
welding_key = "Welding"
for w in welding:
if welding_key not in sorted_stats:
sorted_stats[welding_key] = {}
w_name_split = w.Name.split('-')
w_len = w_name_split[-1].split('@')[0]
sorted_stats[welding_key][w.Name] = w_len
if welding_key in sorted_stats:
def float_f(n):
try:
return float(n)
except:
return 0
total_length = sum(float_f(v) for v in sorted_stats[welding_key].values())
sorted_stats[welding_key]["Total"] = total_length
for section in sorted_stats:
print(section)
for name, value in sorted_stats[section].items():
print(f"{name} -- {value}")
print('-----')
except Exception as e:
print(f"[ERROR] Ошибка при обработке документа #{i + 1}: {e}")
traceback.print_exc()
def export_to_raster(self):
"""Заглушка: Экспорт в растровый формат"""
pass
"""Экспорт открытых 2D-документов (чертежи, фрагменты, спецификации) в JPG и DXF. Создание многостраничного PDF."""
print("Начинаем экспорт документов в растровый формат...")
images = []
first_doc_name = None
# Получаем доступные типы для экспорта из разрешенных действий
av_actions = self.get_available_actions()
allowed_types = av_actions[KompasCommand.EXPORT_RASTER]["allowed_types"]
docs_collection = self.application.Documents
for i in range(docs_collection.Count):
try:
doc = docs_collection.Item(i)
if doc is None:
continue
doc_type = doc.DocumentType
if doc_type not in allowed_types:
continue
doc.Active = True
doc_path = doc.Path
doc_name = os.path.splitext(doc.Name)[0] # Имя без расширения
print(f"Обрабатываем документ: {doc_name}")
# Сохраняем имя первого документа
if first_doc_name is None:
doc7 = self.api7_module.IKompasDocument(doc)
first_doc_name = doc7.LayoutSheets.ItemByNumber(1).Stamp.Text(2).Str
# Получаем интерфейс 2D-документа
if doc_type == self.constants.ksDocumentSpecification:
doc_api5 = self.api5.SpcActiveDocument()
else:
doc_api5 = self.api5.ActiveDocument2D()
if not doc_api5:
raise RuntimeError("Не удалось получить активный 2D-документ")
# Параметры экспорта в JPG
raster_params = doc_api5.RasterFormatParam()
raster_params.Init()
raster_params.colorBPP = 8
raster_params.colorType = 3
raster_params.extResolution = 96
raster_params.format = 0 # JPEG format
# Сохранение в JPG и DXF
for ext in ["jpg", "dxf"]:
output_dir = os.path.join(doc_path, ext)
filename = f"{doc_name}.{ext}"
full_path = os.path.join(output_dir, filename)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Создана папка: {output_dir}")
if ext == "jpg":
doc_api5.SaveAsToRasterFormat(full_path, raster_params)
print(f"[OK] Сохранен JPG: {full_path}")
images.append(Image.open(full_path))
elif ext == "dxf":
doc_api5.ksSaveToDXF(full_path)
print(f"[OK] Сохранен DXF: {full_path}")
except Exception as e:
print(f"[ERROR] Ошибка при обработке документа #{i + 1}: {e}")
traceback.print_exc()
# Создание PDF
if images:
desktop_path = os.path.expanduser("~\\Desktop")
pdf_filename = f"{first_doc_name}_pages.pdf"
pdf_output_path = os.path.join(desktop_path, pdf_filename)
# Создаем титульную страницу с названием и количеством страниц
try:
font = ImageFont.truetype("arial.ttf", size=48)
except IOError:
print("Шрифт Arial не найден. Используется стандартный шрифт.")
font = ImageFont.load_default()
title_image = Image.new("RGB", (images[0].width, 200), color="white")
draw = ImageDraw.Draw(title_image)
title_text = f"{first_doc_name}\nКоличество страниц: {len(images)}"
draw.text((10, 50), title_text, fill="black", font=font, spacing=10)
images.insert(0, title_image)
# Сохраняем как PDF
try:
images[0].save(
pdf_output_path,
save_all=True,
append_images=images[1:],
format="PDF",
resolution=96.0,
)
print(f"[OK] PDF успешно сохранен: {pdf_output_path}")
except Exception as e:
print(f"[ERROR] Не удалось создать PDF: {e}")
def get_available_actions(self):
"""
Возвращает список доступных действий и допустимые типы документов
Формат: { action_key: { 'label': str, 'allowed_types': list } }
Формат: {
action_key: {
'label': str,
'allowed_types': list,
'method': str,
'command': str
}
}
"""
# Допустимые типы документов
ALLOWED_TYPES_3D = [
@ -115,20 +531,28 @@ class KompasDocumentParser:
ALLOWED_TYPES_SPEC = [self.constants.ksDocumentSpecification]
ALLOWED_TYPES_ALL = ALLOWED_TYPES_3D + ALLOWED_TYPES_2D + ALLOWED_TYPES_SPEC
return {
"iges": {
KompasCommand.IGES: {
"label": "Сохранить как IGES",
"allowed_types": ALLOWED_TYPES_3D,
"method": "save_to_iges",
"command": KompasCommand.IGES,
},
"stats": {
KompasCommand.STATS: {
"label": "Собрать статистику по элементам",
"allowed_types": ALLOWED_TYPES_3D,
"method": "collect_statistics",
"command": KompasCommand.STATS,
},
"export_pdf": {
KompasCommand.EXPORT_RASTER: {
"label": "Экспортировать в PDF",
"allowed_types": ALLOWED_TYPES_2D + ALLOWED_TYPES_SPEC,
"method": "export_to_raster",
"command": KompasCommand.EXPORT_RASTER,
},
"project_support": {
KompasCommand.PROJECT_SUPPORT: {
"label": "Создать чертежи деталей",
"allowed_types": ALLOWED_TYPES_3D,
"method": "create_drawing_for_parts",
"command": KompasCommand.PROJECT_SUPPORT,
},
}