weld test
This commit is contained in:
parent
f36b06875c
commit
9b880eb91f
42418
logs/parser.log
42418
logs/parser.log
File diff suppressed because it is too large
Load Diff
255
parser/main.py
255
parser/main.py
|
@ -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"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue