Добавлен функционал проверки документа
This commit is contained in:
parent
3e7bfba178
commit
b766e36c31
7 changed files with 1432 additions and 59 deletions
|
@ -6,6 +6,7 @@ from .pddl import freecad2pddl
|
|||
from .BoMList import run_BoM_list
|
||||
from .export_entities import export_coordinate_systems
|
||||
from .utils.freecad_processor import process_file
|
||||
from .project_validator import validate_project
|
||||
from .usecases.asm4parser_usecase import Asm4StructureParseUseCase
|
||||
|
||||
|
||||
|
@ -320,6 +321,11 @@ spawnClassCommand("Export_Entities",
|
|||
"MenuText": "ExportLCS",
|
||||
"ToolTip": "Export all the markups"})
|
||||
|
||||
spawnClassCommand("Validate_Project",
|
||||
validate_project,
|
||||
{"Pixmap": str(os.path.join(ICONPATH, "")),
|
||||
"MenuText": "Validate Project",
|
||||
"ToolTip": "Check errors in project file"})
|
||||
spawnClassCommand("Publish_Project",
|
||||
process_file,
|
||||
{"Pixmap": str(os.path.join(ICONPATH, "publish.svg")),
|
||||
|
|
|
@ -31,6 +31,7 @@ from usecases.open_freecad_document_use_case import (
|
|||
from mocks.mock_structure import bottle_jack_mock_structure, simple_cube_mock_structure
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
EnvReaderUseCase.call().either(
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -49,7 +49,7 @@ class Robossembler(Gui.Workbench):
|
|||
"Export_Entities",
|
||||
"ExportGazeboModels",
|
||||
"InsertGraspPose",
|
||||
# "ASM4StructureParsing",
|
||||
"Validate_Project",
|
||||
"Publish_Project"
|
||||
]
|
||||
self.appendToolbar(f"{__class__.__name__} Frames", self.framecommands)
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import FreeCAD as App
|
||||
import FreeCAD.Console as Console
|
||||
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:
|
||||
|
@ -38,20 +40,29 @@ class FormalValidator:
|
|||
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 self.is_object_solid(obj):
|
||||
if hasattr(obj, "Shape") and not is_object_solid(obj):
|
||||
Console.PrintError(f"Объект '{obj.Name}' не является твердым телом.\n")
|
||||
|
||||
def is_intersecting(self, obj1, obj2):
|
||||
return obj1.Shape.common(obj2.Shape).Volume > 0
|
||||
if obj1.Shape.common(obj2.Shape).Volume > 0.0:
|
||||
return True
|
||||
|
||||
def has_allow_intersections(self, obj):
|
||||
return hasattr(obj, self.ALLOWED_INTERSECTION_ATTRIBUTE) and getattr(obj, self.ALLOWED_INTERSECTION_ATTRIBUTE, False)
|
||||
if hasattr(obj, 'Base_Allowed_Intersection') and getattr(obj, 'Base_Allowed_Intersection', True):
|
||||
return True
|
||||
|
||||
def check_bodies_for_intersections(self):
|
||||
bodies = [obj for obj in self.document.Objects if hasattr(obj, "Shape")]
|
||||
bodies = self.partlist
|
||||
num_bodies = len(bodies)
|
||||
|
||||
for i in range(num_bodies):
|
||||
|
@ -59,73 +70,115 @@ class ModelValidator:
|
|||
body1 = bodies[i]
|
||||
body2 = bodies[j]
|
||||
if self.is_intersecting(body1, body2):
|
||||
if not self.has_allow_intersections(body1) or not self.has_allow_intersections(body2):
|
||||
if self.has_allow_intersections(body1) or self.has_allow_intersections(body2):
|
||||
Console.PrintWarning(
|
||||
f"Пересечение обнаружено между '{body1.Name}' и '{body2.Name}', "
|
||||
f"но у них нет разрешения на пересечение.\n"
|
||||
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 check_bodies_for_intersections(self):
|
||||
pass
|
||||
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):
|
||||
pass
|
||||
adjacency_matrix = self.get_adjacency_matrix()
|
||||
bodies = self.partlist
|
||||
|
||||
def check_bodies_without_material(self):
|
||||
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):
|
||||
pass
|
||||
material_objects = self.material_objects
|
||||
material_references = {}
|
||||
|
||||
def run_checks(self):
|
||||
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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ProjectValidateUseCase:
|
||||
def __init__(self):
|
||||
self.doc = None
|
||||
|
||||
def getBodies(doc):
|
||||
bodies = []
|
||||
for obj in doc.Objects:
|
||||
if hasattr(obj, 'TypeId') and obj.TypeId == "Part::Feature":
|
||||
bodies.append(obj)
|
||||
return bodies
|
||||
|
||||
|
||||
|
||||
def check_intersections(self, bodies):
|
||||
intersections = []
|
||||
for i in range(len(bodies)):
|
||||
for j in range(i + 1, len(bodies)):
|
||||
if bodies[i].intersects(bodies[j]):
|
||||
intersections.append((i + 1, j + 1))
|
||||
return intersections
|
||||
|
||||
def check_zero_volume(self, bodies):
|
||||
zero_volume_bodies = [i + 1 for i, body in enumerate(bodies) if body.Volume == 0]
|
||||
return zero_volume_bodies
|
||||
|
||||
def print_intersections(self, intersections):
|
||||
for i, j in intersections:
|
||||
print("Тела пересекаются: Body {} и Body {}".format(i, j))
|
||||
|
||||
def print_zero_volume(self, zero_volume_bodies):
|
||||
for i in zero_volume_bodies:
|
||||
print("Тело {} имеет нулевой объем".format(i))
|
||||
|
||||
def save_checked_document(self, original_file_path):
|
||||
checked_file_path = original_file_path.replace(".step", "_checked.FCStd")
|
||||
FreeCAD.saveDocument(self.doc, checked_file_path)
|
||||
print("Проверенная сборка сохранена в файл:", checked_file_path)
|
||||
FreeCAD.closeDocument("Unnamed")
|
||||
|
||||
|
||||
def validate_project():
|
||||
doc = App.ActiveDocument
|
||||
FormalValidator(doc).validate()
|
||||
ModelValidator(doc).validate()
|
||||
|
||||
|
||||
|
|
BIN
test_models/test_reductor.20240510-053606.FCBak
Normal file
BIN
test_models/test_reductor.20240510-053606.FCBak
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue