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 win32com.client import Dispatch, gencache
from PIL import Image, ImageDraw, ImageFont
import xmltodict
import pythoncom
from win32com.client import Dispatch, VARIANT
from enums import KompasCommand
from logger import logger
@ -389,8 +392,8 @@ class KompasDocumentParser:
for j in range(doc_parts.Count):
element = doc_parts.Part(j)
# if element.Parts.Count == 0:
# elements.append(element)
elements.append(element)
# elements.append(element)
elements.append(element)
bends += self._collect_bends_from_element(element)
result = self._traverse_parts_recursive(element)
elements += result["elements"]
@ -404,7 +407,7 @@ class KompasDocumentParser:
def _build_statistics_data(self, elements, welding):
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 = {
"standard": defaultdict(item_template),
"custom": defaultdict(item_template),
@ -420,7 +423,7 @@ class KompasDocumentParser:
mass_inertial_params = self.api7_module.IMassInertiaParam7(e)
area = mass_inertial_params.Area * 0.0001
mass = round(getattr(e, 'Mass'), 3)
mass = round(getattr(e, "Mass"), 3)
quantity = 1
detail_stats[type_key][element_key]["material"] = material
@ -465,11 +468,10 @@ class KompasDocumentParser:
stats["Welding"]["Total"] = round(total_length, 2)
return stats
def extract_section(name):
"""Извлечение сечения из имени профиля"""
match = re.search(r'(\d+)х(\d+)(?:х(\d+))?', name)
match = re.search(r"(\d+)х(\d+)(?:х(\d+))?", name)
if match:
w, h, t = match.groups()
return f"{w}x{h}" + (f", толщ. {t}" if t else "")
@ -481,19 +483,28 @@ class KompasDocumentParser:
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 "Гиб"
# Сварной шов
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 "Сварной шов"
# Стандартное изделие
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 "Стандартное изделие"
# Профильная труба
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 "Профильная труба"
# Листовая оболочка
@ -505,103 +516,149 @@ class KompasDocumentParser:
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 "Вспомогательный объект"
else:
return "Неизвестный тип"
def traverse_features(self, feature, level=0):
"""
Рекурсивный обход дерева построения модели.
Возвращает:
result_all: список всех элементов
classified_data: словарь с категориями
"""
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)
return target
def keeper(self, obj):
property_keeper = self.api7_module.IPropertyKeeper(obj)
try:
sub_features = self.api7_module.IFeature7(feature).SubFeatures(1, True, False)
if not sub_features:
return [], {
"bends": [],
"welding": [],
"standard_items": [],
"profile_tubes": [],
"sheet_metal_parts": [],
"custom_parts": [],
"support_objects": []
}
data = xmltodict.parse(property_keeper.Properties)
properties_list = data.get("infObject", {}).get("property", [])
if not isinstance(properties_list, list):
properties_list = [properties_list]
result_all = []
bends = []
welding = []
standard_items = []
profile_tubes = []
sheet_metal_parts = []
custom_parts = []
support_objects = []
# Создаём словарь по @id
props = {prop["@id"]: prop for prop in properties_list if "@id" in prop}
if props.get("276039607982", None):
section_prop = props.get("276039607982") # Сечение (тип профиля)
sketch_prop = props.get("316618764777") # Эскиз сечения
profile_length_prop = props.get("235833998283") # Длина профиля
key = sketch_prop["@value"]
return (key, profile_length_prop)
except Exception as e:
logger.error(e)
return None
for item in sub_features:
name = getattr(item, "Name", "---")
ftype = str(type(item))
indent = " " * level
return None
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)
# Добавляем в общий список
result_all.append((name, ftype))
if result is None:
result = {"Standard": {}, "Sheet": {}, "Pipe": {}, "Weld": {}}
# Классифицируем элемент
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})
property_manager = self.api7_module.IPropertyMng(self.application)
# Рекурсивно обходим дочерние элементы
child_all, child_data = self.traverse_features(item, level + 1)
parts_collection = self.api7_module.IPart7(element).Parts
if not isinstance(parts_collection, tuple):
parts_collection = (parts_collection,)
result_all.extend(child_all)
bends.extend(child_data.get("bends", []))
welding.extend(child_data.get("welding", []))
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", []))
sub_features = self.api7_module.IFeature7(element).SubFeatures(1, True, True)
if not isinstance(sub_features, tuple):
sub_features = (sub_features,)
return result_all, {
"bends": bends,
"welding": welding,
"standard_items": standard_items,
"profile_tubes": profile_tubes,
"sheet_metal_parts": sheet_metal_parts,
"custom_parts": custom_parts,
"support_objects": support_objects
}
bodies = self.api7_module.IFeature7(element).ResultBodies
if not isinstance(bodies, tuple):
bodies = (bodies,)
for f in parts_collection + sub_features + bodies:
print(f"Обрабатываем: {type(f)} - {getattr(f, 'Name', 'Без имени')}")
if getattr(f, "Standard", False):
key = (f.Name, getattr(f, "Material", "Без материала"))
result["Standard"].setdefault(key, []).append(f.Name)
elif getattr(f, "FileName", None):
param = f.GetOpenDocumentParam()
param.Visible = True
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
except Exception as ex:
logger.error(f"Ошибка при обходе SubFeatures: {ex}", exc_info=True)
return [], {
"bends": [],
"welding": [],
"standard_items": [],
"profile_tubes": [],
"sheet_metal_parts": [],
"custom_parts": [],
"support_objects": []
}
def collect_statistics(self):
"""Сбор статистики по элементам, гибам и сваркам в активном документе"""
logger.info("Начинаем сбор статистики по элементам...")
@ -645,16 +702,10 @@ class KompasDocumentParser:
elements += [top_part]
bends += self._collect_bends_from_element(top_part)
welding += self._collect_welds_from_drawing(top_part)
result_all, categorized = self.traverse_features(top_part)
# Пример вывода
print(f"Гибы: {len(categorized['bends'])}")
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'])}")
res = self.traverse_ipart(top_part)
print("@@@")
print(res)
logger.info(
f"Найдено:\n Элементов {len(elements)}\n Гибов {len(bends)}\n"
)