184 lines
7.1 KiB
Python
184 lines
7.1 KiB
Python
import FreeCAD as App
|
||
import unicodedata
|
||
import numpy as np
|
||
from .helper.is_solid import is_object_solid
|
||
|
||
## Программа, содержащая все проверки активного проекта FreeCAD в соответствии с issue#149
|
||
|
||
doc = App.ActiveDocument
|
||
Console = App.Console
|
||
|
||
|
||
#========== Проверка имен ===============
|
||
class FormalValidator:
|
||
def __init__(self, document):
|
||
self.document = document
|
||
|
||
def is_unicode_safe(self, name):
|
||
normalized_name = unicodedata.normalize('NFKD', name).encode('ASCII', 'ignore').decode()
|
||
return name == normalized_name
|
||
|
||
def fix_invalid_names(self):
|
||
for obj in self.document.Objects:
|
||
if not self.is_unicode_safe(obj.Label):
|
||
safe_name = unicodedata.normalize('NFKD', obj.Label).encode('ASCII', 'ignore').decode()
|
||
obj.Label = safe_name
|
||
self.document.recompute()
|
||
|
||
#запуск проверки и исправления имен файлов
|
||
def validate(self):
|
||
invalid_names = [obj.Label for obj in self.document.Objects if not self.is_unicode_safe(obj.Label)]
|
||
if invalid_names:
|
||
print("Некорректные имена:")
|
||
for name in invalid_names:
|
||
print(name)
|
||
self.fix_invalid_names()
|
||
else:
|
||
print("Все имена корректны.")
|
||
|
||
|
||
class ModelValidator:
|
||
def __init__(self, document):
|
||
self.document = document
|
||
self.partlist = [obj for obj in self.document.Objects if (is_object_solid(obj) and not obj.TypeId == 'App::Part') ]
|
||
self.material_objects = [obj for obj in document.Objects if obj.TypeId == "App::MaterialObjectPython"]
|
||
|
||
def get_parts(self):
|
||
pass
|
||
|
||
|
||
|
||
def validate_geometry(self):
|
||
for obj in self.document.Objects:
|
||
if hasattr(obj, "Shape") and not is_object_solid(obj):
|
||
Console.PrintError(f"Объект '{obj.Name}' не является твердым телом.\n")
|
||
|
||
def is_intersecting(self, obj1, obj2):
|
||
if obj1.Shape.common(obj2.Shape).Volume > 0.0:
|
||
return True
|
||
|
||
def has_allow_intersections(self, obj):
|
||
if hasattr(obj, 'Base_Allowed_Intersection') and getattr(obj, 'Base_Allowed_Intersection', True):
|
||
return True
|
||
|
||
def check_bodies_for_intersections(self):
|
||
bodies = self.partlist
|
||
num_bodies = len(bodies)
|
||
|
||
for i in range(num_bodies):
|
||
for j in range(i + 1, num_bodies):
|
||
body1 = bodies[i]
|
||
body2 = bodies[j]
|
||
if self.is_intersecting(body1, body2):
|
||
if self.has_allow_intersections(body1) or self.has_allow_intersections(body2):
|
||
Console.PrintWarning(
|
||
f"Тела '{body1.Label}' и '{body2.Label}' ""предусмотренно пересекаются.\n")
|
||
else:
|
||
Console.PrintError(
|
||
f"Тела '{body1.Label}' и '{body2.Label}' ""непредусмотренно пересекаются.\n")
|
||
print('V = ' + str(body1.Shape.common(body2.Shape).Volume))
|
||
|
||
|
||
def get_adjacency_matrix(self, padding = 1):
|
||
# print(int(padding))
|
||
bodies = self.partlist
|
||
num_bodies = len(bodies)
|
||
adjacency_matrix = np.zeros((num_bodies, num_bodies), dtype=bool)
|
||
|
||
for i in range(num_bodies):
|
||
shape1 = bodies[i].Shape
|
||
for j in range(i + 1, num_bodies):
|
||
shape2 = bodies[j].Shape
|
||
|
||
if shape1.common(shape2).Volume > 0:
|
||
continue
|
||
|
||
distance = shape1.distToShape(shape2)
|
||
if distance[0] < padding:
|
||
adjacency_matrix[i][j] = 1
|
||
adjacency_matrix[j][i] = 1
|
||
|
||
return adjacency_matrix
|
||
|
||
def check_bodies_without_contacts(self):
|
||
adjacency_matrix = self.get_adjacency_matrix()
|
||
bodies = self.partlist
|
||
|
||
isolated_bodies = []
|
||
num_bodies = len(bodies)
|
||
|
||
for i in range(num_bodies):
|
||
# Проверяем, есть ли у тела касания с другими телами
|
||
if not any(adjacency_matrix[i]):
|
||
isolated_bodies.append(bodies[i].Label)
|
||
|
||
if isolated_bodies:
|
||
App.Console.PrintWarning("Следующие тела не касаются других:\n")
|
||
for label in isolated_bodies:
|
||
App.Console.PrintWarning(f"- {label}\n")
|
||
else:
|
||
App.Console.PrintMessage("Все тела имеют контакты.\n")
|
||
|
||
|
||
def find_material_objects(document):
|
||
pass
|
||
|
||
|
||
|
||
def check_bodies_with_multiple_materials(self):
|
||
material_objects = self.material_objects
|
||
material_references = {}
|
||
|
||
for material in material_objects:
|
||
if hasattr(material, "References"):
|
||
for reference in material.References:
|
||
if reference in material_references:
|
||
material_references[reference].append(material.Label)
|
||
else:
|
||
material_references[reference] = [material.Label]
|
||
|
||
conflicts = {k: v for k, v in material_references.items() if len(v) > 1}
|
||
|
||
if conflicts:
|
||
App.Console.PrintWarning("Обнаружены конфликты между объектами материалов:\n")
|
||
for ref, materials in conflicts.items():
|
||
App.Console.PrintWarning(f"Деталь '{ref[0].Label}' используется в материалах: {', '.join(materials)}\n")
|
||
else:
|
||
App.Console.PrintMessage("Конфликтов в ссылках материалов не обнаружено.\n")
|
||
|
||
def check_bodies_without_material(self):
|
||
material_objects = self.material_objects
|
||
partlist = self.partlist
|
||
referenced_bodies = []
|
||
for material in material_objects:
|
||
if hasattr(material, "References"):
|
||
for reference in material.References:
|
||
referenced_bodies.append(reference[0].Label)
|
||
|
||
bodies_without_material = []
|
||
for part in partlist:
|
||
if part.Label not in referenced_bodies:
|
||
bodies_without_material.append(part.Label)
|
||
|
||
if bodies_without_material:
|
||
App.Console.PrintWarning("Следующие тела не имеют назначенного материала:\n")
|
||
for name in bodies_without_material:
|
||
App.Console.PrintWarning(f"- {name}\n")
|
||
else:
|
||
App.Console.PrintMessage("Все тела имеют назначенные материалы.\n")
|
||
|
||
|
||
|
||
def validate(self):
|
||
self.validate_geometry()
|
||
self.check_bodies_for_intersections()
|
||
self.check_bodies_without_contacts()
|
||
self.check_bodies_without_material()
|
||
self.check_bodies_with_multiple_materials()
|
||
|
||
def validate_project():
|
||
doc = App.ActiveDocument
|
||
FormalValidator(doc).validate()
|
||
ModelValidator(doc).validate()
|
||
|
||
|