weld test

This commit is contained in:
ksenia_mikhailova 2025-06-27 17:02:17 +03:00
parent f36b06875c
commit 9b880eb91f
2 changed files with 42571 additions and 102 deletions

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,9 @@ import re
from collections import defaultdict from collections import defaultdict
from win32com.client import Dispatch, gencache from win32com.client import Dispatch, gencache
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
import xmltodict
import pythoncom
from win32com.client import Dispatch, VARIANT
from enums import KompasCommand from enums import KompasCommand
from logger import logger from logger import logger
@ -389,7 +392,7 @@ class KompasDocumentParser:
for j in range(doc_parts.Count): for j in range(doc_parts.Count):
element = doc_parts.Part(j) element = doc_parts.Part(j)
# if element.Parts.Count == 0: # if element.Parts.Count == 0:
# elements.append(element) # elements.append(element)
elements.append(element) elements.append(element)
bends += self._collect_bends_from_element(element) bends += self._collect_bends_from_element(element)
result = self._traverse_parts_recursive(element) result = self._traverse_parts_recursive(element)
@ -404,7 +407,7 @@ class KompasDocumentParser:
def _build_statistics_data(self, elements, welding): def _build_statistics_data(self, elements, welding):
stats = {"Name": {}, "Material": {}, "Area": {}} stats = {"Name": {}, "Material": {}, "Area": {}}
item_template = lambda: {"quantity": 0, "area": 0, "mass":0, "material": ""} item_template = lambda: {"quantity": 0, "area": 0, "mass": 0, "material": ""}
detail_stats = { detail_stats = {
"standard": defaultdict(item_template), "standard": defaultdict(item_template),
"custom": defaultdict(item_template), "custom": defaultdict(item_template),
@ -420,7 +423,7 @@ class KompasDocumentParser:
mass_inertial_params = self.api7_module.IMassInertiaParam7(e) mass_inertial_params = self.api7_module.IMassInertiaParam7(e)
area = mass_inertial_params.Area * 0.0001 area = mass_inertial_params.Area * 0.0001
mass = round(getattr(e, 'Mass'), 3) mass = round(getattr(e, "Mass"), 3)
quantity = 1 quantity = 1
detail_stats[type_key][element_key]["material"] = material detail_stats[type_key][element_key]["material"] = material
@ -466,10 +469,9 @@ class KompasDocumentParser:
return stats return stats
def extract_section(name): def extract_section(name):
"""Извлечение сечения из имени профиля""" """Извлечение сечения из имени профиля"""
match = re.search(r'(\d+)х(\d+)(?:х(\d+))?', name) match = re.search(r"(\d+)х(\d+)(?:х(\d+))?", name)
if match: if match:
w, h, t = match.groups() w, h, t = match.groups()
return f"{w}x{h}" + (f", толщ. {t}" if t else "") return f"{w}x{h}" + (f", толщ. {t}" if t else "")
@ -481,19 +483,28 @@ class KompasDocumentParser:
cls_name = str(type(obj)) cls_name = str(type(obj))
# Гиб листовой детали # Гиб листовой детали
if isinstance(obj, (self.api7_module.ISheetMetalBend, self.api7_module.ISheetMetalLineBend)): if isinstance(
obj,
(self.api7_module.ISheetMetalBend, self.api7_module.ISheetMetalLineBend),
):
return "Гиб" return "Гиб"
# Сварной шов # Сварной шов
elif "IUserDesignationCompObj" in cls_name or ("IUserObject3D" in cls_name and "свар" in name_lower): elif "IUserDesignationCompObj" in cls_name or (
"IUserObject3D" in cls_name and "свар" in name_lower
):
return "Сварной шов" return "Сварной шов"
# Стандартное изделие # Стандартное изделие
elif "IMacroObject3D" in cls_name or any(kw in name_lower for kw in ["болт", "гайка", "шайба"]): elif "IMacroObject3D" in cls_name or any(
kw in name_lower for kw in ["болт", "гайка", "шайба"]
):
return "Стандартное изделие" return "Стандартное изделие"
# Профильная труба # Профильная труба
elif "IUserObject3D" in cls_name and any(kw in name_lower for kw in ["труба", "профиль"]): elif "IUserObject3D" in cls_name and any(
kw in name_lower for kw in ["труба", "профиль"]
):
return "Профильная труба" return "Профильная труба"
# Листовая оболочка # Листовая оболочка
@ -505,102 +516,148 @@ class KompasDocumentParser:
return "Кастомная деталь" return "Кастомная деталь"
# Вспомогательные объекты # Вспомогательные объекты
elif any(kw in cls_name for kw in ["IPlane3D", "IAxis3D", "IModelObject", "IMateConstraint3D", "ISketch"]): elif any(
kw in cls_name
for kw in [
"IPlane3D",
"IAxis3D",
"IModelObject",
"IMateConstraint3D",
"ISketch",
]
):
return "Вспомогательный объект" return "Вспомогательный объект"
else: else:
return "Неизвестный тип" return "Неизвестный тип"
def traverse_features(self, feature, level=0): def merge_results(self, target, source):
""" for category in ["Standard", "Sheet", "Pipe"]:
Рекурсивный обход дерева построения модели. for key, items in source.get(category, {}).items():
Возвращает: target[category].setdefault(key, []).extend(items)
result_all: список всех элементов return target
classified_data: словарь с категориями
""" def keeper(self, obj):
property_keeper = self.api7_module.IPropertyKeeper(obj)
try: try:
sub_features = self.api7_module.IFeature7(feature).SubFeatures(1, True, False) data = xmltodict.parse(property_keeper.Properties)
if not sub_features: properties_list = data.get("infObject", {}).get("property", [])
return [], { if not isinstance(properties_list, list):
"bends": [], properties_list = [properties_list]
"welding": [],
"standard_items": [],
"profile_tubes": [],
"sheet_metal_parts": [],
"custom_parts": [],
"support_objects": []
}
result_all = [] # Создаём словарь по @id
bends = [] props = {prop["@id"]: prop for prop in properties_list if "@id" in prop}
welding = [] if props.get("276039607982", None):
standard_items = [] section_prop = props.get("276039607982") # Сечение (тип профиля)
profile_tubes = [] sketch_prop = props.get("316618764777") # Эскиз сечения
sheet_metal_parts = [] profile_length_prop = props.get("235833998283") # Длина профиля
custom_parts = [] key = sketch_prop["@value"]
support_objects = [] return (key, profile_length_prop)
except Exception as e:
logger.error(e)
return None
for item in sub_features: return None
name = getattr(item, "Name", "---")
ftype = str(type(item))
indent = " " * level
classification = self.classify_item(name, item) def traverse_ipart(self, element, depth=0, viewed=None, result=None):
if viewed is None:
viewed = set()
# print(f"{indent}- {name} | {ftype} → [{classification}]") obj_id = id(element)
if obj_id in viewed:
return
viewed.add(obj_id)
# Добавляем в общий список if result is None:
result_all.append((name, ftype)) result = {"Standard": {}, "Sheet": {}, "Pipe": {}, "Weld": {}}
# Классифицируем элемент property_manager = self.api7_module.IPropertyMng(self.application)
if classification == "Гиб":
bends.append({"name": name, "type": ftype})
elif classification == "Сварной шов":
welding.append({"name": name, "type": ftype})
elif classification == "Стандартное изделие":
standard_items.append({"name": name, "type": ftype})
elif classification == "Профильная труба":
profile_tubes.append({"name": name, "type": ftype, "section": extract_section(name)})
elif classification == "Листовая деталь":
sheet_metal_parts.append({"name": name, "type": ftype})
elif classification == "Кастомная деталь":
custom_parts.append({"name": name, "type": ftype})
elif classification == "Вспомогательный объект":
support_objects.append({"name": name, "type": ftype})
# Рекурсивно обходим дочерние элементы parts_collection = self.api7_module.IPart7(element).Parts
child_all, child_data = self.traverse_features(item, level + 1) if not isinstance(parts_collection, tuple):
parts_collection = (parts_collection,)
result_all.extend(child_all) sub_features = self.api7_module.IFeature7(element).SubFeatures(1, True, True)
bends.extend(child_data.get("bends", [])) if not isinstance(sub_features, tuple):
welding.extend(child_data.get("welding", [])) sub_features = (sub_features,)
standard_items.extend(child_data.get("standard_items", []))
profile_tubes.extend(child_data.get("profile_tubes", []))
sheet_metal_parts.extend(child_data.get("sheet_metal_parts", []))
custom_parts.extend(child_data.get("custom_parts", []))
support_objects.extend(child_data.get("support_objects", []))
return result_all, { bodies = self.api7_module.IFeature7(element).ResultBodies
"bends": bends, if not isinstance(bodies, tuple):
"welding": welding, bodies = (bodies,)
"standard_items": standard_items,
"profile_tubes": profile_tubes,
"sheet_metal_parts": sheet_metal_parts,
"custom_parts": custom_parts,
"support_objects": support_objects
}
except Exception as ex: for f in parts_collection + sub_features + bodies:
logger.error(f"Ошибка при обходе SubFeatures: {ex}", exc_info=True) print(f"Обрабатываем: {type(f)} - {getattr(f, 'Name', 'Без имени')}")
return [], { if getattr(f, "Standard", False):
"bends": [], key = (f.Name, getattr(f, "Material", "Без материала"))
"welding": [], result["Standard"].setdefault(key, []).append(f.Name)
"standard_items": [],
"profile_tubes": [], elif getattr(f, "FileName", None):
"sheet_metal_parts": [], param = f.GetOpenDocumentParam()
"custom_parts": [], param.Visible = True
"support_objects": [] param.ReadOnly = True
} new_doc3d = f.OpenSourceDocument(param)
new_doc = self.api7_module.IKompasDocument(new_doc3d)
new_doc.Active = True
new_doc3d = self.api7_module.IKompasDocument3D(new_doc)
new_result = self.traverse_ipart(new_doc3d.TopPart)
self.merge_results(result, new_result)
new_doc.Close(self.constants.kdDoNotSaveChanges)
else:
if isinstance(f, self.api7_module.IBody7):
res = self.keeper(f)
if res:
key, value = res
result["Pipe"].setdefault(key, []).append(value)
if isinstance(f, self.api7_module.IUserDesignationCompObj):
weldes = self.api7_module.IFeature7(f).SubFeatures(1, True, True)
print(f.Name)
for w in weldes:
# Получаем IUserParameters
user_params = self.api7_module.IUserParameters(w)
# Получаем имя файла библиотеки
lib_filename = user_params.LibraryFileName # Например: Welding3D.rtw
print("Библиотека:", lib_filename)
# Создаем VARIANT с путём к библиотеке (VT_BSTR)
var_libname = VARIANT(pythoncom.VT_BSTR, lib_filename)
property_manager = self.api7_module.IPropertyMng(w.Application)
properties_variant = property_manager.GetProperties(var_libname)
print(properties_variant)
raw_data = bytes(self.api7_module.IUserParameters(w).UserParams)
decoded = raw_data.strip(b'\x00').decode('utf-16le', errors='ignore')
# Разделяем на строки (если есть разделители)
parts = decoded.split('\x00') # Разделение по нулевым символам
print(decoded)
print(raw_data)
for ww in range(w.AssociationObjectCount):
_ww = w.AssociationObject(ww)
if _ww:
print(_ww.Name)
# if _ww:
# if _ww.ModelObjectType == 7:
# print(property_manager.GetReport(_ww.Application.ActiveDocument))
if isinstance(f, self.api7_module.ISheetMetalRuledShell):
key = getattr(f, "Name", "----")
value = getattr(f, "Name", "----")
result["Sheet"].setdefault(key, []).append(value)
if isinstance(
f,
(
self.api7_module.IPart7,
self.api7_module.IBody7,
self.api7_module.IFeature7,
),
):
self.traverse_ipart(f, depth + 1, viewed, result)
return result
def collect_statistics(self): def collect_statistics(self):
"""Сбор статистики по элементам, гибам и сваркам в активном документе""" """Сбор статистики по элементам, гибам и сваркам в активном документе"""
@ -646,15 +703,9 @@ class KompasDocumentParser:
bends += self._collect_bends_from_element(top_part) bends += self._collect_bends_from_element(top_part)
welding += self._collect_welds_from_drawing(top_part) welding += self._collect_welds_from_drawing(top_part)
result_all, categorized = self.traverse_features(top_part) res = self.traverse_ipart(top_part)
# Пример вывода print("@@@")
print(f"Гибы: {len(categorized['bends'])}") print(res)
print(f"Сварные швы: {len(categorized['welding'])}")
print(f"Стандартные изделия: {len(categorized['standard_items'])}")
print(f"Профильные трубы: {len(categorized['profile_tubes'])}")
print(f"Листовые детали: {len(categorized['sheet_metal_parts'])}")
print(f"Кастомные детали: {len(categorized['custom_parts'])}")
logger.info( logger.info(
f"Найдено:\n Элементов {len(elements)}\n Гибов {len(bends)}\n" f"Найдено:\n Элементов {len(elements)}\n Гибов {len(bends)}\n"
) )